在一个或多个嵌套循环内部从函数返回?

Sta*_*ked 5 clojure

有没有办法在一个或多个嵌套循环中立即从函数返回?

以下是一些说明问题的示例代码:

; Grid data structure
; -------------------
(defstruct grid :width :height)

(defn create-grid [w h initial-value]
  (struct-map grid
    :width  w
    :height h
    :data   (ref (vec (repeat (* w h) initial-value)))))

(defn create-grid-with-data [w h gdata]
  (struct-map grid
    :width w
    :height h
    :data (ref gdata)))

(defn get-grid [g x y]
  (let [gdata (g :data)
        idx   (+ x (* (g :width) y)) ]
    (gdata idx)))

(defn set-grid [g x y value]
  (let [data  (deref (g :data))
        idx   (+ x (* (g :width) y)) ]
    (dosync (alter (g :data) (fn [_] (assoc data idx value))))))

(defn get-grid-rows [g]
  (partition (g :width) (deref (g :data))))



; Beginning of test app
; ---------------------

; The Tetris playing field  
(def current-field (create-grid 20 10 0))


; A tetris block (the L-Shape)
(def current-block {
  :grid (struct-map grid :width 3 :height 3 :data [ 0 1 0
                                                    0 1 0
                                                    0 1 1 ])

  ; upper-left corner of the block position in the playing field
  :x (ref 0) 
  :y (ref 0)
} )


; check-position-valid checks if the current position
; of a block is a valid position in a playing field
(defn check-position-valid [field block]
  (dotimes [ x ((block :grid) :width) ]
    (dotimes [ y ((block :grid) :height) ]
      (if
        (let [ g           (block :grid)
               block-value (get-grid g x y)
               field-x     (+ x (deref (block :x)))
               field-y     (+ y (deref (block :y))) ]
          (if (not (zero? block-value))
            (if-not
              (and (>= field-x 0)
                   (< field-x (field :width))
                   (< field-y (field :height))
                   (zero? (get-grid field field-x field-y)))
              false ; invalid position, function should now return false
              true ; ok, continue loop
              )))
        true
        false))))

(println (check-position-valid current-field current-block))
Run Code Online (Sandbox Code Playgroud)

也许我正在以一种必要的方式解决这个问题.

更新
好了,我找到了一个解决方案:

; check-position-valid checks if the current position
; of a block is a valid position in a playing field
(defn check-position-valid [field block]
  (let [stop-condition (ref false)]
    (loop [ x 0 ]
      (when (and (not (deref stop-condition))
                 (< x ((block :grid) :width)))
        (println "x" x)
        (loop [ y 0 ]
          (when (and (not (deref stop-condition))
                     (< y ((block :grid) :height)))
            (println "y" y)
            (let [ g           (block :grid)
                   block-value (get-grid g x y)
                   field-x     (+ x (deref (block :x)))
                   field-y     (+ y (deref (block :y))) ]
              (if (not (zero? block-value))
                (if-not
                  (and (>= field-x 0)
                       (< field-x (field :width))
                       (< field-y (field :height))
                       (zero? (get-grid field field-x field-y)))
                  (do
                    (println "stop is true")
                    (dosync (alter stop-condition (fn [_] true)))))))
            (recur (inc y))))
        (recur (inc x))))
    (not (deref stop-condition))))

(println (check-position-valid current-field current-block))
Run Code Online (Sandbox Code Playgroud)

它使用可变引用作为停止标志,打破了编程的功能风格.但我很高兴有一个解决方案.随意分享更好的方式.

更新
对于那些感兴趣的人,我已经完成了我的Clojure俄罗斯方块游戏的第一个版本.随意尝试:)

Bri*_*per 4

未经测试:

(defn position-valid? [field block]
  (let [g (block :grid)]
    (every? true? (for [x (range 0 (inc (g :width)))
                        y (range 0 (inc (g :height)))
                        :let [block-value (get-grid g x y)
                              field-x     (+ x @(block :x))
                              field-y     (+ y @(block :y))]]
                    (and (not (zero? block-value))
                         (>= field-x 0)
                         (< field-x (field :width))
                         (< field-y (field :height))
                         (zero? (get-grid field field-x field-y)))))))
Run Code Online (Sandbox Code Playgroud)

for是惰性的,所以every?只会到达第一个非真值。