I really do enjoy writing F# code. In fact, I enjoy it more than C# or XAML. I feel as if I’m spending my mornings doing Soduku.

This post will go over my thought process as I attempted to construct a deck of cards.

My first attempt was the following:

module TempImpl

type Joker = Big | Little with
    static member Suite() = [Big ; Little]

type Spade = 
    | Ace  | King  | Queen | Jack| Ten
    | Nine | Eight | Seven | Six
    | Five | Four  | Three | Two with
    static member Suite() = [Ace  ; King  ; Queen ; Jack ; Ten
                             Nine ; Eight ; Seven ; Six
                             Five ; Four  ; Three ; Two]

type Club = 
    | Ace  | King  | Queen | Jack| Ten
    | Nine | Eight | Seven | Six
    | Five | Four  | Three | Two with
    static member Suite() = [Ace  ; King  ; Queen ; Jack ; Ten
                             Nine ; Eight ; Seven ; Six
                             Five ; Four  ; Three ; Two]

type Heart = 
    | Ace  | King  | Queen | Jack| Ten
    | Nine | Eight | Seven | Six
    | Five | Four  | Three | Two with
    static member Suite() = [Ace  ; King  ; Queen ; Jack ; Ten
                             Nine ; Eight ; Seven ; Six
                             Five ; Four  ; Three ; Two]

type Diamond = 
    | Ace  | King  | Queen | Jack| Ten
    | Nine | Eight | Seven | Six
    | Five | Four  | Three | Two with
    static member Suite() = [Ace  ; King  ; Queen ; Jack ; Ten
                             Nine ; Eight ; Seven ; Six
                             Five ; Four  ; Three ; Two]

type Deck = 
    | Spades   of Spade   list
    | Hearts   of Heart   list
    | Clubs    of Club    list
    | Diamonds of Diamond list
    | Jokers   of Joker   list

let deck = [Spades   <| Spade.Suite()
            Hearts   <| Heart.Suite()
            Clubs    <| Club.Suite()
            Diamonds <| Diamond.Suite()
            Jokers   <| Joker.Suite()]

The following output was generated:

val deck : Deck list =
  [Spades
     [Ace; King; Queen; Jack; Ten; Nine; Eight; Seven; Six; Five; Four; Three;
      Two];
   Hearts
     [Ace; King; Queen; Jack; Ten; Nine; Eight; Seven; Six; Five; Four; Three;
      Two];
   Clubs
     [Ace; King; Queen; Jack; Ten; Nine; Eight; Seven; Six; Five; Four; Three;
      Two];
   Diamonds
     [Ace; King; Queen; Jack; Ten; Nine; Eight; Seven; Six; Five; Four; Three;
      Two]; Jokers [Big; Little]]

The output above presents challenges if I were to next shuffle the deck. Hence, the list consists of a list of suits instead of a list of cards.

I then went back to the drawing board and wrote the following:

module File1

type Ace =   Spades | Hearts | Clubs | Diamonds
type King =  Spades | Hearts | Clubs | Diamonds
type Queen = Spades | Hearts | Clubs | Diamonds
type Jack =  Spades | Hearts | Clubs | Diamonds
type Ten =   Spades | Hearts | Clubs | Diamonds
type Nine =  Spades | Hearts | Clubs | Diamonds
type Eight = Spades | Hearts | Clubs | Diamonds
type Seven = Spades | Hearts | Clubs | Diamonds
type Six =   Spades | Hearts | Clubs | Diamonds
type Five =  Spades | Hearts | Clubs | Diamonds
type Four =  Spades | Hearts | Clubs | Diamonds
type Three = Spades | Hearts | Clubs | Diamonds
type Two =   Spades | Hearts | Clubs | Diamonds

type Suit =
    | Ace   of Ace 
    | King  of King 
    | Queen of Queen 
    | Jack  of Jack
    | Ten   of Ten 
    | Nine  of Nine 
    | Eight of Eight
    | Seven of Seven
    | Six   of Six 
    | Five  of Five 
    | Four  of Four 
    | Three of Three 
    | Two   of Two
    | BigJoker   
    | LittleJoker

