如何使用F#处理卡片

时间:2015-07-29 19:25:06

标签: functional-programming f#

我一直致力于使用F#对流行的纸牌游戏(情书)进行建模,以了解有关函数式编程的更多信息。

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)

我一直表现不错,直到我知道如何绘制卡片的模型。为了测试这个,我想从牌组中抽出所有牌。我的程序看起来像这样:

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

任何帮助或反馈都会很棒。

2 个答案:

答案 0 :(得分:6)

F#列表不可变,因此如果deck.IsEmpty开始false,它将永远保留false。但是,没有理由让事情变得那么复杂。

假设您有一个已排序的牌组。我们只使用三张牌作为例子,但假设它是一个完整的牌组:

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

您可以使用随机数生成器轻松地对卡座进行加扰:

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

第一次创建scrambledDeck时,它在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;}]

但如果你再次这样做,它可能会是这样的:

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

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

现在你有一个混乱的牌组,你可以简单地开始拉牌,例如为了打印它们:

scrambledDeck |> List.iter (printfn "%O")

答案 1 :(得分:1)

您可以使用List.sortBy对套牌进行随机播放,然后在dealACard方法中执行头尾模式匹配,以返回顶部卡片的Option和新套牌或{{ 1}}如果牌组中没有其他牌。

None

您还可以通过允许应用随机数生成函数使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 } 更高阶函数

shuffle

使用示例

let shuffle random deck =
    deck |> List.sortBy (fun x -> random())

根据评论添加

要以不可变的方式跟踪卡组的当前状态,您可能会有某种递归函数接受卡片

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