Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal a card using F#

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

type Deck = Card list

let dealACard (deck:Deck) = 
    let randomGenerator = System.Random()
    let index = randomGenerator.Next deck.Length
    let card = deck.Item index
    (card, (deck |> List.filter((<>) card)))

let createPlayer playerNumber deck =
    let card, newDeck = dealACard deck
    ({cards=[card]; playerNumber=playerNumber}, newDeck)

I've been doing well until I got to how to model how to draw a card. To test this, I wanted to draw all the cards from the deck. My program would look something like this:

let deck = createDeck
while not deck.IsEmpty do
    let card, newDeck = dealACard deck
    // print the card
    // how do I update the deck?

Any help or feedback would be great.

like image 854
Cameron Presley Avatar asked Jul 29 '15 19:07

Cameron Presley


People also ask

What do you call a hand of cards?

Each player is dealt 11 cards. This first set of 11 cards is called a 'Hand'. The 'Hand' can be picked up and examined by each player. Each player is then dealt a second set of 11 cards. This second set of dealt cards is called the 'Foot', which is played when the 'Hand' has been used up, and is kept face-down.

How do you play tens card game?

In the TEN game, players draw cards one at a time, trying to get as many cards as possible without going over 10. The goal of TEN is to build numerically sequential runs in each color group. Every player that gets a run of 1 – 9 receives points for that color.

What are book cards?

A book is any four of a kind, such as four kings, four aces, and so on.

How many cards are in a deck?

Deck of Cards Questions - There are 52 cards in a standard deck of cards - There are 4 of each card (4 Aces, 4 Kings, 4 Queens, etc.)


2 Answers

An F# list is immutable, so if deck.IsEmpty starts out false, it'll stay false forever. There's really no reason to make things so complicated, though.

Assume that you have a sorted deck. Let's use only three cards as an example, but assume that it's a full deck:

let deck =
    [
        { Suit = Hearts; Face = Queen }
        { Suit = Diamonds; Face = King }
        { Suit = Spades; Face = Ace }
    ]

You can easily scramble the deck using a random number generator:

let r = Random ()
let scrambledDeck = deck |> List.sortBy (fun _ -> r.Next ())

The first time you create scrambledDeck, it may look like this in FSI:

> let scrambledDeck = deck |> List.sortBy (fun _ -> r.Next ());;

val scrambledDeck : Card list =
  [{Suit = Spades;
    Face = Ace;}; {Suit = Hearts;
                   Face = Queen;}; {Suit = Diamonds;
                                    Face = King;}]

But if you do it again, it might look like this:

> let scrambledDeck = deck |> List.sortBy (fun _ -> r.Next ());;

val scrambledDeck : Card list =
  [{Suit = Spades;
    Face = Ace;}; {Suit = Diamonds;
                   Face = King;}; {Suit = Hearts;
                                   Face = Queen;}]

Now you have a scrambled deck, and you can simply start pulling cards off it, for example in order to print them:

scrambledDeck |> List.iter (printfn "%O")
like image 102
Mark Seemann Avatar answered Sep 19 '22 21:09

Mark Seemann


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

Addition per Comments

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
like image 40
Reid Evans Avatar answered Sep 19 '22 21:09

Reid Evans