FCards - Defining Cards

09. Shuffling

Shuffling the deck

So far we have been using a deck that is always in the same predictable order. It’s time we mixed things up a bit and shuffled the cards.

Recursive functions

A recursive function is a special kind of function that can call itself. This is useful for when we want to dive down into a collection of items and get to an end of some sort and bubble back up to the beginning.

In F# we need to mark a function as being recursive with the rec keyword, to help the compiler with its optimisation.

For example we can add up numbers in a list we can add the first in the list to whatever the sum of the rest of the list is, which we can get by calling the same function on the rest of the list…

let rec addAll (numbers: int list) =
  match numbers with 
  | [] -> 0
  | [a] -> a
  | a::rest -> a + (addAll rest)

addAll [1; 2; 3; 4; 5; 6; 7; 8; 9]  // returns 45

Exercise: Shuffle a deck

Write a function that shuffles a list of cards by taking a random card from the list and joining that to a list of random cards from the rest of the list.

TIP: To get a random number you create a randomiser using let rrr = System.Random()
Then call it as let randomValue = rrr.Next(20) to get a random number from 0 to 19.

See an answer

let rec shuffle deck = 
  let random = System.Random()
  match deck with 
  | [] -> []
  | [a] -> [a]
  | _ -> // NOTE: `_` means "some value, but I don't care what it is"
      let randomPosition = random.Next(deck.Length)
      let cardAtPosition = deck[randomPosition]
      let rest = deck |> List.removeAt randomPosition
      [cardAtPosition] @ (shuffle rest)

Putting it together

So now we can create a new game with a shuffled deck and pickup some cards!

{
  deck = newDeck |> shuffle
  hand = []
}
|> pickupCard
|> pickupCard
|> pickupCard
|> pickupCard
|> pickupCard

// Result:
Game {
  deck: Card list ( x 47 )
  hand: Card list ( x 5 )
}

Code so far

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

type Card = 
  | Hearts of CardNumber
  | Diamonds of CardNumber
  | Clubs of CardNumber
  | Spades of CardNumber
  | Joker

let newDeck = 
  let suits = [Hearts; Diamonds; Clubs; Spades]
  let numbers = [
    Two; Three; Four; Five; Six; Seven; Eight; Nine; Ten;
    Jack; Queen; King; Ace
  ]
  List.allPairs suits numbers
  |> List.map (fun (suit, number) -> suit number)

type Game = {
  deck: Card list
  hand: Card list
}

let pickupCard (game: Game) =
  match game.deck with 
  | [] -> failwith "No cards left!!!"
  | [a] -> { hand = game.hand @ [a]; deck = [] }
  | a::rest -> { hand = game.hand @ [a]; deck = rest }

let rec shuffle deck = 
  let random = System.Random()
  match deck with 
  | [] -> []
  | [a] -> [a]
  | _ -> // NOTE: `_` means "some value, but I don't care what it is"
      let randomPosition = random.Next(deck.Length)
      let cardAtPosition = deck[randomPosition]
      let rest = deck |> List.removeAt randomPosition
      [cardAtPosition] @ (shuffle rest)


;;
// DO IT!
{ 
  deck = newDeck |> shuffle;
  hand = [] 
}
|> pickupCard
|> pickupCard
|> pickupCard
|> pickupCard
|> pickupCard