如何在clojure中实现具有嵌套返回的循环?

时间:2013-05-16 23:37:16

标签: clojure clojurescript

我在这里玩一个狡猾的教程:

http://buildnewgames.com/introduction-to-crafty/

我想知道如何在clojurescript / clojure中实现这个特定的功能

 var max_villages = 5;
 for (var x = 0; x < Game.map_grid.width; x++) {
   for (var y = 0; y < Game.map_grid.height; y++) {
     if (Math.random() < 0.02) {
       Crafty.e('Village').at(x, y);

       if (Crafty('Village').length >= max_villages) {
        return;
       }
    }
  }
}

我知道我们可以拥有(for [])构造但是当max_villages达到5时你会如何让它停止?

3 个答案:

答案 0 :(得分:5)

这是一种方法:

(def max-villages 5)

(->> (for [x (range map-width)
           y (range map-height)]
       [x y])
     (filter (fn [_] (< (rand) 0.02)))
     (take max-villages))

然后可能添加(map make-village-at)或类似管道的下一个阶段;如果要执行副作用,请添加dorundoall作为最后阶段,以强制它们立即发生(根据返回值是否有趣来选择一个或另一个)。

NB。由于seq分块可能会生成一些额外的向量和随机数,但它会小于32。

使用计数器进行比较的更为迫切的方法:

(let [counter (atom 0)]
  (doseq [x (range map-width)
          :while (< @counter max-villages)
          y (range map-height)
          :while (< @counter max-villages)
          :when (< (rand) 0.02)]
    (swap! counter inc)
    (prn [x y]))) ; call make-village-at here

:while在其测试表达式失败时终止当前嵌套级别的循环; :when立即进入下一次迭代。 doseq也支持分块,但:while会阻止它执行不必要的工作。

答案 1 :(得分:2)

使用递归就像是:

(letfn [(op [x y]
          (if (= (rand) 0.02)
            (do
              (village-at x y)
              (if (>= (village-length) max-villages) true))))]
  (loop [x 0 y 0]
    (when (and (< x width) (not (op x y)))
      (if (= (inc y) height)
        (recur (inc x) 0)
        (recur x (inc y))))))

答案 2 :(得分:0)

这是一个很棒的教程!

迈克尔方法的一个变种(我刚刚回答他的答案,但我还没有足够的叠加能力)将是使用笛卡尔积而不是嵌套for循环:

;; some stub stuff to get the example to run
(ns example.core
  (:use clojure.math.combinatorics))

(def max-villages 5)
(def map-width 10)
(def map-height 10)
(defn crafty-e [x y z] (print z))

;; the example, note I use doseq rather than map to empasize the fact that the loop 
;; is being performed for its side effects not its return value.
(doseq [coord (take max-villages 
                (filter 
                 (fn [_] (< (rand)  0.02))
                 (cartesian-product (range map-width) (range map-height))))]
(crafty-e :village :at coord))