gpt4 book ai didi

haskell - 使用 Haskell 中纸牌游戏的数据模型避免不可能的状态

转载 作者:行者123 更新时间:2023-12-04 01:34:03 27 4
gpt4 key购买 nike

我正在尝试在 Haskell 中实现 Jass 纸牌游戏,并希望使游戏状态尽可能明确或避免使用类型来实现不可能的状态。

标准变体涉及四名玩家。相对的玩家组成一个团队。在一个游戏回合中,直到一个团队达到目标分数。在每一轮开始时,每位玩家都会拿到 9 张牌,一位玩家可以选择王牌,并领先第一把戏。在一个技巧中,每个玩家都必须打出一张牌。将牌与领头花色和王牌进行比较,牌数最高的玩家赢得一墩牌。技巧的分数将添加到获胜者团队的分数中。获胜者还领先下一招。在一个回合中,会玩一些技巧,直到每个玩家都没有剩下的牌。wikipedia上有更详细的解释以及关于 jassa.at 的德语解释.

我的播放器数据模型看起来像这样

data Player = Player
{ playerID :: PlayerID
, name :: String
, cards :: Set Card
, sendMessage :: Message -> IO ()
, receiveAction :: IO Action
}

这样我就可以为命令行或网络播放器使用不同的发送和接收函数。

  1. 我希望将游戏表示为具有纯更新功能的状态机,但是在大多数状态下,只有一个玩家的一个 Action 是有效的,所以我认为在更新功能中很大一部分只是处理无效输入。

我不知道什么是表示游戏状态的这些部分的最佳方式。

  1. 球员们。

    • 我的第一个想法是使用一个简单的列表并每次轮换这个列表,这样当前的玩家总是领先的。这很容易做到,但我也认为很容易出错,比如如果列表是空的,或者只有一个玩家等等......
    • 对玩家使用数组,对当前玩家使用索引。这样做的好处是,为了找到下一个玩家,我只需要增加索引即可。在某处我必须使用 mod 来循环数组,但这并不是真正的问题。我还尝试使用 XDataKinds 来获得类型级别的数组大小,因此 nextPlayer 函数可以处理 mod。这也有一个好处,对于球队我可以只使用偶数和奇数球员指数。 但是有了这个我必须存储一个额外的 map 从 playerID 或索引到玩家的卡片。所以现在数组和 map 可能会不同步。
  2. 技巧
    我不确定我是否应该存储一张打牌列表和谁打过它们,或者只存储一个记录,其中包含领头牌、最高牌、获胜者和打出牌的值(value),并在 writer monad 中跟踪所有打出的牌。

  3. 回合和技巧
    这对两者来说有点相同,我应该存储一个包含所有玩过的回合和技巧的列表,还是只存储当前回合和技巧并保存前几轮/技巧的点数总和

最佳答案

让类型检查器证明您的程序是完美的是一种诱惑。然而,那将成为永无止境的追求。一天中真的没有时间花时间教计算机如何确保您确定的事情对每个人来说都是肯定的。

我所做的是从一些解决问题的方法开始,然后在我解决问题的过程中了解痛点是什么。我实际上容易犯哪些错误?在你的情况下,我会以我能想到的某种方式来实现游戏(或部分),然后根据这种经验我会知道如何做得更好。

cycle::[a] -> [a] 获取一个列表并永远重复它。您可以为您的玩家做到这一点,并永远占据榜首。

对于非空列表,有 Data.List.NonEmpty

一种只构造有效游戏状态的方法是定义一个抽象数据类型。您无需导出类型的数据构造函数,而只需导出您自己定义的可以构造该类型的函数。这样,您就可以执行任何您想要的(运行时)检查或修复操作。

另一个工具是单元测试。将命题编码为类型很困难,尤其是在 Haskell 中,因此绝大多数不会。相反,您可以使用基于属性的单元测试来恢复一点保证。

关于haskell - 使用 Haskell 中纸牌游戏的数据模型避免不可能的状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60215125/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com