clojure循环/递归

时间:2012-01-08 01:39:09

标签: recursion clojure

我正在尝试学习一些Clojure。我制作了一个非常基本的儿童游戏模型“滑道和梯子”。当玩家获得大于或等于100的分数时,游戏结束。 现在这仅适用于玩家。

以“(play player1)”开始游戏。

我被困在如何制作多人游戏,不得不使用重复和没有“foreach”声明。
我如何将其修改为多人游戏?

(defn roll []
 (+ 1 (rand-int 6)))

(def chutes { 10 5, 12 3, 55 38, 77 69})
(def ladders { 12 16, 10 25, 20 55, 77 91})

(defn apply_chutes [player]
 (if (contains? chutes @player)
  (do (reset! player (chutes @player))
      (println "down chute! " @player))))

(defn apply_ladders [player]
 (if (contains? ladders @player)
  (do (reset! player (ladders @player))
  (println "up ladder! " @player))))

(defn move [player]
 (do(swap! player + (roll))
  (println "p: " @player)
  (apply_chutes player)
  (apply_ladders player)
    player))
  (if 
("done")))

(defn play [player]
 (move player)
 (if (>= @player 100)
  (println "done")
  (play player)))

(def player1 (atom 0))

1 个答案:

答案 0 :(得分:3)

好的,我不会为您提供完整的代码,但更好的是关于函数式编程的高级设计,特别是Clojure中的循环/递归。

让我们从函数式编程中一个非常重要的概念开始 - immutability 。功能程序试图避免系统状态的任何变化。程序不是更改状态,而是生成新的状态。例如,如果您有向量v1 = [1, 2, 3, 4]并希望在其末尾插入5,则不会销毁v1,而是会生成v2 = [1, 2, 3, 4, 5]v1记忆不变)。有关函数式编程中不变性的更多详细信息,请参阅this问题。

有了这个,最好的方法是创建特殊变量state,它将保持游戏的整体状态。

接下来要考虑的是循环。同样,在函数式编程循环中,概念几乎被递归取代。循环和递归通常是相似的 - 它们都允许您在终止之前多次重复某些代码。在大多数命令式编程语言(例如Python,Java)中,递归导致堆栈增长,但在函数式语言中,非常流行的尾递归概念。如果您不熟悉这个概念,我强烈建议您学习它。现在我只说,尾递归只能发生在尾部位置(控制流中的最后一个语句),而不会导致堆栈增长,因此可以用作循环结构。

在Clojure中,尾递归使用recur关键字组织:

(defn play [state ...]
   ...
   (recur new-state ...))

在这里,我们使用参数play定义state函数,并在最后一行使用关键字recur递归调用它(我们也可以将其称为(play new-state ...),但是在这种情况下,JVM不会优化代码以进行尾递归)。 new-state在函数体中的某处定义,并且完全符合它的含义 - 游戏的新状态。

最后,你想让你的游戏成为多人游戏,也就是说,在每次迭代后改变当前玩家。使用循环/递归,只需通过交换玩家就可以轻松实现:

(defn play [state current-player next-player]
   ;; do play with current-player and compute new-state
   (recur new-state next-player current-player))

请注意,在重复呼叫中,玩家互换了他们的位置,因此在play的新呼叫中,下一位玩家成为当前玩家,反之亦然。

有了这个,你应该能够将你的代码翻译成新版本。