Clojure纸牌游戏的状态

Clojure纸牌游戏的状态,clojure,game-engine,state,Clojure,Game Engine,State,我对clojure比较陌生,但对主要的功能概念有一定的了解。我真正挣扎的是状态 我正在编写一个简单的纸牌游戏应用程序,它已经到了我编写游戏引擎的地步。所以国家的概念很快就给了我一记耳光 我需要跟踪很多与游戏相关的事情: 甲板的状态 点的状态 谁是商人 。。。ect 我已经阅读了clojure、REF、代理、原子和线程局部变量中如何使用状态。但对于我所做的事情来说,没有一个是正确的选择 所以我的实际问题是:我使用什么clojure构造来维护clojure中单线程游戏引擎的状态 听起来这个游戏的

我对clojure比较陌生,但对主要的功能概念有一定的了解。我真正挣扎的是状态

我正在编写一个简单的纸牌游戏应用程序,它已经到了我编写游戏引擎的地步。所以国家的概念很快就给了我一记耳光

我需要跟踪很多与游戏相关的事情:

  • 甲板的状态
  • 点的状态
  • 谁是商人
  • 。。。ect
我已经阅读了clojure、REF、代理、原子和线程局部变量中如何使用状态。但对于我所做的事情来说,没有一个是正确的选择


所以我的实际问题是:我使用什么clojure构造来维护clojure中单线程游戏引擎的状态

听起来这个游戏的状态有几个组成部分,牌组、点数、庄家等等。所以你可以选择将所有这些放在一张地图中,并将其存储在一个不协调的可变数据类型(
atom
agent
var
)中,或者单独存储它们并使用协调的可变数据类型,
ref
。既然你说游戏是单线程的,那么通过不协调的方式来避免多次键入单词
dosync
可能会稍微容易一些,尽管这两种方式的效果都不会有太大的差别

(def state-of-game (atom {:deck ...
                          :points
                          :dealer}))   

函数式编程的一般原则是,通过为每个函数访问状态添加输入arg和输出arg来替换全局状态,可以使代码更加通用

在这种情况下,这意味着为每一轮游戏提供一个
游戏
arg,并让每一轮游戏返回一个新的
游戏
,以便继续使用。这有一些好处。没有突变,因此不需要管理和协调突变。您的测试可以包括运行一轮播放功能。如果您需要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)))))
这当然是一个非常简单的游戏,每个玩家的点数都是从抽到的牌中得到的。下一张牌将在每一回合从洗牌牌组中抽取,直到我们有一个总分数表示胜利者