Skip to content

Instantly share code, notes, and snippets.

@misterspeedy
misterspeedy / gist:6872555
Created October 7, 2013 18:21
Representing a card suit as a Discriminated Union.
/// A card 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:6872596
Created October 7, 2013 18:23
Representing a card rank as a Discriminated Union
/// 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:6872627
Created October 7, 2013 18:25
Representing a hand of cards as an F# type.
/// 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:6875621
Created October 7, 2013 21:56
Some utility functions which summarise an array of cards in various useful ways.
/// 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:6875648
Created October 7, 2013 21:58
Royal Flush active pattern.
let (|RoyalFlush|_|) (hand : Hand) =
if (hand.Cards.[0].Rank) = Ace && (Consecutive hand.Cards) && (SameSuit hand.Cards) then
RoyalFlush |> Some
else
None
@misterspeedy
misterspeedy / gist:6875657
Created October 7, 2013 21:59
Partial active pattern for Straight Flush
let (|StraightFlush|_|) (hand : Hand) =
if (SameSuit hand.Cards) && (Consecutive hand.Cards) then
StraightFlush |> Some
else
None
@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
@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: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:6889386
Created October 8, 2013 18:36
Make invalid state unrepresentable.
let rank1, rank2 = hand1.Cards.[0].Rank, hand2.Cards.[0].Rank