let deck = 
    [
     Ace Ace.Spades   ; King King.Spades   ; Queen Queen.Spades   ; Jack Jack.Spades  
     Ace Ace.Hearts   ; King King.Hearts   ; Queen Queen.Hearts   ; Jack Jack.Hearts  
     Ace Ace.Clubs    ; King King.Clubs    ; Queen Queen.Clubs    ; Jack Jack.Clubs   
     Ace Ace.Diamonds ; King King.Diamonds ; Queen Queen.Diamonds ; Jack Jack.Diamonds

     Ten Ten.Spades   ; Nine Nine.Spades   ; Eight Eight.Spades   ; Seven Seven.Spades  
     Ten Ten.Hearts   ; Nine Nine.Hearts   ; Eight Eight.Hearts   ; Seven Seven.Hearts  
     Ten Ten.Clubs    ; Nine Nine.Clubs    ; Eight Eight.Clubs    ; Seven Seven.Clubs   
     Ten Ten.Diamonds ; Nine Nine.Diamonds ; Eight Eight.Diamonds ; Seven Seven.Diamonds

     Six Six.Spades   ; Five Five.Spades   ; Four Four.Spades   ; Three Three.Spades  
     Six Six.Hearts   ; Five Five.Hearts   ; Four Four.Hearts   ; Three Three.Hearts
     Six Six.Clubs    ; Five Five.Clubs    ; Four Four.Clubs    ; Three Three.Clubs   
     Six Six.Diamonds ; Five Five.Diamonds ; Four Four.Diamonds ; Three Three.Diamonds

     Two Two.Spades
     Two Two.Hearts
     Two Two.Clubs    
     Two Two.Diamonds 

     BigJoker ; LittleJoker
    ]

The above code generated the following deck:

val deck : Suit list =
  [Ace Spades; King Spades; Queen Spades; Jack Spades; Ace Hearts; King Hearts;
   Queen Hearts; Jack Hearts; Ace Clubs; King Clubs; Queen Clubs; Jack Clubs;
   Ace Diamonds; King Diamonds; Queen Diamonds; Jack Diamonds; Ten Spades;
   Nine Spades; Eight Spades; Seven Spades; Ten Hearts; Nine Hearts;
   Eight Hearts; Seven Hearts; Ten Clubs; Nine Clubs; Eight Clubs; Seven Clubs;
   Ten Diamonds; Nine Diamonds; Eight Diamonds; Seven Diamonds; Six Spades;
   Five Spades; Four Spades; Three Spades; Six Hearts; Five Hearts;
   Four Hearts; Three Hearts; Six Clubs; Five Clubs; Four Clubs; Three Clubs;
   Six Diamonds; Five Diamonds; Four Diamonds; Three Diamonds; Two Spades;
   Two Hearts; Two Clubs; Two Diamonds; BigJoker; LittleJoker]

The deck generated above was better than my previous deck. Hence, I actually had a deck of cards instead of a deck of suits.

I then refactored the code above to the following:

type Ace =   Spades | Hearts | Clubs | Diamonds
type King =  Spades | Hearts | Clubs | Diamonds
type Queen = Spades | Hearts | Clubs | Diamonds
type Jack =  Spades | Hearts | Clubs | Diamonds
type Ten =   Spades | Hearts | Clubs | Diamonds
type Nine =  Spades | Hearts | Clubs | Diamonds
type Eight = Spades | Hearts | Clubs | Diamonds
type Seven = Spades | Hearts | Clubs | Diamonds
type Six =   Spades | Hearts | Clubs | Diamonds
type Five =  Spades | Hearts | Clubs | Diamonds
type Four =  Spades | Hearts | Clubs | Diamonds
type Three = Spades | Hearts | Clubs | Diamonds
type Two =   Spades | Hearts | Clubs | Diamonds

type Deck =
    | Ace   of Ace 
    | King  of King 
    | Queen of Queen 
    | Jack  of Jack
    | Ten   of Ten 
    | Nine  of Nine 
    | Eight of Eight
    | Seven of Seven
    | Six   of Six 
    | Five  of Five 
    | Four  of Four 
    | Three of Three 
    | Two   of Two
    | BigJoker   
    | LittleJoker with

    static member Generate() = 
        [
        Ace Ace.Spades   ; King King.Spades   ; Queen Queen.Spades   ; Jack Jack.Spades  
        Ace Ace.Hearts   ; King King.Hearts   ; Queen Queen.Hearts   ; Jack Jack.Hearts  
        Ace Ace.Clubs    ; King King.Clubs    ; Queen Queen.Clubs    ; Jack Jack.Clubs   
        Ace Ace.Diamonds ; King King.Diamonds ; Queen Queen.Diamonds ; Jack Jack.Diamonds

        Ten Ten.Spades   ; Nine Nine.Spades   ; Eight Eight.Spades   ; Seven Seven.Spades  
        Ten Ten.Hearts   ; Nine Nine.Hearts   ; Eight Eight.Hearts   ; Seven Seven.Hearts  
        Ten Ten.Clubs    ; Nine Nine.Clubs    ; Eight Eight.Clubs    ; Seven Seven.Clubs   
        Ten Ten.Diamonds ; Nine Nine.Diamonds ; Eight Eight.Diamonds ; Seven Seven.Diamonds

        Six Six.Spades   ; Five Five.Spades   ; Four Four.Spades   ; Three Three.Spades  
        Six Six.Hearts   ; Five Five.Hearts   ; Four Four.Hearts   ; Three Three.Hearts
        Six Six.Clubs    ; Five Five.Clubs    ; Four Four.Clubs    ; Three Three.Clubs   
        Six Six.Diamonds ; Five Five.Diamonds ; Four Four.Diamonds ; Three Three.Diamonds

        Two Two.Spades
        Two Two.Hearts
        Two Two.Clubs    
        Two Two.Diamonds 

        BigJoker ; LittleJoker
        ]

