Gibt es eine Möglichkeit, in einer oder mehreren verschachtelten Schleifen sofort von einer Funktion zurückzukehren?Rückkehr von einer Funktion innerhalb einer oder mehrerer verschachtelter Schleifen?
Hier ist ein Beispielcode veranschaulicht das Problem:
; 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))
Vielleicht das Problem zu viel in einer imperativen Art, wie ich bin näher.
aktualisieren
Ok, ich fand eine Lösung:
; 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))
Es verwendet eine veränderbare Referenz als Stop-Flag, die funktionelle Art der Programmierung zu brechen. Aber ich bin glücklich, eine Lösung zu haben. Fühlen Sie sich frei, einen besseren Weg zu teilen.
aktualisieren
Für Interessenten, ich habe eine erste Version Version meines Clojure Tetris Spiel beendet. Fühlen Sie sich frei, es zu versuchen :)
Mit verschachtelten Schleifen meinen Sie eine rekursive Struktur (entweder tatsächliche Rekursion oder eine Schleife-wiederkehrende Struktur)? Oder meinst du einen Sequenzprozessor wie "für"? – Greg
@Greg Harman: Ich habe meinen Beitrag mit einem Codebeispiel aktualisiert. – StackedCrooked
Nur ein Tipp: Sie sollten Abstraktionen in diesen Code einfügen (d. H. Teile mit fns und Makros trennen, falls zutreffend), wenn es hier keinen Leistungsengpass gibt. Der Code, wie er aussieht, sieht ziemlich komplex aus und ist daher schwieriger zu warten. – jjpe