Clojure 中纸牌游戏的状态
Posted
技术标签:
【中文标题】Clojure 中纸牌游戏的状态【英文标题】:State of a card game in Clojure 【发布时间】:2015-04-12 05:29:24 【问题描述】:我对clojure 比较陌生,但掌握了主要的功能概念。我真正苦苦挣扎的是状态。
我正在编写一个简单的纸牌游戏应用程序,它已经到了我正在编写游戏引擎的地步。所以状态这个概念很快就给了我一记耳光。
我需要跟踪很多与游戏相关的事情:
甲板状态 点的状态 谁是经销商 ...等我已经阅读了如何在 clojure、Refs、Atoms、Atoms 和线程本地变量中使用状态。但它们似乎都不适合我正在做的事情。
所以我的实际问题是:我使用什么 clojure 构造来维护 clojure 中单线程游戏引擎的状态?
【问题讨论】:
【参考方案1】:函数式编程的一般原则是,您可以通过将全局状态替换为每个访问状态的函数添加的输入 arg 和输出 arg 来使代码更通用。
在这种情况下,这意味着为每一轮游戏提供一个 game
参数,并让每一轮游戏返回一个新的 game
以供后续使用。这有几个优点。没有突变,因此无需管理和协调突变。您的测试可以包括运行一轮游戏功能。如果您需要 AI,它可以在广度优先的基础上轻松运行游戏的许多分支回合,以测试可能的结果,而不会干扰实际游戏的状态。
大概的样子:
(def make-game
[players]
(let [[draw & deck] (shuffle cards)]
:draw draw
:deck deck
:points (zipmap players (repeat 0))
:dealer (first players))
(defn run-round
[game]
(let [points (update-points (:draw game) (:points game))
[draw & deck] (:deck game)]
(assoc game :deck deck :draw draw :points points)))
(defn winner?
[game]
(some #(> (val %) 42) (:points game)))
(defn -main
(let [gameplay (take-while #(not (winner? %))
(iterate run-round (make-game)))]
(:points (run-round (last gameplay)))))
这当然是一个非常微不足道的游戏,每个玩家的分数都是从抽到的牌中得出的。下一张牌将在每回合从洗好的牌组中抽出,直到我们的总分表示获胜。
【讨论】:
【参考方案2】:听起来这个游戏的状态有几个组成部分,牌组、点数、庄家等,因此您可以选择将所有这些内容放入一张地图中,并将其存储在一种不协调的可变数据类型中(@ 987654321@, agent
, var
) 或单独存储它们并使用协调可变数据类型ref
。既然你说游戏是单线程的,那么走不协调的路线可能会稍微容易一些,省去输入几次dosync
这个词,尽管这两种方式的工作量差别不大。
(def state-of-game (atom :deck ...
:points
:dealer))
【讨论】:
以上是关于Clojure 中纸牌游戏的状态的主要内容,如果未能解决你的问题,请参考以下文章
如何从 Clojure 调用 C++ 程序以使程序保持打开状态?