let result = Deck.Generate()

The output was the same:

val result : Deck list =
  [Ace Spades; King Spades; Queen Spades; Jack Spades; Ace Hearts; King Hearts;
   Queen Hearts; Jack Hearts; Ace Clubs; King Clubs; Queen Clubs; Jack Clubs;
   Ace Diamonds; King Diamonds; Queen Diamonds; Jack Diamonds; Ten Spades;
   Nine Spades; Eight Spades; Seven Spades; Ten Hearts; Nine Hearts;
   Eight Hearts; Seven Hearts; Ten Clubs; Nine Clubs; Eight Clubs; Seven Clubs;
   Ten Diamonds; Nine Diamonds; Eight Diamonds; Seven Diamonds; Six Spades;
   Five Spades; Four Spades; Three Spades; Six Hearts; Five Hearts;
   Four Hearts; Three Hearts; Six Clubs; Five Clubs; Four Clubs; Three Clubs;
   Six Diamonds; Five Diamonds; Four Diamonds; Three Diamonds; Two Spades;
   Two Hearts; Two Clubs; Two Diamonds; BigJoker; LittleJoker]

I then revisited a blog post from last year, that Mark Seeman had influenced:

type Suit = | Spades
            | Clubs
            | Diamonds
            | Hearts
 
type Face = | Two  | Three | Four  | Five
            | Six  | Seven | Eight | Nine | Ten
            | Jack | Queen | King  | Ace
 
type Card = { Face:Face; Suit:Suit }
 
let suits = [Spades; Clubs; Diamonds; Hearts]
let faces = [Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
                     Jack; Queen; King; Ace]
 
let deck = [for suit in suits do
                for face in faces do
                    yield {Face=face; Suit=suit}]

Here’s the output:

val deck : Card list =
  [{Face = Two;
    Suit = Spades;}; {Face = Three;
                      Suit = Spades;}; {Face = Four;
                                        Suit = Spades;}; {Face = Five;
                                                          Suit = Spades;};
   {Face = Six;
    Suit = Spades;}; {Face = Seven;
                      Suit = Spades;}; {Face = Eight;
                                        Suit = Spades;}; {Face = Nine;
                                                          Suit = Spades;};
   {Face = Ten;
    Suit = Spades;}; {Face = Jack;
                      Suit = Spades;}; {Face = Queen;
                                        Suit = Spades;}; {Face = King;
                                                          Suit = Spades;};
   {Face = Ace;
    Suit = Spades;}; {Face = Two;
                      Suit = Clubs;}; {Face = Three;
                                       Suit = Clubs;}; {Face = Four;
                                                        Suit = Clubs;};
   {Face = Five;
    Suit = Clubs;}; {Face = Six;
                     Suit = Clubs;}; {Face = Seven;
                                      Suit = Clubs;}; {Face = Eight;
                                                       Suit = Clubs;};
   {Face = Nine;
    Suit = Clubs;}; {Face = Ten;
                     Suit = Clubs;}; {Face = Jack;
                                      Suit = Clubs;}; {Face = Queen;
                                                       Suit = Clubs;};
   {Face = King;
    Suit = Clubs;}; {Face = Ace;
                     Suit = Clubs;}; {Face = Two;
                                      Suit = Diamonds;}; {Face = Three;
                                                          Suit = Diamonds;};
   {Face = Four;
    Suit = Diamonds;}; {Face = Five;
                        Suit = Diamonds;}; {Face = Six;
                                            Suit = Diamonds;};
   {Face = Seven;
    Suit = Diamonds;}; {Face = Eight;
                        Suit = Diamonds;}; {Face = Nine;
                                            Suit = Diamonds;};
   {Face = Ten;
    Suit = Diamonds;}; {Face = Jack;
                        Suit = Diamonds;}; {Face = Queen;
                                            Suit = Diamonds;};
   {Face = King;
    Suit = Diamonds;}; {Face = Ace;
                        Suit = Diamonds;}; {Face = Two;
                                            Suit = Hearts;}; {Face = Three;
                                                              Suit = Hearts;};
   {Face = Four;
    Suit = Hearts;}; {Face = Five;
                      Suit = Hearts;}; {Face = Six;
                                        Suit = Hearts;}; {Face = Seven;
                                                          Suit = Hearts;};
   {Face = Eight;
    Suit = Hearts;}; {Face = Nine;
                      Suit = Hearts;}; {Face = Ten;
                                        Suit = Hearts;}; {Face = Jack;
                                                          Suit = Hearts;};
   {Face = Queen;
    Suit = Hearts;}; {Face = King;
                      Suit = Hearts;}; {Face = Ace;
                                        Suit = Hearts;}]

