我一直致力于使用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?
任何帮助或反馈都会很棒。
答案 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