I'm trying to implement the Game of Life in Clojure. I managed to implement the main logic, but now I'd like to provide a couple of functions that add an object (e.g. a Glider) to the grid.
Here are some functions that work fine so far:
(ns glider.core
(:gen-class))
(defn new-grid
"Creates a 2d grid with rows*cols."
[rows cols]
(partition cols (take (* rows cols) (repeat false))))
(defn get-coordinates
"Returns the row/col coordinates of each 2d grid field."
[grid]
(let [rows (count grid)
cols (count (get grid 0))]
(partition cols (for [r (range rows) c (range cols)] [r c]))))
(defn set-at
"Sets the field at row/col to state."
[grid row col state]
(assoc grid row (assoc (get grid row) col state)))
new-gridcreates a grid.get-coordinatesturns the grid withtrue/falsestates into a grid of row/col coordinates.set-atsets a new state to the grid at row/col.
Now I'd like to add a glider. Here's my approach:
(defn add-glider
"Adds a glider pattern to the lower-right quadrant of the grid."
[grid]
(let [rows (count grid)
cols (count (get grid 0))
row-offset (/ rows 2)
col-offset (/ cols 2)
glider [[false true false]
[false false true]
[true true true]]
glider-coords (get-coordinates glider)
grid-coords (map (fn [[r c]] [(+ r row-offset) (+ c col-offset)]) glider-coords)]
(apply (fn [[r c]] (set-at grid r c true)) grid-coords)))
First, I compute rows/cols, and also the mid-point of the grid (row-offset/col-offset). Second, I build up a glider in a 3x3 field with true/false states. I turn the glider into coordinates (glider-coords), which I then move by the offset (grid-coords).
Now I have a sequence of coordinates. I'd like to set the grid state to true on all these points.
I wrote this program to test it:
(defn -main
"Creates a grid and adds a glider to it."
[& args]
(let [grid (new-grid 8 8)
grid-with-glider (add-glider grid)]
(println grid)
(println grid-with-glider)))
Which gives me the following error message when I run it using lein:
$ lein repl
glider.core=> (-main)
Execution error (ClassCastException) at glider.core/add-glider$fn (core.clj:32).
class clojure.lang.PersistentVector cannot be cast to class java.lang.Number (clojure.lang.PersistentVector is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')
Line 32 refers to the following code:
grid-coords (map (fn [[r c]] [(+ r row-offset) (+ c col-offset)]) glider-coords)
My questions:
- What does that error message mean?
- Is my approach using
applysensible, or how should one tackle such an issue?