我正在设计如何从牌组中绘制扑克牌,我想出了以下解决方案:
type Card = { Value:int }
type Deck = Card list
type Player = { Hand : Card list }
type CardDrawer(deck) =
let mutable deck = deck
member this.drawCard () =
match deck with
| h::t ->
deck <- t
h
member this.getDeck () = deck
//Example Usage
let createPlayers deck numPlayers =
let cardDrawer = new CardDrawer(deck)
let drawCard = cardDrawer.drawCard
let createPlayer drawCard =
let hand = [drawCard(); drawCard()]
{Hand=hand}
([1 .. numPlayers] |> List.map(fun _ -> createPlayer drawCard)),cardDrawer.getDeck()
这个解决方案的主要问题是我正在使用CardDrawer的可变字段来获取修改后的套牌。我觉得使用计算表达式可以在这里工作,但我不确定如何实现它。
有任何想法/建议吗?
编辑: 这是一个替代设置,但是我如何让createPlayer知道如何获取变异输出并将其转回输入?
// Create a function that draws a card
let drawCard deck ()=
match deck with
| h::t -> (h,t)
// Function given a deck and number of players, will return all the players and the deck
let createPlayers deck numPlayers =
// Function given a deck, will return the player and the new deck
let createPlayer deck =
let card, deck = drawCard deck ()
let card', deck = drawCard deck ()
{ Hand = [card; card'] }, deck
// But what would this look like now?
// How can I get the deck coming back from createPlayer
// used for the input to the next time createPlayer is called?
([1 .. numPlayers] |> List.map(fun _ -> createPlayer deck)
答案 0 :(得分:5)
您可以将其作为弃用:
// Function given a deck and number of players, will return all the players and the deck
let createPlayers deck numPlayers =
// Function given a deck, will return the player and the new deck
let createPlayer deck =
let card, deck = drawCard deck ()
let card', deck = drawCard deck ()
{ Hand = [card; card'] }, deck
let dealToNewPlayer (players, deck) _ =
let player, deck = createPlayer deck
player :: players, deck
[1..numPlayers] |> List.fold dealToNewPlayer ([], deck)
List.fold
的类型为('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
。在这种情况下,因为我们使用类型为[1..numPlayers]
的{{1}}启动折叠,所以泛型类型参数int list
为'T
。因此,您需要定义int
类型为folder
的函数。
每次调用此函数时,您都希望累积状态,这意味着您要使用先前的'State -> 'int -> 'State
值来计算deck
的新值。您还希望获取生成的deck
并添加到已生成的Player
值列表中。这意味着您需要跟踪的状态必须包含两个 Player
值列表和套牌。跟踪两者的最简单方法是通过元组 - 例如Player
。这意味着您的Player list * Card list
函数必须具有folder
类型。
上面的Player list * Card list -> int -> Player list * Card list
函数的类型为dealToNewPlayer
,因为它忽略了第二个参数。因为它是通用的,所以它也适合类型Player list * Card list -> 'a -> Player list * Card list
。
您需要Player list * Card list -> int -> Player list * Card list
的另一个参数是初始状态:List.fold
。该值是一个元组,其中第一个元素是([], deck)
值的空列表,第二个元素是完整的牌组。它符合状态类型Player
。
此特定Player list * Card list
的返回值是累计状态,即List.fold
。因此,整个Player list * Card list
类型为createPlayers
。
以下是使用此功能的FSI会话示例:
Card list -> int -> Player list * Card list
正如您所看到的,它从输入> let deck = List.init 10 (fun i -> { Value = i });;
val deck : Card list =
[{Value = 0;}; {Value = 1;}; {Value = 2;}; {Value = 3;}; {Value = 4;};
{Value = 5;}; {Value = 6;}; {Value = 7;}; {Value = 8;}; {Value = 9;}]
> createPlayers deck 3;;
val it : Player list * Card list =
([{Hand = [{Value = 4;}; {Value = 5;}];};
{Hand = [{Value = 2;}; {Value = 3;}];};
{Hand = [{Value = 0;}; {Value = 1;}];}],
[{Value = 6;}; {Value = 7;}; {Value = 8;}; {Value = 9;}])
处理到3个玩家,因此返回的第一个元素是deck
值列表,其中卡片发给每个玩家。元组的第二个元素包含剩余的套牌。