Я пытаюсь создать игру, подобную тетрису, с Clojure, и у меня возникают проблемы с определением структуры данных для игрового поля. Я хочу определить игровое поле как изменяющуюся сетку. Отдельные блоки также являются сетками, но они не должны быть изменяемыми.
Моей первой попыткой было определить сетку как вектор векторов. Например, S-блок выглядит так:
:s-block {
:grids [
[ [ 0 1 1 ]
[ 1 1 0 ] ]
[ [ 1 0 ]
[ 1 1 ]
[ 0 1 ] ] ]
}
Но это оказывается довольно сложно для простых вещей, таких как итерация и рисование (см. Код ниже).
Чтобы сделать сетку изменчивой, моей первоначальной идеей было сделать каждую строку ссылкой. Но тогда я не мог понять, как изменить значение определенной ячейки подряд. Одним из вариантов было бы создание каждой отдельной ячейки ссылки вместо каждой строки. Но это похоже на нечистый подход.
Сейчас я рассматриваю возможность использования массивов Java. Функции aget и aset у Clojure, вероятно, окажутся намного проще.
Однако, прежде чем копаться в более глубоком беспорядке, я хочу спросить идеи / идеи. Как бы вы порекомендовали реализовать изменяемую 2d сетку? Не стесняйтесь также обмениваться альтернативными подходами.
Текущее состояние исходного кода: Tetris.clj (rev452)
Обновление
С помощью ваших предложений и после некоторой работы я придумал следующее:
(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))))
Мне это нравится, потому что это более общее решение. Если это совершенно неправильно или может быть улучшено, не стесняйтесь так говорить.