【问题标题】:State of a card game in ClojureClojure 中纸牌游戏的状态
【发布时间】:2015-04-12 05:29:24
【问题描述】:

我对clojure 比较陌生,但掌握了主要的功能概念。我真正苦苦挣扎的是状态。

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

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

  • 甲板状态
  • 点的状态
  • 谁是经销商
  • ...等

我已经阅读了如何在 clojure、Refs、Atoms、Atoms 和线程本地变量中使用状态。但它们似乎都不适合我正在做的事情。

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

【问题讨论】:

    标签: clojure game-engine state


    【解决方案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}))   
      

      【讨论】:

        猜你喜欢
        • 2013-12-08
        • 1970-01-01
        • 1970-01-01
        • 2017-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-17
        相关资源
        最近更新 更多