I am thinking about poker hand (5 cards) evaluation in Java. Now I am looking for simplicity and clarity rather than performance and efficiency. I probably can write a "naive" algorithm but it requires a lot of code.
I saw also a few poker evaluation libraries, which use hashing and bitwise operations, but they look rather complex.
What is the "cleanest and simplest" algorithm for poker hand evaluation ?
Here is a very short but complete histogram based 5 card poker scoring function in Python (2.x). It will get considerably longer if converted to Java.
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
Lookup tables are the most straightforward and simplest solution to the problem, and also the fastest. The trick is managing the size of the table and keeping the mode of use simple enough to process very quickly (space–time tradeoff). Obviously, in theory you could just encode each hand that could be held and have an array of evaluations, then --poof-- one table lookup and you are done. Unfortunately, such a table would be huge and unmanageable for most machines, and would invariably have you thrashing disks anyway as memory gets swapped out lots.
The so-called two-plus-two solution sports a big 10M table, but literally involves one table lookup for each card in the hand. You are not likely to find a faster and simpler to understand algorithm.
Other solutions involve more compressed tables with more complex indexing, but they are readily comprehensible and pretty fast (although much slower than 2+2). This is where you see language concerning hashing and so forth -- tricks to reduce a table size to more manageable sizes.
In any case, lookup solutions are orders of magnitude faster than the histogram-sort-dance-on-your-head-compare-special-case-and-by-the-way-was-it-a-flush solutions, almost none of which are worthy of a second glance.
You actually don't need any advanced functions, it can be all done bitwise: (source: http://www.codeproject.com/Articles/569271/A-Poker-hand-analyzer-in-JavaScript-using-bit-math)
(This one is actually written in JavaScript, but you can evaluate JavaScript from Java if needed, so it shouldn't be a problem. Also, this is as short as it gets, so if even for illustration of the approach...):
First you split your cards into two arrays: ranks (cs) and suits (ss) and to represent suits, you will use either 1,2,4 or 8 (that is 0b0001, 0b0010,...):
var J=11, Q=12, K=13, A=14, C=1, D=2, H=4, S=8;
Now here's the magic:
function evaluateHand(cs, ss) {
var pokerHands = ["4 of a Kind", "Straight Flush","Straight","Flush","High Card","1 Pair","2 Pair","Royal Flush", "3 of a Kind","Full House"];
var v,i,o,s = 1 << cs[0] | 1 << cs[1] | 1 << cs[2] | 1 << cs[3] | 1 << cs[4];
for (i = -1, v = o = 0; i < 5; i++, o = Math.pow(2, cs[i] * 4)) {v += o * ((v / o & 15) + 1);}
v = v % 15 - ((s / (s & -s) == 31) || (s == 0x403c) ? 3 : 1);
v -= (ss[0] == (ss[1] | ss[2] | ss[3] | ss[4])) * ((s == 0x7c00) ? -5 : 1);
return pokerHands[v];
}
Usage:
evaluateHand([A,10,J,K,Q],[C,C,C,C,C]); // Royal Flush
Now what it does (very briefly) is that it puts 1 into 3rd bit of s when there's a 2, into 4th when there's 3, etc., so for the above example s looks like this:
0b111110000000000
for [A,2,3,4,5] it would look like this
0b100 0000 0011 1100
etc.
v uses four bits to record multiple occurencies of same card, so it's 52bits long and if you have three Aces and two kings, its 8 MSB bits look like:
0111 0011 ...
The last line then checks for a flush or straight flush or royal flush (0x7c00).
import java.util.*; // Arrays, Set
import java.util.Map.Entry;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.*; // counting, groupingBy
public record Hand(Category category, Rank... ranks) implements Comparable<Hand> {
public static Hand evaluate(Set<Card> cards) {
if (cards.size() != 5) { throw new IllegalArgumentException(); }
var flush = cards.stream().map(Card::suit).distinct().count() == 1;
var counts = cards.stream().collect(groupingBy(Card::rank, counting()));
var ranks = counts.entrySet().stream().sorted(
comparing(Entry<Rank, Long>::getValue).thenComparing(Entry::getKey).reversed()
).map(Entry::getKey).toArray(Rank[]::new);
if (ranks.length == 4) {
return new Hand(ONE_PAIR, ranks);
} else if (ranks.length == 3) {
return new Hand(counts.get(ranks[0]) == 2 ? TWO_PAIR : THREE_OF_A_KIND, ranks);
} else if (ranks.length == 2) {
return new Hand(counts.get(ranks[0]) == 3 ? FULL_HOUSE : FOUR_OF_A_KIND, ranks);
} else if (ranks[0].ordinal() - ranks[4].ordinal() == 4) {
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, ranks[0]);
} else if (ranks[0].equals(ACE) && ranks[1].equals(FIVE)) { // A-2-3-4-5
return new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, FIVE);
} else {
return new Hand(flush ? FLUSH : HIGH_CARD, ranks);
}
}
#Override
public int compareTo(Hand that) { // first compare by category, then compare ranks lexicographically
return comparing(Hand::category).thenComparing(Hand::ranks, Arrays::compare).compare(this, that);
}
}
enum Category {HIGH_CARD, ONE_PAIR, TWO_PAIR, THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH}
enum Rank {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE}
enum Suit {DIAMONDS, CLUBS, HEARTS, SPADES}
record Card(Rank rank, Suit suit) {}
Here's a modified version of dansalmo's program which works for holdem hands:
def holdem(board, hands):
scores = [(evaluate((board + ' ' + hand).split()), i) for i, hand in enumerate(hands)]
best = max(scores)[0]
return [x[1] for x in filter(lambda(x): x[0] == best, scores)]
def evaluate(hand):
ranks = '23456789TJQKA'
if len(hand) > 5: return max([evaluate(hand[:i] + hand[i+1:]) for i in range(len(hand))])
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items())[::-1])
if len(score) == 5: # if there are 5 different ranks it could be a straight or a flush (or both)
if ranks[0:2] == (12, 3): ranks = (3, 2, 1, 0, -1) # adjust if 5 high straight
score = ([1,(3,1,2)],[(3,1,3),(5,)])[len({suit for _, suit in hand}) == 1][ranks[0] - ranks[4] == 4] # high card, straight, flush, straight flush
return score, ranks
def test():
print holdem('9H TC JC QS KC', [
'JS JD', # 0
'AD 9C', # 1 A-straight
'JD 2C', # 2
'AC 8D', # 3 A-straight
'QH KH', # 4
'TS 9C', # 5
'AH 3H', # 6 A-straight
'3D 2C', # 7
# '8C 2C', # 8 flush
])
test()
holdem() returns a list of indices of the winning hand(s). In the test() example that's [1, 3, 6], since the three hands with aces split the pot, or [8] if the flush hand is uncommented.
Python 3 version
def poker(hands):
scores = [(i, score(hand.split())) for i, hand in enumerate(hands)]
winner = sorted(scores , key=lambda x:x[1])[-1][0]
return hands[winner]
def score(hand):
ranks = '23456789TJQKA'
rcounts = {ranks.find(r): ''.join(hand).count(r) for r, _ in hand}.items()
score, ranks = zip(*sorted((cnt, rank) for rank, cnt in rcounts)[::-1])
if len(score) == 5:
if ranks[0:2] == (12, 3): #adjust if 5 high straight
ranks = (3, 2, 1, 0, -1)
straight = ranks[0] - ranks[4] == 4
flush = len({suit for _, suit in hand}) == 1
'''no pair, straight, flush, or straight flush'''
score = ([(1,), (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]
return score, ranks
>>> poker(['8C TS KC 9H 4S', '7D 2S 5D 3S AC', '8C AD 8D AC 9C', '7C 5H 8D TD KS'])
'8C AD 8D AC 9C'
Basically have to replace 1 by (1,) to avoid the int to tuple comparison error.
I have written a poker hand evaluator in both C++ and Javascript. Basically the program would convert a randomly picked set of cards to a 3d array of 1s and 0s. By converting the cards into this format I was then able to write functions that would test for each type of hand starting from the highest.
So in recap, my program would generate random cards, convert them into a 3D array of hearts, diamonds, spades and clubs, where 1 represented one of the cards I had. I would then test the 3D array to see if I had a Royal Flush, Then Straight Flush, Then 4 of a Kind until a match was detected. Once a match was detected say after testing for a flush, then my program wouldn't have to test for straight, 3 of a kind, etc as a flush beats a straight.
Below is outputted data from my program:
My random cards:
Table Cards
{ Value: '9', Suit: 'H' }
{ Value: 'A', Suit: 'H' }
{ Value: '9', Suit: 'D' }
{ Value: '7', Suit: 'S' }
{ Value: '6', Suit: 'S' }
3D array representing my cards:
A 2 3 4 5 6 7 8 9 10 J Q K A
Spades
[ 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 ]
Diamonds
[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 ]
Clubs
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]
Hearts
[ 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ]
Using the values above I can tell that I have a pair 9s with an A, 7, 6 kicker.
You can see the array includes Aces twice. This is because you want to test for a straight flush starting from A. So (A,2,3,4,5).
If you wanted to test for 7 cards instead of 5 you could also use this system. You can include the users 2 cards with the 5 on the table and run it through my system. You can also do the same for other players at the table and compare the results.
I hope this helps a little.
If you are representing a hand as an array of, for example, Card objects, then I would have methods for looping through this array and determining if it has a 2-of-a-kind, flush etc - and if it does, what type it is; so you could have the 3ofaKind() method return 5 if a hand had three 5s. Then I would establish a hierarchy of possibilities (e.g. 3 of a kind is higher than 2 of a kind) and work from there. The methods themselves should be pretty straightforward to write.
If you just want to understand how it works here is simple algorithm:
HandStrength(ourcards,boardcards)
{
ahead = tied = behind = 0
ourrank = Rank(ourcards,boardcards)
/* Consider all two-card combinations
of the remaining cards. */
for each case(oppcards)
{
opprank = Rank(oppcards,boardcards)
if(ourrank>opprank)
ahead += 1
else if(ourrank==opprank)
tied += 1
else /* < */
behind += 1
}
handstrength = (ahead+tied/2) / (ahead+tied+behind)
return(handstrength)
}
It is from "ALGORITHMS AND ASSESSMENT IN COMPUTER POKER" by Darse Billings.
Here's a simple rule-based implementation in Kotlin:
class PokerHand constructor(hand: String) : Comparable<PokerHand> {
companion object {
const val WIN = 1
const val TIE = 0
const val LOSS = -1
}
val cards: List<Card>
val isStraightFlush: Boolean
get() = isStraight && isFlush
val isFourOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 4 }
val isFullHouse: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.size == 2
val isFlush: Boolean
get() = cards.groupBy { it.suit }.map { it.value }.size == 1
val isStraight: Boolean
get() = cards.map { it.weight.ordinal } == (cards[0].weight.ordinal..cards[0].weight.ordinal + 4).toList()
val isThreeOfAKind: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 3 }
val isTwoPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.filter { it.size == 2 }.count() == 2
val isPair: Boolean
get() = cards.groupBy { it.weight }.map { it.value }.any { it.size == 2 }
init {
val cards = ArrayList<Card>()
hand.split(" ").forEach {
when (it.length != 2) {
true -> throw RuntimeException("A card code must be two characters")
else -> cards += Card(Weight.forCode(it[0]), Suit.forCode(it[1]))
}
}
if (cards.size != 5) {
throw RuntimeException("There must be five cards in a hand")
}
this.cards = cards.sortedBy { it.weight.ordinal }
}
override fun compareTo(other: PokerHand): Int = when {
(this.isStraightFlush || other.isStraightFlush) ->
if (this.isStraightFlush) if (other.isStraightFlush) compareByHighCard(other) else WIN else LOSS
(this.isFourOfAKind || other.isFourOfAKind) ->
if (this.isFourOfAKind) if (other.isFourOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isFullHouse || other.isFullHouse) ->
if (this.isFullHouse) if (other.isFullHouse) compareByHighCard(other) else WIN else LOSS
(this.isFlush || other.isFlush) ->
if (this.isFlush) if (other.isFlush) compareByHighCard(other) else WIN else LOSS
(this.isStraight || other.isStraight) ->
if (this.isStraight) if (other.isStraight) compareByHighCard(other) else WIN else LOSS
(this.isThreeOfAKind || other.isThreeOfAKind) ->
if (this.isThreeOfAKind) if (other.isThreeOfAKind) compareByHighCard(other) else WIN else LOSS
(this.isTwoPair || other.isTwoPair) ->
if (this.isTwoPair) if (other.isTwoPair) compareByHighCard(other) else WIN else LOSS
(this.isPair || other.isPair) ->
if (this.isPair) if (other.isPair) compareByHighCard(other) else WIN else LOSS
else -> compareByHighCard(other)
}
private fun compareByHighCard(other: PokerHand, index: Int = 4): Int = when {
(index < 0) -> TIE
cards[index].weight === other.cards[index].weight -> compareByHighCard(other, index - 1)
cards[index].weight.ordinal > other.cards[index].weight.ordinal -> WIN
else -> LOSS
}
}
Implementation details:
Instantiate with a coded hand, eg 2H 3H 4H 5H 6H
Methods to evaluate whether the hand is a 'Straight Flush', 'Four of a Kind', 'Full House' etc. These are easy to express in Kotlin.
Implements Comparable<PokerHand> to evaluate against another hand using a simple rules approach, eg a straight flush beats four of a kind, which beats a full house, and so forth.
The sources are here.
as the question was for Java and the answer was for Python I thought of posting a newer asnwer in Java. My target is the function to be easy to understand.
The Evaluator will score:
Royal flush - 10000
Straight flush - 9000 + highest card
Four of a kind - 8000 + card
Full house - 7000 + card
----- Here we have a smal gap
Flush - 5000 + highest card
Straight - 4000 + highest card
Three of a kind - 3000 + card
Two pair - 2000 + 13*card1 + card2 (card1 > card2)
Pair - 1000 + card
high card is not scored! (If you tie on a high card you need to keep checking for the next card etc...) If you want to encode that in your evaluator you would really need bitcode and the program would be less understandable. Fortunately enough, it is easy to check high card on two sorted hands so you first check score. If score is equal you check high card to break the tie ;-)
With no further due here is the code (works with sorted hands):
public static int scoreHand(int[] hand) {
return scoreSeries(hand) + scoreKinds(hand);
}
public static int scoreStraight(int[] hand) {
for(int i = 1; i < hand.length; i++) {
if ((hand[i] % 100 + 1) != (hand[i - 1] % 100)) return 0;
}
return 4000;
}
public static int scoreFlush(int[] hand) {
for(int i = 1; i < hand.length; i++) {
if ((hand[i] / 100) != (hand[i - 1] / 100)) return 0;
}
return 5000;
}
public static int scoreSeries(int[] hand) {
int score = scoreFlush(hand) + scoreStraight(hand);
if (hand[0] % 100 == 12 && score == 9000)
return 10000;
if (score > 0) return score + hand[0] % 100;
return 0;
}
public static int scoreKinds(int[] hand) {
int[] counts = new int[13], highCards = new int[2];
int max = 1, twoSets = 0;
for(int i = 0; i < hand.length; i++) {
counts[hand[i] % 100]++;
if (max > 1 && counts[hand[i] % 100] == 2) {
twoSets = 1;
highCards[1] = hand[i] % 100;
}
if (max < counts[hand[i] % 100]) {
max = counts[hand[i] % 100];
highCards[0] = hand[i] % 100;
}
}
if (max == 1) return 0;
int score = (max * 2 + twoSets) * 1000;
if (score < 7000) score -= 3000;
if (max == 2 && twoSets == 1) {
if (highCards[1] > highCards[0]) swap(highCards, 0, 1);
score += 13 * highCards[0] + highCards[1];
} else {
if (counts[highCards[1]] > counts[highCards[0]]) swap(highCards, 0, 1);
score += highCards[0];
}
return score;
}
Here is the algorithm translated to R, tested with a 6 card deck, corresponding to 42.504 combinations given by the result of:
combinations of poker hands. Did not tested with 13 card deck due to processing limitations (it would correspond to 2.598.960 combinations).
The algorithm represents the value of a hand by a string, composed by 2 parts:
5 character with ordered card count (ex. "31100" means three of a kind)
The card numbers are valued by letters from 'B' (Deuce) to 'N' (Ace) (ex. 'NILH' means Ace, Queen, Nine and Eight). It starts in letter 'B' because of the A2345 poker hand where the Ace comes before the '2' which (the Ace) will have the value 'A'.
So, for example, "32000NB" will be a Full House of three Aces and two Deuce.
The poker hand value string is convenient for comparative and ordering purposes.
library(tidyverse)
library(gtools)
hand_value <- function(playerhand) {
numbers <- str_split("23456789TJQKA", "")[[1]]
suits <- str_split("DCHS", "")[[1]]
playerhand <- data.frame(card = playerhand) %>% separate(card, c("number", "suit"), sep = 1)
number_values <- data.frame(number = numbers, value = LETTERS[2:14], stringsAsFactors = FALSE)
playerhand_number <- playerhand %>%
group_by(number) %>%
count(number) %>%
inner_join(number_values, by = "number") %>%
arrange(desc(n), desc(value))
playerhand_suit <- playerhand %>%
group_by(suit) %>%
count(suit) %>%
arrange(desc(n))
if (nrow(playerhand_number) == 5)
{
if (playerhand_number[1,1] == 'A' & playerhand_number[2,1] == '5')
playerhand_number <- data.frame(playerhand_number[,1:2], value = str_split("EDCBA", "")[[1]], stringsAsFactors = FALSE)
straight <- asc(playerhand_number[1,3]) - asc(playerhand_number[5,3]) == 4
} else
straight = FALSE
flush <- nrow(playerhand_suit) == 1
if (flush)
{
if (straight)
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(5, 0, 0, 0, 0), stringsAsFactors = FALSE) else
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(3, 1, 1, 2, 0), stringsAsFactors = FALSE)
} else
{
if (straight)
playerhand_number <- data.frame(playerhand_number[,c(1,3)], n = c(3, 1, 1, 1, 0), stringsAsFactors = FALSE)
}
playerhand_value <- append(append(c(playerhand_number$n), rep("0", 5 - nrow(playerhand_number))), c(playerhand_number$value))
playerhand_value <- paste(playerhand_value, collapse = '')
playerhand_value
}
Testing the function with the same hands of above example:
l <- c("8C TS KC 9H 4S", "7D 2S 5D 3S AC", "8C AD 8D AC 9C", '7C 5H 8D TD KS')
t <- as_tibble(l)
t <- t %>% mutate(hand = str_split(value, " ")) %>% select(hand)
t <- t %>% mutate(value = sapply(t[,1]$hand, hand_value)) %>% arrange(desc(value))
paste(t[[1]][[1]], collapse = " ")
Which returns the same result:
[1] "8C AD 8D AC 9C"
Hope it helps.
public class Line
{
private List<Card> _cardsToAnalyse;
public Line()
{
Cards = new List<Card>(5);
}
public List<Card> Cards { get; }
public string PriceName { get; private set; }
public int Result()
{
_cardsToAnalyse = Cards;
var valueComparer = new CardValueComparer();
_cardsToAnalyse.Sort(valueComparer);
if (ContainsStraightFlush(_cardsToAnalyse))
{
PriceName = "Straight Flush";
return PayTable.StraightFlush;
}
if (ContainsFourOfAKind(_cardsToAnalyse))
{
PriceName = "Quadra";
return PayTable.FourOfAKind;
}
if (ContainsStraight(_cardsToAnalyse))
{
PriceName = "Straight";
return PayTable.Straight;
}
if (ContainsFullen(_cardsToAnalyse))
{
PriceName = "Full House";
return PayTable.Fullen;
}
if (ContainsFlush(_cardsToAnalyse))
{
PriceName = "Flush";
return PayTable.Flush;
}
if (ContainsThreeOfAKind(_cardsToAnalyse))
{
PriceName = "Trinca";
return PayTable.ThreeOfAKind;
}
if (ContainsTwoPairs(_cardsToAnalyse))
{
PriceName = "Dois Pares";
return PayTable.TwoPairs;
}
if (ContainsPair(_cardsToAnalyse))
{
PriceName = "Um Par";
return PayTable.Pair;
}
return 0;
}
private bool ContainsFullen(List<Card> _cardsToAnalyse)
{
var valueOfThree = 0;
// Search for 3 of a kind
Card previousCard1 = null;
Card previousCard2 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null)
if (c.Value == previousCard1.Value && c.Value == previousCard2.Value)
valueOfThree = c.Value;
previousCard2 = previousCard1;
previousCard1 = c;
}
if (valueOfThree > 0)
{
Card previousCard = null;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
if (c.Value != valueOfThree)
return true;
previousCard = c;
}
return false;
}
return false;
}
private bool ContainsPair(List<Card> Cards)
{
Card previousCard = null;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
return true;
previousCard = c;
}
return false;
}
private bool ContainsTwoPairs(List<Card> Cards)
{
Card previousCard = null;
var countPairs = 0;
foreach (var c in Cards)
{
if (previousCard != null)
if (c.Value == previousCard.Value)
countPairs++;
previousCard = c;
}
if (countPairs == 2)
return true;
return false;
}
private bool ContainsThreeOfAKind(List<Card> Cards)
{
Card previousCard1 = null;
Card previousCard2 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null)
if (c.Value == previousCard1.Value && c.Value == previousCard2.Value)
return true;
previousCard2 = previousCard1;
previousCard1 = c;
}
return false;
}
private bool ContainsFlush(List<Card> Cards)
{
return Cards[0].Naipe == Cards[1].Naipe &&
Cards[0].Naipe == Cards[2].Naipe &&
Cards[0].Naipe == Cards[3].Naipe &&
Cards[0].Naipe == Cards[4].Naipe;
}
private bool ContainsStraight(List<Card> Cards)
{
return Cards[0].Value + 1 == Cards[1].Value &&
Cards[1].Value + 1 == Cards[2].Value &&
Cards[2].Value + 1 == Cards[3].Value &&
Cards[3].Value + 1 == Cards[4].Value
||
Cards[1].Value + 1 == Cards[2].Value &&
Cards[2].Value + 1 == Cards[3].Value &&
Cards[3].Value + 1 == Cards[4].Value &&
Cards[4].Value == 13 && Cards[0].Value == 1;
}
private bool ContainsFourOfAKind(List<Card> Cards)
{
Card previousCard1 = null;
Card previousCard2 = null;
Card previousCard3 = null;
foreach (var c in Cards)
{
if (previousCard1 != null && previousCard2 != null && previousCard3 != null)
if (c.Value == previousCard1.Value &&
c.Value == previousCard2.Value &&
c.Value == previousCard3.Value)
return true;
previousCard3 = previousCard2;
previousCard2 = previousCard1;
previousCard1 = c;
}
return false;
}
private bool ContainsStraightFlush(List<Card> Cards)
{
return ContainsFlush(Cards) && ContainsStraight(Cards);
}
}
Related
I have on the first problem of Google Foobar Level 2. The problem is:
Being a henchman isn't all drudgery. Occasionally, when feeling generous, Commander Lambda hand out Lucky LAMBs (Lambda's All-purpose Money Bucks). Henchmen can use Lucky LAMBs to buy things like a second pair of socks, a pillow for their bunks, or even a third daily meal!
However, actually passing out LAMBs isn't easy. Each henchman squad has a strict seniority ranking which must be respected -- or else the henchmen will revolt and you'll all get demoted back to minions again!
There are 4 key rules which you must follow in order to avoid a revolt:
1. The most junior henchman (with the least seniority) gets exactly 1 LAMB. (There will always be at least 1 henchman on a team.)
2. A henchman will revolt if the person who ranks immediately above them gets more than double the number of LAMBs they do.
3. A henchman will revolt if the amount of LAMBs given to their next two subordinates combined is more than the number of LAMBs they get. (Note that the two most junior henchmen won't have two subordinates, so this rule doesn't apply to them. The 2nd most junior henchman would require at least as many LAMBs as the most junior henchman.)
4. You can always find more henchmen to pay - the Commander has plenty of employees. If there are enough LAMBs left over such that another henchman could be added as the most senior while obeying the other rules, you must always add and pay that henchman.
Note that you may not be able to hand out all the LAMBs. A single LAMB cannot be subdivided. That is, all henchmen must get a positive integer number of LAMBs.
Write a function called solution(total_lambs), where total_lambs is the integer number of LAMBs in the handout you are trying to divide. It should return an integer which represents the difference between the minimum and maximum number of henchmen who can share the LAMBs (that is, being as generous as possible to those you pay and as stingy as possible, respectively) while still obeying all of the above rules to avoid a revolt. For instance, if you had 10 LAMBs and were as generous as possible, you could only pay 3 henchmen (1, 2, and 4 LAMBs, in order of ascending seniority), whereas if you were as stingy as possible, you could pay 4 henchmen (1, 1, 2, and 3 LAMBs). Therefore, solution(10) should return 4-3 = 1.
To keep things interesting, Commander Lambda varies the sizes of the Lucky LAMB payouts. You can expect total_lambs to always be a positive integer less than 1 billion (10 ^ 9).
My code:
public class Solution {
public static int solution(int total_lambs) {
// person 1 gets 1 lamb
// person 2 gets more than 1 lamb
// person 3 gets more than or = person 1 + person 2 but less or = than double person 2
// person 4 gets more than person 3 + person 2 but less than or = double person 3
return (solution_conservative(total_lambs) - solution_generous(total_lambs));
}
public static int solution_generous(int total_lambs) {
int lamb_pay_current = 0;
int person_before = 0;
//int person_before_before = 0;
int person_counter = 0;
for (int lamb_pay_cumm = 0; lamb_pay_cumm < total_lambs; lamb_pay_cumm += lamb_pay_current) {
if (!(total_lambs > 0)) {break;}
if ((total_lambs == 1)) {break;}
if ((lamb_pay_cumm == 0) && (total_lambs > 0)) {
lamb_pay_current = 1;
person_counter++;
continue;
}
if ((lamb_pay_cumm) == 1 && (total_lambs > 1)) {
lamb_pay_current = 2;
person_before = 1;
person_counter++;
continue;
}
if (person_before == 1) {
person_before = 2;
}
if (person_before * 2 + lamb_pay_cumm > total_lambs) {continue;}
lamb_pay_current = person_before * 2;
person_counter++;
// person_before_before = person_before;
person_before = lamb_pay_current;
}
if (total_lambs == 1) {return 1;}
if (!(total_lambs > 0)) {return 0;}
return person_counter;
}
public static int solution_conservative(int total_lambs) {
int lamb_pay_current = 0;
int person_before = 0;
int person_before_before = 0;
int person_counter = 0;
for (int lamb_pay_cumm = 0; lamb_pay_cumm < total_lambs; lamb_pay_cumm += lamb_pay_current) {
if (!(total_lambs > 0)) {break;}
if ((total_lambs == 1)) {break;}
if ((lamb_pay_cumm == 0) && (total_lambs > 0)) {
lamb_pay_current = 1;
person_counter++;
continue;
}
if ((lamb_pay_cumm) == 1 && (total_lambs > 1)) {
lamb_pay_current = 1;
person_before = 1;
person_counter++;
continue;
}
if (person_before == 1) {
person_before_before = 1;
}
if (person_before + person_before_before + lamb_pay_cumm > total_lambs) {continue;}
lamb_pay_current = person_before + person_before_before;
person_counter++;
person_before_before = person_before;
person_before = lamb_pay_current;
}
if (total_lambs == 1) {return 1;}
if (!(total_lambs > 0)) {return 0;}
return person_counter;
}
}
What I am trying to get done is that I have 2 functions. One is to find the most "generous" possible way to give everyone the most amount of LAMBS possible before someone revolts. This pattern appears to be like this: 1, 2, 4, 8, 16 etc. I may be wrong. The other function is to find the most "conservative" possible way to give everyone the least amount of LAMBS possible before someone revolts. This pattern appears to be like this: 1, 1, 2, 3, 5, 8, 13, etc. I may also be wrong.
Whenever I do
"verify Solutions.java", it always fails Test #7. All other tests succeed, just this one fails. And I don't know what Test #7 is.
i have also tried most of the tests i knew of on Intellij Idea but all of them looked correct to me...
You are right about the patterns of generous and stingy. Generous path follows powers of two and the stingy follows pattern of fibonacci.
It is hard to figure out what is wrong with your code. But I think most probably your code doesn't calculate the number of henchmen correctly especially when there are remaining lambs that can be handed out without violating the restrictions.
Generous:
Start with the power of two = 1 and keep taking powers of two and adding to lambs to be paid, until you exceed the total_lambs. When you exceed make sure that you subtract the excess from the paid out lambs, so you get the original lambs paid. Also get the last two paid lambs which can be easily obtained by:
current_power_of_two/2 + current_power_of_two/4
See if it is less than or equal to remaining lambs = total_lambs - lambs_paid, then increment the henchmen by 1.
Stingy: Its the same approach except here you keep track of the last two paid lambs in the fibonacci series.
Here is one straightforward implementation for both generous and stingy handouts:
public static int solution_generous(int total_lambs) {
// Apply power of two
int power_of_two = 1;
int henchmen = 1;
int lambs_paid = 1;
while ( lambs_paid <= total_lambs ) {
power_of_two = 2*power_of_two;
lambs_paid += power_of_two;
if ( lambs_paid > total_lambs ) {
lambs_paid -= power_of_two;
power_of_two = power_of_two/2;
break;
}
henchmen++;
}
int last_one = power_of_two;
int last_before_one = power_of_two/2;
if ( last_one + last_before_one <= total_lambs - lambs_paid ) {
henchmen++;
}
return henchmen;
}
public static int solution_conservative(int total_lambs) {
//Fibonacci
int f1 = 1;
int f2 = 1;
int f12 = f1 + f2;
int henchmen = 1;
int lambs_paid = f1;
int last_two_paid = f2;
while ( lambs_paid <= total_lambs ) {
last_two_paid = f2;
f1 = f2;
f2 = f12;
f12 = f1 + f2;
lambs_paid += f1;
if ( lambs_paid > total_lambs ) {
break;
}
henchmen++;
}
if ( last_two_paid <= total_lambs - lambs_paid ) {
henchmen++;
}
return henchmen;
}
I was asked to create a method that would:
Return a Change object or null if there was no possible change
The "machine" has unlimited bills of: 2, 5 and 10
The Change object must return the most minimal amount of bills possible
This was a question asked in codingame.com and wanted to investigate further on it.
Here's the code:
package com;
class Change {
long coin2 = 0, bill5 = 0, bill10 = 0;
}
public class Test {
static Change c = new Change();
public static void main(String[] args) {
Change m = optimalChange(19L);
if(m == null){
System.out.println("no change possible ...");
return;
}
System.out.println("Coin 2E: " + m.coin2);
System.out.println("bill 5E: " + m.bill5);
System.out.println("bill 10E: " + m.bill10);
long result = m.coin2 * 2 + m.bill5 * 5 + m.bill10 * 10;
System.out.println("Change given: " + result);
}
static Change optimalChange(long s) {
if (s < 2) {
return s == 0 ? c : null;
} else if (s < 5) {
c.coin2++;
return optimalChange(s - 2);
} else if (s < 10) {
c.bill5++;
return optimalChange(s - 5);
} else {
c.bill10++;
return optimalChange(s - 10);
}
}
}
What you are looking for is the most minimal amount of bills possible.
The Dynamic-Programming approach would be a more optimal approach for this.
Time-complexity = O(Money * |Coins|)
Let:
Coins = {c1, c2, c3, ... cN} => Set of coins that can be used to make change
Money = Amount of money required to get change for
D[i][j] = Represents the minimum of bills needed to change money=i with coins from set={c1, c2 ... cj}
Here is the working code (code is in Python, but easily transferrable to Java):
Coins = [2, 5, 10]
Money = 99
D = [[100000000 for j in range(len(Coins))] for i in range(Money + 1)]
for i in range(1, Money + 1):
for j in range(len(Coins)):
if j > 0:
D[i][j] = D[i][j-1]
if i == Coins[j]:
D[i][j] = min(D[i][j], 1)
elif i > Coins[j] and D[i - Coins[j]][j] > 0:
D[i][j] = min(1 + D[i - Coins[j]][j], D[i][j])
print (D[-1][-1])
Output:
12
Given a two 1d arrays that are stick one to the other with n and m lengths , write a recursive algorithm to find the number of ways that this shape could be filled by 1x1 or 1x2 or 2x1 blocks ,
here is my attempt , but I believe that I'm counting the same option several times :
public static int foo(int n1 ,int m){
if(n1==0 && m ==0){
return 1;
}
if(n1 < 0 || m < 0)
return 0;
return (foo(n1-1,m)+foo(n1,m-1)+foo(n1-1,m-1) +foo(n1,m-2) + foo(n1-2,m));
}
*** UPDATE ****
now the code compiles.
Examples :
input foo(2,2) output : 21 , the right answer is 7 .
input foo(4,3) output : 417, the right answer is 32.
these are the options for foo(2,2).
We'll assume n < m. If this is not the case we can just reverse the arguments - this makes the code simpler.
Once we've dealt with the terminating conditions we use a decrease-and-conquer strategy to reduce the input according to the following rules: if n == m, we can reduce both n & m by 1 two ways, n & m by 2 one way, n by 1 and m by 2 one way, and n by 2 and m by 1 one way. If n < m we can reduce m by 1 one way and m by 2 one way.
static int foo(int n, int m)
{
if(n > m) return foo(m, n);
if(n < 0 || m < 0) return 0;
if(n == 0 && m == 0) return 1;
if(n == m) return 2*foo(n-1, m-1) + foo(n-2, m-2) + foo(n-1, m-2) + foo(n-2, m-1);
return foo(n, m-1) + foo(n, m-2);
}
Test:
for(int i=0; i<5; i++)
for(int j=i; j<5; j++)
System.out.format("(%d, %d) = %d%n", i, j, foo(i, j));
Output:
(0, 0) = 1
(0, 1) = 1
(0, 2) = 2
(0, 3) = 3
(0, 4) = 5
(1, 1) = 2
(1, 2) = 3
(1, 3) = 5
(1, 4) = 8
(2, 2) = 7
(2, 3) = 10
(2, 4) = 17
(3, 3) = 22
(3, 4) = 32
(4, 4) = 71
For the case n == m (2, 7, 22, 71, ...) this is a known integer sequence (A030186).
And just for reference, here are the 32 configurations for (3,4):
I believe that i have found the correct answer to my question :
yet i'm not closing this problem until someone with better knowledge than me confirm my answer
public static int foo(int n1 ,int m){
if(n1==0 && m ==0){
return 1;
}
if(n1 < 0 || m < 0)
return 0;
if(m == n1){
return Integer.max(foo(n1-1,m),foo(n1,m-1)) + Integer.max(foo(n1-2,m),foo(n1,m-2))+ foo(n1-1,m-1);
}else{
return Integer.max(foo(n1-1,m),foo(n1,m-1)) + Integer.max(foo(n1-2,m),foo(n1,m-2));
}
}
now i'm taking only the maximum sub-Problem answer so I won't count the same option more than once.
I am stuck on the coin denomination problem.
I am trying to find the lowest number of coins used to make up $5.70 (or 570 cents). For example, if the coin array is {100,5,2,5,1} (100 x 10c coins, 5 x 20c, 2 x 50c, 5 x $1, and 1 x $2 coin), then the result should be {0,1,1,3,1}
At the moment the coin array will consist of the same denominations ( $2, $1, 50c, 20c, 10c)
public static int[] makeChange(int change, int[] coins) {
// while you have coins of that denomination left and the total
// remaining amount exceeds that denomination, take a coin of that
// denomination (i.e add it to your result array, subtract it from the
// number of available coins, and update the total remainder). –
for(int i= 0; i< coins.length; i++){
while (coins[i] > 0) {
if (coins[i] > 0 & change - 200 >= 0) {
coins[4] = coins[4]--;
change = change - 200;
} else
if (coins[i] > 0 & change - 100 >= 0) {
coins[3] = coins[3]--;
change = change - 100;
} else
if (coins[i] > 0 & change - 50 >= 0) {
coins[2] = coins[2]--;
change = change - 50;
} else
if (coins[i] > 0 & change - 20 >= 0) {
coins[1] = coins[1]--;
change = change - 20;
} else
if (coins[i] > 0 & change - 10 >= 0) {
coins[0] = coins[0]--;
change = change - 10;
}
}
}
return coins;
}
I am stuck on how to deduct the values from coins array and return it.
EDIT: New code
The brute force solution is to try up to the available number of coins of the highest denomination (stopping when you run out or the amount would become negative) and for each of these recurse on solving the remaining amount with a shorter list that excludes that denomination, and pick the minimum of these. If the base case is 1c the problem can always be solved, and the base case is return n otherwise it is n/d0 (d0 representing the lowest denomination), but care must be taken to return a large value when not evenly divisible so the optimization can pick a different branch. Memoization is possible, and parameterized by the remaining amount and the next denomination to try. So the memo table size would be is O(n*d), where n is the starting amount and d is the number of denominations.
So the problem can be solved in pseudo-polynomial time.
The wikipedia link is sparse on details on how to decide if a greedy algorithm such as yours will work. A better reference is linked in this CS StackExchange question. Essentially, if the coin system is canonical, a greedy algorithm will provide an optimal solution. So, is [1, 2, 5, 10, 20] canonical? (using 10s of cents for units, so that the sequence starts in 1)
According to this article, a 5-coin system is non-canonical if and only if it satisfies exactly one of the following conditions:
[1, c2, c3] is non-canonical (false for [1, 2, 5])
it cannot be written as [1, 2, c3, c3+1, 2*c3] (true for [1, 2, 5, 10, 20])
the greedyAnswerSize((k+1) * c4) > k+1 with k*c4 < c5 < (k+1) * c4; in this case, this would require a k*10 < 20 < (k+1)*10; there is no integer k in that range, so this is false for [1, 2, 5, 10, 20].
Therefore, since the greedy algorithm will not provide optimal answers (and even if it did, I doubt that it would work with limited coins), you should try dynamic programming or some enlightened backtracking:
import java.util.HashSet;
import java.util.PriorityQueue;
public class Main {
public static class Answer implements Comparable<Answer> {
public static final int coins[] = {1, 2, 5, 10, 20};
private int availableCoins[] = new int[coins.length];
private int totalAvailable;
private int totalRemaining;
private int coinsUsed;
public Answer(int availableCoins[], int totalRemaining) {
for (int i=0; i<coins.length; i++) {
this.availableCoins[i] = availableCoins[i];
totalAvailable += coins[i] * availableCoins[i];
}
this.totalRemaining = totalRemaining;
}
public boolean hasCoin(int coinIndex) {
return availableCoins[coinIndex] > 0;
}
public boolean isPossibleBest(Answer oldBest) {
boolean r = totalRemaining >= 0
&& totalAvailable >= totalRemaining
&& (oldBest == null || oldBest.coinsUsed > coinsUsed);
return r;
}
public boolean isAnswer() {
return totalRemaining == 0;
}
public Answer useCoin(int coinIndex) {
Answer a = new Answer(availableCoins, totalRemaining - coins[coinIndex]);
a.availableCoins[coinIndex]--;
a.totalAvailable = totalAvailable - coins[coinIndex];
a.coinsUsed = coinsUsed+1;
return a;
}
public int getCoinsUsed() {
return coinsUsed;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder("{");
for (int c : availableCoins) sb.append(c + ",");
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}
// try to be greedy first
#Override
public int compareTo(Answer a) {
int r = totalRemaining - a.totalRemaining;
return (r==0) ? coinsUsed - a.coinsUsed : r;
}
}
// returns an minimal set of coins to solve
public static int makeChange(int change, int[] availableCoins) {
PriorityQueue<Answer> queue = new PriorityQueue<Answer>();
queue.add(new Answer(availableCoins, change));
HashSet<String> known = new HashSet<String>();
Answer best = null;
int expansions = 0;
while ( ! queue.isEmpty()) {
Answer current = queue.remove();
expansions ++;
String s = current.toString();
if (current.isPossibleBest(best) && ! known.contains(s)) {
known.add(s);
if (current.isAnswer()) {
best = current;
} else {
for (int i=0; i<Answer.coins.length; i++) {
if (current.hasCoin(i)) {
queue.add(current.useCoin(i));
}
}
}
}
}
// debug
System.out.println("After " + expansions + " expansions");
return (best != null) ? best.getCoinsUsed() : -1;
}
public static void main(String[] args) {
for (int i=0; i<100; i++) {
System.out.println("Solving for " + i + ":"
+ makeChange(i, new int[]{100,5,2,5,1}));
}
}
}
You are in wrong direction. This program will not give you an optimal solution. To get optimal solution go with dynamic algorithms implemented and discussed here. Please visit these few links:
link 1
link 2
link 3
I am trying to sort a list using Collections.sort() and noticing notice all the members are being sorted:
Here is my input, a print out of the .compareTo() insides, and the output:
5 4 3 2 1 // Original
me = 4: o = 5 // A printout at each entry into .compareTo()
me = 3: o = 4
me = 3: o = 5
me = 2: o = 5
me = 2: o = 3
me = 1: o = 3
me = 1: o = 2
4 5 3 2 1 // Final output (1 should be at the beginning though)
My rules for sorting are:
1<4
3<2
4<5
My implementation is:
List<Task> tasks = new TaskList();
Task.create(tasks); // creates a list 5 4 3 2 1
while (scan.hasNext()) {
String line = scan.next();
Task.rules.add(line); // address the rules such as "1<4"
}
System.out.println(tasks);
Collections.sort(tasks);
And the compareTo() implementation:
#Override
public int compareTo(Object arg0) {
int me = id;
int o = ((Task) arg0).id;
System.out.println("me = " + me + ": o = " + o);
for (String s : rules) { // rules is an array of strings "1<4" etc
int left = Integer.valueOf(s.substring(0, 1));
int right = Integer.valueOf(s.substring(2));
char op = s.charAt(1);
boolean meLeft = left == me;
boolean oLeft = left == o;
boolean meRight = right == me;
boolean oRight = right == o;
if (meLeft && oRight) {
if (op == '<') { // me < other
return -1;
} else
return 1;
} else if (oLeft && meRight) {
if (op == '<') {// other < me
return 1;
} else {
return -1;
}
}
}
return 0;
}
As you can see from the "me = M, o = O" at the top, the Collections.sort() is not iterating through all the members of the list!
I would expect the following to show for each member "me" all the other members "o" to be compared, so I'd expected that list at the top of this question to be much longer! I believe its size should be N^2...
Your compareTo method breaks the contract for that method in two ways.
1) Transitivity says that if x.compareTo(y) > 0 and y.compareTo(z) > 0 then x.compareTo(z) > 0. Your method breaks this because 5 > 4 and 4 > 1, but 5>1 is not one of your rules.
2) compareTo must also meet the condition that if x.compareTo(y) == 0 then sgn(x.compareTo(z)) == sgn(y.compareTo(z)) for all z. Your method breaks this because 5.compareTo(1) == 0, whereas 5.compareTo(4) and 1.compareTo(4) have opposite signs.
If you don't meet the contract for compareTo, the results of sort are unpredictable. However in your case, we can see what's going on. 4, 5, 3, 2, 1 is in order because 4 < 5 = 3 < 2 = 1. (I am using = to mean the compareTo method returns 0). There are no > signs in that chain, so there is no reason to continue sorting.
If you want 1 to come to the front, in addition to making your compareTo method meet the two conditions above, you will have to add at least one rule involving something from [1, 4, 5] and something from [2, 3]. As long as there is no such rule, there is no reason for the 1 at the end to move past the 2 and the 3.