Upgraded everything. This may be a mistake!
This commit is contained in:
parent
67a43279f6
commit
f4d4e9b694
171
.calva/output-window/output.calva-repl
Normal file
171
.calva/output-window/output.calva-repl
Normal file
|
@ -0,0 +1,171 @@
|
|||
; This is the Calva evaluation results output window.
|
||||
; TIPS: The keyboard shortcut `ctrl+alt+o o` shows and focuses this window
|
||||
; when connected to a REPL session.
|
||||
; Please see https://calva.io/output/ for more info.
|
||||
; Happy coding! ♥️
|
||||
|
||||
; Connecting ...
|
||||
; Reading port file: file:///Users/simon/workspace/MicroWorld/mw-engine/.nrepl-port ...
|
||||
; Using host:port localhost:58100 ...
|
||||
; Hooking up nREPL sessions ...
|
||||
; Connected session: clj
|
||||
; TIPS:
|
||||
; - You can edit the contents here. Use it as a REPL if you like.
|
||||
; - `alt+enter` evaluates the current top level form.
|
||||
; - `ctrl+enter` evaluates the current form.
|
||||
; - `alt+up` and `alt+down` traverse up and down the REPL command history
|
||||
; when the cursor is after the last contents at the prompt
|
||||
; - Clojure lines in stack traces are peekable and clickable.
|
||||
; Evaluating code from settings: 'calva.autoEvaluateCode.onConnect.clj'
|
||||
nil
|
||||
clj꞉user꞉> ; Use `alt+enter` to evaluate
|
||||
clj꞉user꞉>
|
||||
nil
|
||||
; WARNING: abs already refers to: #'clojure.core/abs in namespace: mw-engine.utils, being replaced by: #'mw-engine.utils/abs
|
||||
clj꞉mw-engine.core꞉>
|
||||
nil
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.core/apply-rule
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.core/apply-rules
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.core/transform-cell
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.core/transform-world
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.core/run-world
|
||||
clj꞉mw-engine.core꞉>
|
||||
#'mw-engine.display/*image-base*
|
||||
clj꞉mw-engine.display꞉>
|
||||
; Syntax error compiling at (src/cljc/mw_engine/display.clj:32:1).
|
||||
; Unable to resolve symbol: defn in this context
|
||||
clj꞉mw-engine.display꞉>
|
||||
; Syntax error compiling at (src/cljc/mw_engine/display.clj:32:1).
|
||||
; Unable to resolve symbol: defn in this context
|
||||
clj꞉mw-engine.display꞉>
|
||||
nil
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/*image-base*
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/format-css-class
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/format-image-path
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/format-mouseover
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/render-cell
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/render-world-row
|
||||
clj꞉mw-engine.display꞉>
|
||||
#'mw-engine.display/render-world-table
|
||||
clj꞉mw-engine.display꞉>
|
||||
nil
|
||||
; WARNING: abs already refers to: #'clojure.core/abs in namespace: mw-engine.heightmap, being replaced by: #'mw-engine.utils/abs
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/*sealevel*
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/rainfall
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/rain-row
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/rain-world
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow-contributors
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/is-hollow
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flood-hollow
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flood-hollows
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/max-altitude
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow-nr
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow-world-nr
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/flow-world
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/explore-lake
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/is-lake?
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/find-lakes
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/run-drainage
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
#'mw-engine.drainage/run-drainage
|
||||
clj꞉mw-engine.drainage꞉>
|
||||
nil
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
#'mw-engine.heightmap/tag-property
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
#'mw-engine.heightmap/tag-gradient
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
#'mw-engine.heightmap/tag-gradients
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
#'mw-engine.heightmap/tag-altitude
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
#'mw-engine.heightmap/apply-heightmap
|
||||
clj꞉mw-engine.heightmap꞉>
|
||||
nil
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/member?
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-int-or-zero
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/in-bounds
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/in-bounds?
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/map-world-n-n
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/map-world-p-p
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/map-world
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-cell
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-int
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/population
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/memo-get-neighbours
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-neighbours
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-neighbours-with-property-value
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-neighbours-with-state
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/get-least-cell
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/set-cell-property
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/set-property
|
||||
clj꞉mw-engine.utils꞉>
|
||||
#'mw-engine.utils/merge-cell
|
||||
clj꞉mw-engine.utils꞉>
|
||||
nil
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/make-cell
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/make-world-row
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/make-world-rows
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/make-world
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/truncate-state
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/format-cell
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/format-world-row
|
||||
clj꞉mw-engine.world꞉>
|
||||
#'mw-engine.world/print-world
|
||||
clj꞉mw-engine.world꞉>
|
||||
; nREPL Connection was closed
|
10
project.clj
10
project.clj
|
@ -1,10 +1,10 @@
|
|||
(defproject mw-engine "0.1.6-SNAPSHOT"
|
||||
:dependencies [[org.clojure/clojure "1.10.3"]
|
||||
[org.clojure/clojurescript "1.10.896" :scope "provided"]
|
||||
[org.clojure/math.combinatorics "0.1.6"]
|
||||
:dependencies [[org.clojure/clojure "1.11.1"]
|
||||
[org.clojure/clojurescript "1.11.60" :scope "provided"]
|
||||
[org.clojure/math.combinatorics "0.2.0"]
|
||||
[org.clojure/tools.trace "0.7.11"]
|
||||
[org.clojure/tools.namespace "1.1.1"]
|
||||
[com.taoensso/timbre "5.1.2"]
|
||||
[org.clojure/tools.namespace "1.4.4"]
|
||||
[com.taoensso/timbre "6.2.1"]
|
||||
[fivetonine/collage "0.3.0"]
|
||||
[hiccup "1.0.5"]
|
||||
[net.mikera/imagez "0.12.0"]]
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
"Base url (i.e., url of directory) from which to load tile images."
|
||||
"img/tiles")
|
||||
|
||||
(defn format-css-class
|
||||
(defn format-css-class
|
||||
"Format this `state`, assumed to be a keyword indicating a state in the
|
||||
world, into a CSS class"
|
||||
[state]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
(ns ^{:doc "Functions to apply a heightmap to a world."
|
||||
:author "Simon Brooke"}
|
||||
mw-engine.heightmap
|
||||
(:require [mikera.image.core :refer [load-image filter-image get-pixels]]
|
||||
(:require [mikera.image.core :refer [load-image filter-image]]
|
||||
[mikera.image.filters :as filters]
|
||||
[mw-engine.utils :refer [abs get-int get-neighbours map-world]]
|
||||
[mw-engine.utils :refer [get-int get-neighbours map-world]]
|
||||
[mw-engine.world :refer [make-world]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -34,7 +34,6 @@
|
|||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
(defn tag-property
|
||||
"Set the value of this `property` of this cell from the corresponding pixel of this `heightmap`.
|
||||
If the heightmap you supply is smaller than the world, this will break.
|
||||
|
@ -45,7 +44,7 @@
|
|||
* `property` the property (normally a keyword) whose value will be set on the cell.
|
||||
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
||||
exceed those of the world of which the `cell` forms part."
|
||||
([world cell property heightmap]
|
||||
([_ cell property heightmap]
|
||||
(tag-property cell property heightmap))
|
||||
([cell property heightmap]
|
||||
(merge cell
|
||||
|
@ -58,7 +57,6 @@
|
|||
(get-int cell :x)
|
||||
(get-int cell :y)) 256))))})))
|
||||
|
||||
|
||||
(defn tag-gradient
|
||||
"Set the `gradient` property of this `cell` of this `world` to the difference in
|
||||
altitude between its highest and lowest neghbours."
|
||||
|
@ -71,14 +69,12 @@
|
|||
gradient (- highest lowest)]
|
||||
(merge cell {:gradient gradient})))
|
||||
|
||||
|
||||
(defn tag-gradients
|
||||
"Set the `gradient` property of each cell in this `world` to the difference in
|
||||
altitude between its highest and lowest neghbours."
|
||||
[world]
|
||||
(map-world world tag-gradient))
|
||||
|
||||
|
||||
(defn tag-altitude
|
||||
"Set the altitude of this cell from the corresponding pixel of this heightmap.
|
||||
If the heightmap you supply is smaller than the world, this will break.
|
||||
|
@ -88,12 +84,11 @@
|
|||
* `cell` a cell, as discussed in world.clj, q.v. Alternatively, a map;
|
||||
* `heightmap` an (ideally) greyscale image, whose x and y dimensions should
|
||||
exceed those of the world of which the `cell` forms part."
|
||||
([world cell heightmap]
|
||||
([_ cell heightmap]
|
||||
(tag-property cell :altitude heightmap))
|
||||
([cell heightmap]
|
||||
(tag-property cell :altitude heightmap)))
|
||||
|
||||
|
||||
(defn apply-heightmap
|
||||
"Apply the image file loaded from this path to this world, and return a world whose
|
||||
altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that
|
||||
|
@ -105,21 +100,20 @@
|
|||
* `imagepath` a file path or URL which indicates an (ideally greyscale) image file."
|
||||
([world imagepath]
|
||||
(let [heightmap (filter-image
|
||||
(filters/grayscale)
|
||||
(load-image imagepath))]
|
||||
(load-image imagepath)
|
||||
(filters/grayscale))]
|
||||
(map-world
|
||||
(map-world world tag-altitude (list heightmap))
|
||||
tag-gradient)))
|
||||
([imagepath]
|
||||
(let [heightmap (filter-image
|
||||
(filters/grayscale)
|
||||
(load-image imagepath))
|
||||
(load-image imagepath)
|
||||
(filters/grayscale))
|
||||
world (make-world (.getWidth heightmap) (.getHeight heightmap))]
|
||||
(map-world
|
||||
(map-world world tag-altitude (list heightmap))
|
||||
tag-gradient))))
|
||||
|
||||
|
||||
(defn apply-valuemap
|
||||
"Generalised from apply-heightmap, set an arbitrary property on each cell
|
||||
of this `world` from the values in this (ideally greyscale) heightmap.
|
||||
|
@ -130,6 +124,6 @@
|
|||
intensity of the corresponding cell of the image."
|
||||
[world imagepath property]
|
||||
(let [heightmap (filter-image
|
||||
(filters/grayscale)
|
||||
(load-image imagepath))]
|
||||
(load-image imagepath)
|
||||
(filters/grayscale))]
|
||||
(map-world world tag-property (list property heightmap))))
|
||||
|
|
|
@ -33,46 +33,41 @@
|
|||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;; treeline at arbitrary altitude.
|
||||
(def treeline 150)
|
||||
|
||||
|
||||
;; waterline also at arbitrary altitude.
|
||||
(def waterline 10)
|
||||
|
||||
|
||||
;; and finally snowline is also arbitrary.
|
||||
(def snowline 200)
|
||||
|
||||
|
||||
;; Rare chance of lightning strikes
|
||||
(def lightning-probability 500)
|
||||
|
||||
|
||||
;; rules describing vegetation
|
||||
(def vegetation-rules
|
||||
(list
|
||||
;; Randomly, birds plant tree seeds into grassland.
|
||||
(fn [cell world] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
|
||||
(fn [cell _] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
|
||||
;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (and
|
||||
(= (:state cell) :heath)
|
||||
;; browsing limit really ought to vary with soil fertility, but...
|
||||
(< (+ (get-int cell :deer)(get-int cell :sheep)) 6)
|
||||
(< (get-int cell :altitude) treeline))
|
||||
(merge cell {:state :scrub})))
|
||||
(fn [cell world] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
|
||||
(fn [cell _] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
|
||||
;; Forest on fertile land grows to climax
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond
|
||||
(and
|
||||
(= (:state cell) :forest)
|
||||
(> (get-int cell :fertility) 10))
|
||||
(merge cell {:state :climax})))
|
||||
;; Climax forest occasionally catches fire (e.g. lightning strikes)
|
||||
(fn [cell world] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
|
||||
(fn [cell _] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
|
||||
;; Climax forest neighbouring fires is likely to catch fire
|
||||
(fn [cell world]
|
||||
(cond
|
||||
|
@ -81,7 +76,7 @@
|
|||
(not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire))))
|
||||
(merge cell {:state :fire})))
|
||||
;; After fire we get waste
|
||||
(fn [cell world] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
|
||||
(fn [cell _] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
|
||||
;; And after waste we get pioneer species; if there's a woodland seed
|
||||
;; source, it's going to be heath, otherwise grassland.
|
||||
(fn [cell world]
|
||||
|
@ -95,11 +90,11 @@
|
|||
(get-neighbours-with-state world (:x cell) (:y cell) 1 :forest)
|
||||
(get-neighbours-with-state world (:x cell) (:y cell) 1 :climax))))))
|
||||
(merge cell {:state :heath})))
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (= (:state cell) :waste)
|
||||
(merge cell {:state :grassland})))
|
||||
;; Forest increases soil fertility
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (member? (:state cell) '(:forest :climax))
|
||||
(merge cell {:fertility (+ (get-int cell :fertility) 1)})))))
|
||||
|
||||
|
@ -109,7 +104,7 @@
|
|||
(list
|
||||
;; if there are too many deer for the fertility of the area to sustain,
|
||||
;; some die or move on.
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (> (get-int cell :deer) (get-int cell :fertility))
|
||||
(merge cell {:deer (get-int cell :fertility)})))
|
||||
;; deer arrive occasionally at the edge of the map.
|
||||
|
@ -128,7 +123,7 @@
|
|||
(>= n 2))
|
||||
(merge cell {:deer (int (/ n 2))}))))
|
||||
;; deer breed.
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond
|
||||
(>= (get-int cell :deer) 2)
|
||||
(merge cell {:deer (int (* (:deer cell) 2))})))))
|
||||
|
@ -137,7 +132,7 @@
|
|||
(def predator-rules
|
||||
(list
|
||||
;; wolves eat deer
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond
|
||||
(>= (get-int cell :wolves) 1)
|
||||
(merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
|
||||
|
@ -146,7 +141,7 @@
|
|||
;; (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8})))
|
||||
;; if there are not enough deer to sustain the get-int of wolves,
|
||||
;; some wolves die or move on. (doesn't seem to be working?)
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (> (get-int cell :wolves) (get-int cell :deer))
|
||||
(merge cell {:wolves 0})))
|
||||
;; wolves arrive occasionally at the edge of the map.
|
||||
|
@ -165,7 +160,7 @@
|
|||
(>= n 2))
|
||||
(merge cell {:wolves 2}))))
|
||||
;; wolves breed.
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond
|
||||
(>= (get-int cell :wolves) 2)
|
||||
(merge cell {:wolves (int (* (:wolves cell) 2))})))))
|
||||
|
@ -175,13 +170,13 @@
|
|||
(def init-rules
|
||||
(list
|
||||
;; below the waterline, we have water.
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
|
||||
;; above the snowline, we have snow.
|
||||
(fn [cell world]
|
||||
(fn [cell _]
|
||||
(cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow})))
|
||||
;; in between, we have a wasteland.
|
||||
(fn [cell world] (cond (= (:state cell) :new) (merge cell {:state :grassland})))))
|
||||
(fn [cell _] (cond (= (:state cell) :new) (merge cell {:state :grassland})))))
|
||||
|
||||
|
||||
(def natural-rules (flatten
|
||||
|
|
|
@ -28,22 +28,10 @@
|
|||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn abs
|
||||
"Surprisingly, Clojure doesn't seem to have an abs function, or else I've
|
||||
missed it. So here's one of my own. Maps natural numbers onto themselves,
|
||||
and negative integers onto natural numbers. Also maps negative real numbers
|
||||
onto positive real numbers.
|
||||
|
||||
* `n` a number, on the set of real numbers."
|
||||
[n]
|
||||
(if (neg? n) (- 0 n) n))
|
||||
|
||||
|
||||
(defn member?
|
||||
"True if elt is a member of col."
|
||||
[elt col] (some #(= elt %) col))
|
||||
|
||||
|
||||
(defn get-int-or-zero
|
||||
"Return the value of this `property` from this `map` if it is a integer;
|
||||
otherwise return zero."
|
||||
|
@ -51,13 +39,12 @@
|
|||
(let [value (map property)]
|
||||
(if (integer? value) value 0)))
|
||||
|
||||
|
||||
(defn init-generation
|
||||
"Return a cell like this `cell`, but having a value for :generation, zero if
|
||||
the cell passed had no integer value for generation, otherwise the value
|
||||
taken from the cell passed. The `world` argument is present only for
|
||||
consistency with the rule engine and is ignored."
|
||||
[world cell]
|
||||
[_ cell]
|
||||
(merge cell {:generation (get-int-or-zero cell :generation)}))
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue