Clojure纸牌游戏的状态

时间:2015-02-11 18:01:22

标签: clojure game-engine state

我对clojure相对较新,但掌握了主要的功能概念。我真正挣扎的是州。

我正在写一个简单的纸牌游戏应用程序,它已经到了我正在编写游戏引擎的地步。因此,国家的概念很快打动了我。

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

  • 甲板的状态
  • 分数的状态
  • 谁是经销商
  • ... ect

我已经阅读过如何在clojure,Refs,Agents,Atoms和thread local vars中使用状态。但是,对于我正在做的事情,它们似乎都不是正确的选择。

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

2 个答案:

答案 0 :(得分:7)

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

在这种情况下,这意味着为每轮比赛提供game arg,并且每轮比赛都会返回一个新的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)))))

这当然是一个非常微不足道的游戏,每个玩家的积分都来自抽出的牌。下一张牌将在每个回合中从洗牌的牌组中抽出,直到我们有一个总得分表示获胜者。

答案 1 :(得分:4)

这听起来像这个游戏的状态有几个组件,甲板,点,经销商等,所以你可以选择将所有这些放入一个地图并将其存储在一个未协调的可变数据类型中({ {1}},atomagent)或单独存储它们并使用协调的可变数据类型var。既然你说这个游戏是单线程的,那么可以稍微更容易一点就是不加协调的路线来保存几次输入单词ref,尽管它无论如何都不会在努力方面产生很大的影响。 / p>

dosync