> 

The code above did not account for jokers though.

The following model accounts for jokers in the deck:

type Suit = 
    | Spades | Hearts 
    | Clubs  | Diamonds

type Face =
    | Ace  | King  | Queen | Jack | Ten
    | Nine | Eight | Seven | Six  | Five | Four | Three | Two

type Joker = BigJoker | LittleJoker

type Standard = { Face:Face; Suit:Suit }

and Card = 
    | Card of Standard 
    | Wild of Joker

let suits = [Spades; Hearts; Clubs; Diamonds]

let faces = [Ace; King; Queen; Jack; Ten; Nine; Eight; Seven
             Six; Five; Four; Three; Two]

let deck = [for suit in suits do
                for face in faces do
                    yield Card { Face=face; Suit=suit }
           ] @ [Wild BigJoker
                Wild LittleJoker]

The output is the following:

val deck : Card list =
  [Card {Face = Ace;
         Suit = Spades;}; Card {Face = King;
                                Suit = Spades;}; Card {Face = Queen;
                                                       Suit = Spades;};
   Card {Face = Jack;
         Suit = Spades;}; Card {Face = Ten;
                                Suit = Spades;}; Card {Face = Nine;
                                                       Suit = Spades;};
   Card {Face = Eight;
         Suit = Spades;}; Card {Face = Seven;
                                Suit = Spades;}; Card {Face = Six;
                                                       Suit = Spades;};
   Card {Face = Five;
         Suit = Spades;}; Card {Face = Four;
                                Suit = Spades;}; Card {Face = Three;
                                                       Suit = Spades;};
   Card {Face = Two;
         Suit = Spades;}; Card {Face = Ace;
                                Suit = Hearts;}; Card {Face = King;
                                                       Suit = Hearts;};
   Card {Face = Queen;
         Suit = Hearts;}; Card {Face = Jack;
                                Suit = Hearts;}; Card {Face = Ten;
                                                       Suit = Hearts;};
   Card {Face = Nine;
         Suit = Hearts;}; Card {Face = Eight;
                                Suit = Hearts;}; Card {Face = Seven;
                                                       Suit = Hearts;};
   Card {Face = Six;
         Suit = Hearts;}; Card {Face = Five;
                                Suit = Hearts;}; Card {Face = Four;
                                                       Suit = Hearts;};
   Card {Face = Three;
         Suit = Hearts;}; Card {Face = Two;
                                Suit = Hearts;}; Card {Face = Ace;
                                                       Suit = Clubs;};
   Card {Face = King;
         Suit = Clubs;}; Card {Face = Queen;
                               Suit = Clubs;}; Card {Face = Jack;
                                                     Suit = Clubs;};
   Card {Face = Ten;
         Suit = Clubs;}; Card {Face = Nine;
                               Suit = Clubs;}; Card {Face = Eight;
                                                     Suit = Clubs;};
   Card {Face = Seven;
         Suit = Clubs;}; Card {Face = Six;
                               Suit = Clubs;}; Card {Face = Five;
                                                     Suit = Clubs;};
   Card {Face = Four;
         Suit = Clubs;}; Card {Face = Three;
                               Suit = Clubs;}; Card {Face = Two;
                                                     Suit = Clubs;};
   Card {Face = Ace;
         Suit = Diamonds;}; Card {Face = King;
                                  Suit = Diamonds;}; Card {Face = Queen;
                                                           Suit = Diamonds;};
   Card {Face = Jack;
         Suit = Diamonds;}; Card {Face = Ten;
                                  Suit = Diamonds;}; Card {Face = Nine;
                                                           Suit = Diamonds;};
   Card {Face = Eight;
         Suit = Diamonds;}; Card {Face = Seven;
                                  Suit = Diamonds;}; Card {Face = Six;
                                                           Suit = Diamonds;};
   Card {Face = Five;
         Suit = Diamonds;}; Card {Face = Four;
                                  Suit = Diamonds;}; Card {Face = Three;
                                                           Suit = Diamonds;};
   Card {Face = Two;
         Suit = Diamonds;}; Wild BigJoker; Wild LittleJoker]
Advertisements