I'm working on a small game in Clojure as a learning exercise. I think I've settled on a representation of the game state at any particular time as a list of "movables" and a 2D vector-of-vectors for the "terrain" (board squares).
95% of the time I expect to be checking for a collision in a particular square for which the 2D vector seems appropriate. But in a few cases, I need to go the other direction -- find the (x,y) location of a cell that matches some criteria. First attempt was something like this:
(defn find-cell-row [fn row x y]
(if (empty? row) nil
(if (fn (first row)) [x y]
(find-cell-row fn (rest row) (inc x) y))))
(defn find-cell [fn grid y]
(if (empty? grid) nil
(or (find-cell-row fn (first grid) 0 y)
(find-cell (rest grid) (inc y)))))
(def sample [[\a \b \c][\d \e \f]])
(find-cell #(= % \c) sample 0) ;; => [2 0]
I tried something more concise with map-indexed, but it got ugly quickly and still didn't give me quite what I wanted. Is there a more idiomatic way to do this search, or perhaps I would be better served with a different data structure? Maybe a map { [x y] -> cell }? Using a map to represent a matrix feels so wrong to me :)
A nested vector is pretty normal for this sort of thing, and it's neither hard nor ugly to scan through one if you use a for
comprehension:
(let [h 5, w 10]
(first
(for [y (range h), x (range w)
:let [coords [y x]]
:when (f (get-in board coords))]
coords)))
How about using a plain vector then all the 'usual' functions are available to you and you can extract [x y] as necessary.
(def height 3)
(def width 3)
(def s [\a \b \c \d \e \f \g \h \i])
(defn ->xy [i]
[(mod i height) (int (/ i height))])
(defn find-cell
"returns a vector of the [x y] co-ords of cell when
pred is true"
[pred s]
(let [i (first (keep-indexed #(when (pred %2) %1) s))]
(->xy i)))
(find-cell #(= \h %) s)
;=> [1 2]
(defn update-cells
"returns an updated sequence s where value at index i
is replaced with v. Allows multiple [i v] pairs"
[s i v & ivs]
(apply assoc s i v ivs))
(update-cells s 1 \z)
;=> [\a \z \c \d \e \f \g \h \i]
(update-cells s 1 \p 3 \w)
;=> [\a \p \c \w \e \f \g \h \i]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With