I'm trying to create a Tetris-like game with Clojure and I'm having some trouble deciding the data structure for the playing field. I want to define the playing field as a mutable grid. The individual blocks are also grids, but don't need to be mutable.
My first attempt was to define a grid as a vector of vectors. For example an S-block looks like this:
:s-block {
:grids [
[ [ 0 1 1 ]
[ 1 1 0 ] ]
[ [ 1 0 ]
[ 1 1 ]
[ 0 1 ] ] ]
}
But that turns out to be rather tricky for simple things like iterating and painting (see the code below).
For making the grid mutable my initial idea was to make each row a reference. But then I couldn't really figure out how to change the value of a specific cell in a row. One option would have been to create each individual cell a ref instead of each row. But that feels like an unclean approach.
I'm considering using Java arrays now. Clojure's aget and aset functions will probably turn out to be much simpler.
However before digging myself in a deeper mess I want to ask ideas/insights. How would you recommend implementing a mutable 2d grid? Feel free to share alternative approaches as well.
Source code current state: Tetris.clj (rev452)
Update
With the help of your suggestions and after some tinkering myself I came up with the following:
(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))))
I like it because it's a more generic solution. If it's totally wrong, or can be improved upon, feel free to say so.