有没有办法在一个或多个嵌套循环中立即从函数返回?
以下是一些说明问题的示例代码:
; 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俄罗斯方块游戏的第一个版本.随意尝试:)
未经测试:
(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?只会到达第一个非真值。
| 归档时间: |
|
| 查看次数: |
2724 次 |
| 最近记录: |