Search code examples
f#poker

Poker hand - Determining a full house in F#


Having this issue of my fullHouse function = true when there's a three-of-a-kind. The function checks for a 3 of a kind and a pair but it satisfies the logic with just a three of a kind (D, Ace)(C, Ace)(S, Ace)(D, Ten)(D, 9). This isn't a full house but it's allowing the same 3 aces to satisfy both the pair AND the 3 of a kind.

How do I restrict this so it cannot reduce the 3 of a kind into a pair?


Thanks!

EDIT: F# Newbie

EDIT_2: A full house is when out of your hand of 5 cards you have a 3 of a kind (3 of the same value (suit doesn't matter but they have to be 3x aces or 3x tens etc)) AND a pair (2x ten's, 2x 8's etc - suit doesn't matter)

Input:

fullHouse [(D, K);(C, K);(S, K);(D, T);(D, V 9)];;

Expected output: False, Actual output: True

Input:

fullHouse [(D, K);(C, K);(S, K);(D, T);(C, T)];;

Expected output: True, Actual Output: True


Solution

  • My take on this would be to handle all the cases of Four of a Kind, Full House, Triple, Pair or none of the above all together.

    To do this, I would use List.groupBy in order to group by card values. This will give you a list of lists of each group of the same card value. For example:

    [(D, K);(C, K);(S, K);(D, T);(D, V 9)] |> List.groupBy (snd);;
    

    Gives the result:

    [(K, [(D, K); (C, K); (S, K)]); (T, [(D, T)]); (V 9, [(D, V 9)])]
    

    i.e. A list of three Kings, a list of one Ten and a list of one Nine.

    Now you just need to make sure the longest sublists appear at the start for convenient pattern matching, so simply order this list by the number of cards contained in each sublist and then you can pattern match against the hand to obtain the result.

    let (|FourOfKind|FullHouse|Triple|Pair|Other|) hand =
        let groups = hand |> List.groupBy (snd) |> List.sortByDescending (List.length << snd)
        match groups with
        |(v, [c1; c2; c3; c4]) :: rest -> FourOfKind (c1, c2, c3, c4)
        |(v, [c1; c2; c3]) :: (v2, [c4; c5]) :: rest -> FullHouse(c1, c2, c3, c4, c5)
        |(v, [c1; c2; c3]) :: rest -> Triple(c1, c2, c3)
        |(v, [c1; c2]) :: rest -> Pair(c1, c2)
        |_ -> Other
    

    You could then do, e.g.

    let printHand = function
        |FourOfKind _ -> printfn "Four of a Kind"
        |FullHouse _ -> printfn "Full House"
        |Triple _ -> printfn "Triple"
        |Pair _ -> printfn "Pair"
        |Other -> printfn "Other"
    

    Then in fsi:

    printHand [(D, K);(C, K);(S, K);(D, T);(D, V 9)];;
    Triple
    
    printHand [(D, K);(C, K);(S, K);(D, T);(C, T)];;
    Full House