How to deal a card using F#

前端 未结 2 915
無奈伤痛
無奈伤痛 2021-01-18 23:04

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         


        
相关标签:
2条回答
  • 2021-01-18 23:57

    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
    
    0 讨论(0)
  • 2021-01-19 00:02

    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")
    
    0 讨论(0)
提交回复
热议问题