The simplest algorithm for poker hand evaluation
Asked Answered
S

13

32

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 ?

Soidisant answered 28/4, 2012 at 13:27 Comment(4)
This is very simple, clean and well explained: nsayer.blogspot.com/2007/07/…Infract
There are lots and lots of (probably) relevant question in the "related" sidebar on the right. Do none of them answer your question?Godroon
@OliCharlesworth I saw mostly links to existing librariesSoidisant
@iccthedral I didn't like it too much, evaluating all 21 combinations of 5 cards in a 7 card set seems very inefficient. There are algorithms to determine the best hand out of 7 cards without having to look at every combination and the algorithm is just slightly more complicated than the one for 5 cards.Hurd
Q
33

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'
Quass answered 21/12, 2013 at 5:41 Comment(12)
This doesn't work, it will choose a Three of a Kind over a Straight. poker(['JC JH JD 5C 8D', '2D 3C 4S 5D 6C']) will return 'JC JH JD 5C 8D'Persaud
You should be able to fix this by simple using score = ([1, (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]Persaud
The code from dansalmo above is definitely the most elegant version, however it doesn't work in Python 3 because it throws an error: "TypeError: unorderable types: tuple() < int()". Could it be that there is bug in it as a tuple is compared to an int?Ahimsa
Python 3 does not let you compare different types like 2.x did. It is probably due the sort. See peterbe.com/plog/sorting-mixed-type-lists-in-python-3Quass
Yes it's the sort that throws the error. Is there an easy way to fix it?Ahimsa
The fix is: score = ([(1, ), (3,1,1,1)], [(3,1,1,2), (5,)])[flush][straight]Ahimsa
in reality there are usually 7 cards after the river. How would this change the code? Also, shouldn't it matter which hands are on the table and which are held by a player? Only that way it can be determined which card is the kicker?Ahimsa
This for ranking basic 5 card hands at the showdown. Not for stud or hold'em type games.Quass
In what way would it have to be notified for Holdem?Ahimsa
Simplest way would be to create all possible 5 card hands from 7 cards and then rank them using above method to find the best hand.Quass
This works and is a little shorter: score = ([1,(3,1,2)],[(3,1,3),(5,)])[flush][straight]Photoperiod
"It will get considerably longer if converted to Java." Challenge accepted: https://mcmap.net/q/446888/-the-simplest-algorithm-for-poker-hand-evaluationBrescia
H
14

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.

Holter answered 4/5, 2012 at 21:40 Comment(1)
Some info on the 2+2 solution: github.com/tangentforks/TwoPlusTwoHandEvaluatorMontemayor
Q
9

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).

Quijano answered 22/11, 2015 at 10:20 Comment(4)
I think it would be prudent to include your source: codeproject.com/Articles/569271/… Great article, by the way.Plier
Sure it would, sorry for that. Made an edit to reference the article also in the answer.Shrub
The returned value is not useful if you want to decide which hand won. You would also need to include what pairs and kickers and such.Coefficient
The OP asked about poker hand evaluation - which is exactly what it does. It does not and I think it should not include rules of the game as that would be handled elsewhere - so that we adhere to the single responsibility principleShrub
B
5
public record Card(Rank rank, Suit suit) {
    public enum Rank {
        TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE
    }

    public enum Suit {
        CLUBS, DIAMONDS, HEARTS, SPADES
    }
}
public enum Category {
    HIGH_CARD, PAIR, TWO_PAIR, TRIPS, STRAIGHT, FLUSH, FULL_HOUSE, QUADS, STRAIGHT_FLUSH
}
import java.util.*; // Arrays, Comparator, Set
import java.util.function.Function;

import static java.util.Comparator.*; // comparing, naturalOrder
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) {
        assert cards.size() == 5; // note that assertions are disabled by default
        var counts = cards.stream().collect(groupingBy(Card::rank, counting()));
        Function<Rank,Long> count = counts::get;
        var order = comparing(count).thenComparing(naturalOrder()).reversed();
        Rank[] ranks = counts.keySet().stream().sorted(order).toArray(Rank[]::new);
        boolean straight = ranks[0].ordinal() - ranks[ranks.length - 1].ordinal() == 4;
        boolean wheel = ranks[0] == ACE && ranks[1] == FIVE;
        boolean flush = cards.stream().map(Card::suit).distinct().count() == 1;
        return counts.get(ranks[0]) == 4 ? new Hand(QUADS, ranks)
             : ranks.length == 2 ? new Hand(FULL_HOUSE, ranks)
             : counts.get(ranks[0]) == 3 ? new Hand(TRIPS, ranks)
             : ranks.length == 3 ? new Hand(TWO_PAIR, ranks)
             : ranks.length == 4 ? new Hand(PAIR, ranks)
             : straight ? new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, ranks[0])
             : wheel ? new Hand(flush ? STRAIGHT_FLUSH : STRAIGHT, FIVE)
             : new Hand(flush ? FLUSH : HIGH_CARD, ranks);
    }

    @Override
    public int compareTo(Hand hand) {
        Comparator<Hand> category = comparing(Hand::category);
        Comparator<Hand> ranks = comparing(Hand::ranks, Arrays::compare);
        return category.thenComparing(ranks).compare(this, hand);
    }
}
Brescia answered 28/4, 2012 at 13:27 Comment(0)
P
4

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.

Photoperiod answered 2/11, 2015 at 20:12 Comment(1)
Python 3 gives weird errors in evaluate function: TypeError: '>' not supported between instances of 'tuple' and 'int'Distant
E
4

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.

Emden answered 4/3, 2020 at 21:30 Comment(0)
D
3

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.

Deed answered 9/2, 2020 at 10:18 Comment(0)
M
2

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.

Meaghan answered 28/4, 2012 at 13:36 Comment(1)
Don't forget that some 3-of-a-kind's are better than othersAfterbirth
S
2

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;
}
Sarmentose answered 17/12, 2022 at 13:1 Comment(0)
Y
1

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.

Yean answered 6/5, 2012 at 21:17 Comment(0)
G
1

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.

Galenism answered 13/12, 2018 at 6:54 Comment(1)
you can't compare by high card to decide when both hands are pairs, trips etc. 4S 4C AS 2D 2H, beats 8D 8H 3H 4H 5H , the higher pair should winBerley
O
0

Here is the algorithm translated to R, tested with a 6 card deck, corresponding to 42.504 combinations given by the result of:

C65

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.

Oxtail answered 6/10, 2018 at 11:45 Comment(0)
S
0
 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);
    }
}
Stemson answered 14/4, 2020 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.