Skip to content

Instantly share code, notes, and snippets.

@misterspeedy
misterspeedy / gist:6890347
Created October 8, 2013 19:40
Partial active pattern for Royal Flush
let (|RoyalFlush|_|) (hand : Hand) =
if (hand.Cards.[0].Rank) = Ace && (Consecutive hand.Cards) && (SameSuit hand.Cards) then
RoyalFlush |> Some
else
None
@misterspeedy
misterspeedy / gist:6890274
Created October 8, 2013 19:36
Utility functions
/// True if all cards in the sequence are the same suit.
let SameSuit cards =
( cards |> Seq.distinctBy (fun card -> card.Suit) |> Seq.length ) = 1
/// True if all the cards in the sequence are consecutive by value.
/// Includes both the high-Ace and the low-Ace cases.
let Consecutive cards =
cards
|> Array.map (fun card -> card.Rank)
|> Array.sortBy (fun rank -> 0 - rank.SortValue)
@misterspeedy
misterspeedy / gist:6889791
Created October 8, 2013 19:02
Type to represent a hand of cards
/// A hand of exactly five cards.
type Hand(cards : Card[]) =
do
if cards.Length <> 5 then
raise (ArgumentException("Invalid number of cards"))
/// The cards in the hand, sorted in descending order of rank.
member h.Cards = cards |> Array.sortBy (fun card -> 0 - card.Rank.SortValue)
static member FromString (s : string) =
let cards =
s.Split([|' '|])
@misterspeedy
misterspeedy / gist:6889775
Created October 8, 2013 19:01
Type to represent a card
/// A playing card.
type Card = { Rank : Rank; Suit : Suit }
with
static member FromString (s : String) =
let rank, suit =
match s.Length with
| 2 -> s.Substring(0, 1), s.[1]
// The 10 case has three characters
| 3 -> s.Substring(0, 2), s.[2]
| _ -> raise (ArgumentException("Invalid card string: ", s))
@misterspeedy
misterspeedy / gist:6889751
Created October 8, 2013 19:00
DU to represent a rank
/// A card rank.
type Rank =
| Ace | King | Queen | Jack | Value of int
static member FromString s =
match s with
| "A" -> Ace | "K" -> King | "Q" -> Queen | "J" -> Jack
| "10" -> Value(10)
| _ when s.Length = 1 && s.[0] >= '2' && s.[0] <= '9' -> Value(int(s.[0]) - int('0'))
| _ -> raise (ArgumentException(sprintf "Invalid rank string: %s" s))
/// The value of the rank for comparison purposes.
@misterspeedy
misterspeedy / gist:6889717
Created October 8, 2013 18:57
DU to represent a suit
type Suit =
| Club | Diamond | Heart | Spade
static member FromChar c =
match c with
| '♣' -> Club | '♦' -> Diamond | '♥' -> Heart | '♠' -> Spade
| _ -> raise (ArgumentException(sprintf "Invalid suit character: %c" c))
@misterspeedy
misterspeedy / gist:6889386
Created October 8, 2013 18:36
Make invalid state unrepresentable.
let rank1, rank2 = hand1.Cards.[0].Rank, hand2.Cards.[0].Rank
@misterspeedy
misterspeedy / gist:6889316
Created October 8, 2013 18:31
Comparing two Poker hands.
/// Compare two hands, the first of which can Win, Draw or Lose against the second.
let CompareHands (hand1 : Hand) (hand2 : Hand) =
match hand1, hand2 with
| RoyalFlush, RoyalFlush ->
raise (ArgumentException("Impossible combination: two Royal Flushes"))
| RoyalFlush, _ -> Win
| _, RoyalFlush -> Lose
| StraightFlush, StraightFlush ->
@misterspeedy
misterspeedy / gist:6889219
Created October 8, 2013 18:25
Discriminated union to represent the outcomes of comparing two cards.
/// The possible outcomes when comparing two Poker hands.
type Outcome = Win | Draw | Lose
with
static member FromRanks (rank1 : Rank) (rank2 : Rank) =
let sortValue1, sortValue2 = rank1.SortValue, rank2.SortValue
if sortValue1 > sortValue2 then
Win
elif sortValue1 < sortValue2 then
Lose
else
@misterspeedy
misterspeedy / gist:6875681
Created October 7, 2013 22:01
Partial active pattern for Four of a Kind
let (|FourOfAKind|_|) (hand : Hand) =
if (RankCounts hand.Cards).[0] = 4 then
FourOfAKind |> Some
else
None