I\'ve been working on modeling a popular card game (Love Letter) using F# to learn more about functional programming.
module Game =
open Cards
open Players
You could shuffle the deck with a List.sortBy and then perform a head tail pattern match in the dealACard method to return an Option of the top card and the new deck or None if there are no more cards in the deck.
type DealResult = {
Card : Card
Deck : Deck
}
let shuffle deck =
let random = new System.Random()
deck |> List.sortBy (fun x -> random.Next())
let dealACard deck =
match deck with
| [] -> None
| card::restOfDeck -> Some { Card = card; Deck = restOfDeck }
You could also make shuffle a higher order function by allowing a random number generating function to be applied
let shuffle random deck =
deck |> List.sortBy (fun x -> random())
Example Usage
let deck = [{Rank = 1}; {Rank = 2}] |> shuffle
//val deck : Card list = [{Rank = 2;}; {Rank = 1;}]
let draw1 = deck |> dealACard
//val draw1 : DealResult option = Some {Card = {Rank = 2;};
// Deck = [{Rank = 1;}];}
let draw2 = match draw1 with
| Some d -> d.Deck |> dealACard
| None -> None
//val draw2 : DealResult option = Some {Card = {Rank = 1;};
// Deck = [];}
let draw3 = match draw2 with
| Some d -> d.Deck |> dealACard
| None -> None
//val draw3 : DealResult option = None
To keep track of the current state of the deck in an immutable way you would probably have some sort of recursive function that accepts a deck
type DealResult = {
Card : Card option
Deck : Deck
}
let dealACard deck =
match deck with
| [] -> { Card = None; Deck = deck }
| card::restOfDeck -> { Card = Some card; Deck = restOfDeck }
let rec dealAllCards deck =
let result = deck |> dealACard
match result.Card with
| None -> printfn "Cards out"
| Some c ->
printfn "%A" c
result.Deck |> dealAllCards
let deck = [(Two, Hearts); (Three, Hearts); (Four, Hearts)] |> shuffle
dealAllCards deck
//(Three, Hearts)
//(Four, Hearts)
//(Two, Hearts)
//Cards out