From f4d4e9b6949c71b5dcf0f7e7e629af9b891e1a3e Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Sat, 8 Jul 2023 10:21:41 +0100 Subject: [PATCH] Upgraded everything. This may be a mistake! --- .calva/output-window/output.calva-repl | 171 +++++++++++++++++++++++++ project.clj | 10 +- src/cljc/mw_engine/display.clj | 2 +- src/cljc/mw_engine/heightmap.clj | 26 ++-- src/cljc/mw_engine/natural_rules.clj | 37 +++--- src/cljc/mw_engine/utils.clj | 15 +-- 6 files changed, 204 insertions(+), 57 deletions(-) create mode 100644 .calva/output-window/output.calva-repl diff --git a/.calva/output-window/output.calva-repl b/.calva/output-window/output.calva-repl new file mode 100644 index 0000000..9fea8a2 --- /dev/null +++ b/.calva/output-window/output.calva-repl @@ -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 diff --git a/project.clj b/project.clj index edd1265..21b692e 100644 --- a/project.clj +++ b/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"]] diff --git a/src/cljc/mw_engine/display.clj b/src/cljc/mw_engine/display.clj index 1847943..d0e48a3 100644 --- a/src/cljc/mw_engine/display.clj +++ b/src/cljc/mw_engine/display.clj @@ -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] diff --git a/src/cljc/mw_engine/heightmap.clj b/src/cljc/mw_engine/heightmap.clj index 7dfe9f7..e282dcd 100644 --- a/src/cljc/mw_engine/heightmap.clj +++ b/src/cljc/mw_engine/heightmap.clj @@ -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)))) diff --git a/src/cljc/mw_engine/natural_rules.clj b/src/cljc/mw_engine/natural_rules.clj index 4c85e49..b655704 100644 --- a/src/cljc/mw_engine/natural_rules.clj +++ b/src/cljc/mw_engine/natural_rules.clj @@ -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 diff --git a/src/cljc/mw_engine/utils.clj b/src/cljc/mw_engine/utils.clj index 79dbd7a..f84abe4 100644 --- a/src/cljc/mw_engine/utils.clj +++ b/src/cljc/mw_engine/utils.clj @@ -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)}))