Functions to transform a world and run rules.
+| dependencies| org.clojure/clojure | 
 | 1.8.0 |  | org.clojure/clojurescript | 
 | 1.10.764 |  | org.clojure/math.combinatorics | 
 | 0.0.7 |  | org.clojure/tools.trace | 
 | 0.7.8 |  | org.clojure/tools.namespace | 
 | 0.2.4 |  | com.taoensso/timbre | 
 | 4.10.0 |  | fivetonine/collage | 
 | 0.2.0 |  | hiccup | 
 | 1.0.5 |  | net.mikera/imagez | 
 | 0.3.1 | 
 | 
 
 (this space intentionally left almost blank)
 | 
|  |  | 
|  |  | 
| A set of MicroWorld rules describing a simplified natural ecosystem. | (ns ^{:doc 
-      :author "Simon Brooke"}
-  mw-engine.core
-  (:require [clojure.core.reducers :as r]
-            [mw-engine.world :as world]
-            [mw-engine.utils :refer [get-int-or-zero map-world]])
-  (:gen-class)) | 
| mw-engine: the state/transition engine of MicroWorld.+       :author "Simon Brooke"}
+  mw-engine.natural-rules
+  (:require [mw-engine.utils :refer :all]
+        [mw-engine.world :refer :all])) | 
| mw-engine: the state/transition engine of MicroWorld. This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -3055,136 +2890,143 @@ USA. Copyright (C) 2014 Simon Brooke- Every rule is a function of two arguments, a cell and a world. If the rule
-fires, it returns a new cell, which should have the same values for :x and
-:y as the old cell. Anything else can be modified.-
- While any function of two arguments can be used as a rule, a special high
-level rule language is provided by the -
-mw-parserpackage, which compiles
-rules expressed in a subset of English rules into suitable functions. A cell is a map containing at least values for the keys :x, :y, and :state;
-a transformation should not alter the values of :x or :y, and should not
-return a cell without a keyword as the value of :state. Anything else is
-legal.-
- A world is a two dimensional matrix (sequence of sequences) of cells, such
-that every cell's :x and :y properties reflect its place in the matrix.
-See -
-world.clj. Each time the world is transformed (see -transform-world, for each cell,
-rules are applied in turn until one matches. Once one rule has matched no
-further rules can be applied. |  | 
| Apply a single -ruleto acell. What this is about is that I want to be able,
-   for debugging purposes, to tag a cell with the rule text of the rule which
-   fired (and especially so when an exception is thrown. So a rule may be either
-   an ifn, or a list (ifn source-text). This function deals with despatching
-   on those two possibilities.worldis also passed in in order to be able
-   to access neighbours. | (defn apply-rule
-  ([world cell rule]
-   (cond
-     (ifn? rule) (apply-rule world cell rule nil)
-     (seq? rule) (let [[afn src] rule] (apply-rule world cell afn src))))
-  ([world cell rule source]
-    (let [result (apply rule (list cell world))]
+Since the completion of the rule language this is more or less obsolete -
+there are still a few things that you can do with rules written in Clojure
+that you can't do in the rule language, but not many and I doubt they're
+important.+ |  | 
| 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})))
+    ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
+    (fn [cell world]
+      (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})))
+    ;; Forest on fertile land grows to climax
+    (fn [cell world]
       (cond
-        (and result source) (merge result {:rule source})
-        true result)))) | 
| Derive a cell from this -cellof thisworldby applying theserules. | (defn- apply-rules
-  [world cell rules]
-  (cond (empty? rules) cell
-    true (let [result (apply-rule world cell (first rules))]
-           (cond result result
-             true (apply-rules world cell (rest rules)))))) | 
| Derive a cell from this -cellof thisworldby applying theserules. If an
-   exception is thrown, cache its message on the cell and set it's state to error | (defn- transform-cell
-  [world cell rules]
-  (try
-    (merge
-      (apply-rules world cell rules)
-      {:generation (+ (get-int-or-zero cell :generation) 1)})
-    (catch Exception e
-      (merge cell {:error
-                   (format "%s at generation %d when in state %s"
-                           (.getMessage e)
-                           (:generation cell)
-                           (:state cell))
-                   :stacktrace (map #(.toString %) (.getStackTrace e))
-                   :state :error})))) | 
| Return a world derived from this -worldby applying theserulesto each cell. | (defn transform-world
-  [world rules]
-  (map-world world transform-cell (list rules))) | 
| Consider this single argument as a map of -:worldand:rules; apply the rules
-   to transform the world, and return a map of the new, transformed:worldand
-   these:rules. As a side effect, print the world. | (defn- transform-world-state
-  [state]
-  (let [world (transform-world (:world state) (:rules state))]
-    ;;(world/print-world world)
-    {:world world :rules (:rules state)})) | 
| Run this world with these rules for this number of generations.-
-
- | (defn run-world
-  [world init-rules rules generations]
-  (reduce (fn [world _iteration]
-            (transform-world world rules))
-        (transform-world world init-rules)
-        (range generations))) | 
|  |  | 
|  |  | 
| Simple functions to allow a world to be visualised.- | (ns ^{:doc 
-      :author "Simon Brooke"}
-  mw-engine.display
-  (:require [hiccup.core :refer [html]]
-            mw-engine.utils
-            mw-engine.world)) | 
| mw-engine: the state/transition engine of MicroWorld.-
- This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.-
- This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.-
- You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
-USA.-
- Copyright (C) 2014 Simon Brooke- |  | 
| - | (defn format-css-class [state]
-  "Format this `state`, assumed to be a keyword indicating a state in the
-   world, into a CSS class"
-  (subs (str state) 1)) | 
| Render this -state, assumed to be a keyword indicating a state in the
-   world, into a path which should recover the corresponding image file. | (defn format-image-path
-  [state]
-  (format "img/tiles/%s.png" (format-css-class state))) | 
| - | (defn format-mouseover [cell]
-  (str cell)) | 
| Render this world cell as a Hiccup table cell.- | (defn render-cell
-  [cell]
-  (let [state (:state cell)]
-    [:td {:class (format-css-class state) :title (format-mouseover cell)}
-     [:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
-      [:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]])) | 
| Render this world -rowas a Hiccup table row. | (defn render-world-row
-  [row]
-  (apply vector (cons :tr (map render-cell row)))) | 
| Render this -worldas a Hiccup table. | (defn render-world-table
-  [world]
-  (apply vector
-    (cons :table
-      (map render-world-row world)))) | 
|  |  | 
|  |  | 
| Experimental, probably of no interest to anyone else; attempt to
+        (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})))
+    ;; Climax forest neighbouring fires is likely to catch fire
+    (fn [cell world]
+      (cond
+        (and (= (:state cell) :climax)
+             (< (rand 3) 1)
+             (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})))
+    ;; 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]
+      (cond
+        (and (= (:state cell) :waste)
+             (not
+               (empty?
+                 (flatten
+                   (list
+                     (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub)
+                     (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]
+      (cond (= (:state cell) :waste)
+        (merge cell {:state :grassland})))
+    ;; Forest increases soil fertility
+    (fn [cell world]
+      (cond (member? (:state cell) '(:forest :climax))
+        (merge cell {:fertility (+ (get-int cell :fertility) 1)}))))) | 
| rules describing herbivore behaviour+ | (def herbivore-rules
+  (list
+    ;; if there are too many deer for the fertility of the area to sustain,
+    ;; some die or move on.
+    (fn [cell world]
+      (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.
+    (fn [cell world]
+      (cond (and (< (count (get-neighbours world cell)) 8)
+                 (< (rand 50) 1)
+                 (> (get-int cell :fertility) 0)
+                 (= (get-int cell :deer) 0))
+        (merge cell {:deer 2})))
+    ;; deer gradually spread through the world by breeding or migrating.
+    (fn [cell world]
+      (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))]
+        (cond (and
+                (> (get-int cell :fertility) 0)
+                (= (get-int cell :deer) 0)
+                (>= n 2))
+          (merge cell {:deer (int (/ n 2))}))))
+    ;; deer breed.
+    (fn [cell world]
+      (cond
+        (>= (get-int cell :deer) 2)
+        (merge cell {:deer (int (* (:deer cell) 2))}))))) | 
| rules describing predator behaviour+ |   (def predator-rules
+    (list
+     ;; wolves eat deer
+     (fn [cell world]
+      (cond
+       (>= (get-int cell :wolves) 1)
+       (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
+;;      ;; not more than eight wolves in a pack, for now (hack because wolves are not dying)
+;;      (fn [cell world]
+;;        (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]
+       (cond (> (get-int cell :wolves) (get-int cell :deer))
+         (merge cell {:wolves 0})))
+    ;; wolves arrive occasionally at the edge of the map.
+    (fn [cell world]
+      (cond (and (< (count (get-neighbours world cell)) 8)
+                 (< (rand 50) 1)
+                 (not (= (:state cell) :water))
+                 (= (get-int cell :wolves) 0))
+        (merge cell {:wolves 2})))
+    ;; wolves gradually spread through the world by breeding or migrating.
+    (fn [cell world]
+      (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))]
+        (cond (and
+                (not (= (:state cell) :water))
+                (= (get-int cell :wolves) 0)
+                (>= n 2))
+          (merge cell {:wolves 2}))))
+    ;; wolves breed.
+    (fn [cell world]
+      (cond
+        (>= (get-int cell :wolves) 2)
+        (merge cell {:wolves (int (* (:wolves cell) 2))}))))) | 
| rules which initialise the world+ |   (def init-rules
+    (list
+     ;; below the waterline, we have water.
+     (fn [cell world]
+       (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
+     ;; above the snowline, we have snow.
+     (fn [cell world]
+       (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}))))) | 
| + | (def natural-rules (flatten
+                    (list
+                     vegetation-rules
+                     herbivore-rules
+                     predator-rules))) | 
|  |  | 
|  |  | 
| Experimental, probably of no interest to anyone else; attempt to
       compute drainage on a world, assumed to have altitudes already set
       from a heightmap. | (ns ^{:doc 
@@ -3352,7 +3194,116 @@ USA.
   [hmap]
   "Create a world from the heightmap `hmap`, rain on it, and then compute river
    flows."
-  (flow-world (rain-world (flood-hollows (heightmap/apply-heightmap hmap))))) | 
|  |  | 
|  |  | 
| Functions to apply a heightmap to a world.+  (flow-world (rain-world (flood-hollows (heightmap/apply-heightmap hmap))))) | 
|  |  | 
|  |  | 
| Functions to transform a world and run rules.+ | (ns ^{:doc 
+      :author "Simon Brooke"}
+  mw-engine.core
+  (:require [clojure.core.reducers :as r]
+            [clojure.string :refer [join]]
+            [mw-engine.world :as world]
+            [mw-engine.utils :refer [get-int-or-zero map-world]]
+            [taoensso.timbre :as l])) | 
| mw-engine: the state/transition engine of MicroWorld.+
+ This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.+
+ You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+USA.+
+ Copyright (C) 2014 Simon Brooke+
+ Every rule is a function of two arguments, a cell and a world. If the rule
+fires, it returns a new cell, which should have the same values for :x and
+:y as the old cell. Anything else can be modified.+
+ While any function of two arguments can be used as a rule, a special high
+level rule language is provided by the +
+mw-parserpackage, which compiles
+rules expressed in a subset of English rules into suitable functions. A cell is a map containing at least values for the keys :x, :y, and :state;
+a transformation should not alter the values of :x or :y, and should not
+return a cell without a keyword as the value of :state. Anything else is
+legal.+
+ A world is a two dimensional matrix (sequence of sequences) of cells, such
+that every cell's :x and :y properties reflect its place in the matrix.
+See +
+world.clj. Each time the world is transformed (see +transform-world, for each cell,
+rules are applied in turn until one matches. Once one rule has matched no
+further rules can be applied. |  | 
| Apply a single +ruleto acell. What this is about is that I want to be able,
+   for debugging purposes, to tag a cell with the rule text of the rule which
+   fired (and especially so when an exception is thrown. So a rule may be either
+   an ifn, or a list (ifn source-text). This function deals with despatching
+   on those two possibilities.worldis also passed in in order to be able
+   to access neighbours. | (defn apply-rule
+  ([world cell rule]
+   (cond
+     (ifn? rule) (apply-rule world cell rule nil)
+     (seq? rule) (let [[afn src] rule] (apply-rule world cell afn src))))
+  ([world cell rule source]
+    (let [result (apply rule (list cell world))]
+      (cond
+        (and result source) (merge result {:rule source})
+        true result)))) | 
| Derive a cell from this +cellof thisworldby applying theserules. | (defn- apply-rules
+  [world cell rules]
+  (cond (empty? rules) cell
+    true (let [result (apply-rule world cell (first rules))]
+           (cond result result
+             true (apply-rules world cell (rest rules)))))) | 
| Derive a cell from this +cellof thisworldby applying theserules. If an
+   exception is thrown, cache its message on the cell and set it's state to error | (defn- transform-cell
+  [world cell rules]
+  (try
+    (merge
+      (apply-rules world cell rules)
+      {:generation (+ (get-int-or-zero cell :generation) 1)})
+    (catch Exception e
+      (merge cell {:error
+                   (format "%s at generation %d when in state %s"
+                           (.getMessage e)
+                           (:generation cell)
+                           (:state cell))
+                   :stacktrace (map #(.toString %) (.getStackTrace e))
+                   :state :error})))) | 
| Return a world derived from this +worldby applying theserulesto each cell. | (defn transform-world
+  [world rules]
+  (map-world world transform-cell (list rules))) | 
| Consider this single argument as a map of +:worldand:rules; apply the rules
+   to transform the world, and return a map of the new, transformed:worldand
+   these:rules. As a side effect, print the world. | (defn- transform-world-state
+  [state]
+  (let [world (transform-world (:world state) (:rules state))]
+    ;;(world/print-world world)
+    {:world world :rules (:rules state)})) | 
| Run this world with these rules for this number of generations.+
+
+ | (defn run-world
+  [world init-rules rules generations]
+  (reduce (fn [world iteration]
+            (l/info "Running iteration " iteration)
+            (transform-world world rules))
+        (transform-world world init-rules)
+        (range generations))) | 
|  |  | 
|  |  | 
| Functions to apply a heightmap to a world. | (ns ^{:doc 
       :author "Simon Brooke"}
   mw-engine.heightmap
@@ -3472,12 +3423,12 @@ a world the size of the heightmap will be created;
     (let [heightmap (imagez/filter-image
                       (filters/grayscale)
                       (collage/load-image imagepath))]
-      (map-world world tag-property (list property heightmap)))) | 
|  |  | 
|  |  | 
| A set of MicroWorld rules describing a simplified natural ecosystem.+      (map-world world tag-property (list property heightmap)))) | 
|  |  | 
|  |  | 
| Functions to create and to print two dimensional cellular automata. | (ns ^{:doc 
        :author "Simon Brooke"}
-  mw-engine.natural-rules
-  (:require [mw-engine.utils :refer :all]
-        [mw-engine.world :refer :all])) | 
| mw-engine: the state/transition engine of MicroWorld.+  mw-engine.world
+	(:require [clojure.string :as string :only [join]]
+            [mw-engine.utils :refer [population]])) | 
| mw-engine: the state/transition engine of MicroWorld. This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -3496,143 +3447,132 @@ USA. Copyright (C) 2014 Simon Brooke- Since the completion of the rule language this is more or less obsolete -
-there are still a few things that you can do with rules written in Clojure
-that you can't do in the rule language, but not many and I doubt they're
-important.- |  | 
| 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})))
-    ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
-    (fn [cell world]
-      (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})))
-    ;; Forest on fertile land grows to climax
-    (fn [cell world]
-      (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})))
-    ;; Climax forest neighbouring fires is likely to catch fire
-    (fn [cell world]
-      (cond
-        (and (= (:state cell) :climax)
-             (< (rand 3) 1)
-             (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})))
-    ;; 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]
-      (cond
-        (and (= (:state cell) :waste)
-             (not
-               (empty?
-                 (flatten
-                   (list
-                     (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub)
-                     (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]
-      (cond (= (:state cell) :waste)
-        (merge cell {:state :grassland})))
-    ;; Forest increases soil fertility
-    (fn [cell world]
-      (cond (member? (:state cell) '(:forest :climax))
-        (merge cell {:fertility (+ (get-int cell :fertility) 1)}))))) | 
| rules describing herbivore behaviour- | (def herbivore-rules
-  (list
-    ;; if there are too many deer for the fertility of the area to sustain,
-    ;; some die or move on.
-    (fn [cell world]
-      (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.
-    (fn [cell world]
-      (cond (and (< (count (get-neighbours world cell)) 8)
-                 (< (rand 50) 1)
-                 (> (get-int cell :fertility) 0)
-                 (= (get-int cell :deer) 0))
-        (merge cell {:deer 2})))
-    ;; deer gradually spread through the world by breeding or migrating.
-    (fn [cell world]
-      (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))]
-        (cond (and
-                (> (get-int cell :fertility) 0)
-                (= (get-int cell :deer) 0)
-                (>= n 2))
-          (merge cell {:deer (int (/ n 2))}))))
-    ;; deer breed.
-    (fn [cell world]
-      (cond
-        (>= (get-int cell :deer) 2)
-        (merge cell {:deer (int (* (:deer cell) 2))}))))) | 
| rules describing predator behaviour- |   (def predator-rules
-    (list
-     ;; wolves eat deer
-     (fn [cell world]
-      (cond
-       (>= (get-int cell :wolves) 1)
-       (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
-;;      ;; not more than eight wolves in a pack, for now (hack because wolves are not dying)
-;;      (fn [cell world]
-;;        (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]
-       (cond (> (get-int cell :wolves) (get-int cell :deer))
-         (merge cell {:wolves 0})))
-    ;; wolves arrive occasionally at the edge of the map.
-    (fn [cell world]
-      (cond (and (< (count (get-neighbours world cell)) 8)
-                 (< (rand 50) 1)
-                 (not (= (:state cell) :water))
-                 (= (get-int cell :wolves) 0))
-        (merge cell {:wolves 2})))
-    ;; wolves gradually spread through the world by breeding or migrating.
-    (fn [cell world]
-      (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))]
-        (cond (and
-                (not (= (:state cell) :water))
-                (= (get-int cell :wolves) 0)
-                (>= n 2))
-          (merge cell {:wolves 2}))))
-    ;; wolves breed.
-    (fn [cell world]
-      (cond
-        (>= (get-int cell :wolves) 2)
-        (merge cell {:wolves (int (* (:wolves cell) 2))}))))) | 
| rules which initialise the world- |   (def init-rules
-    (list
-     ;; below the waterline, we have water.
-     (fn [cell world]
-       (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
-     ;; above the snowline, we have snow.
-     (fn [cell world]
-       (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}))))) | 
| - | (def natural-rules (flatten
-                    (list
-                     vegetation-rules
-                     herbivore-rules
-                     predator-rules))) | 
|  |  | 
|  |  | 
|  Utility functions needed by MicroWorld and, specifically, in the
+ Functions to create and to print two dimensional cellular automata.
+Nothing in this namespace should determine what states are possible within
+the automaton, except for the initial state, :new.+
+ A cell is a map containing at least values for the keys :x, :y, and :state.+
+ A world is a two dimensional matrix (sequence of sequences) of cells, such
+that every cell's :x and :y properties reflect its place in the matrix.+ |  | 
| Create a minimal default cell at x, y+
+ 
+++xthe x coordinate at which this cell is created;+ythe y coordinate at which this cell is created. | (defn- make-cell
+  [x y]
+  {:x x :y y :state :new}) | 
| Make the (remaining) cells in a row at this height in a world of this width.+
+ 
+++indexx coordinate of the next cell to be created;+widthtotal width of the matrix, in cells;+heighty coordinate of the next cell to be created. | (defn- make-world-row
+  [index width height]
+  (cond (= index width) nil
+    true (cons (make-cell index height)
+               (make-world-row (inc index) width height)))) | 
| Make the (remaining) rows in a world of this width and height, from this
+   index.+
+ 
+++indexy coordinate of the next row to be created;+widthtotal width of the matrix, in cells;+heighttotal height of the matrix, in cells. | (defn- make-world-rows
+  [index width height]
+  (cond (= index height) nil
+    true (cons (apply vector (make-world-row 0 width index))
+               (make-world-rows (inc index) width height)))) | 
| Make a world width cells from east to west, and height cells from north to
+   south.+
+ 
+++widtha natural number representing the width of the matrix to be created;+heighta natural number representing the height of the matrix to be created. | (defn make-world
+  [width height]
+  (apply vector (make-world-rows 0 width height))) | 
| Truncate the print name of the state of this cell to at most limit characters.+ | (defn truncate-state
+  [cell limit]
+  (let [s (:state cell)]
+    (cond (> (count (str s)) limit) (subs s 0 limit)
+      true s))) | 
| Return a formatted string summarising the current state of this cell.+ | (defn format-cell
+  [cell]
+  (format "%10s(%2d/%2d)"
+          (truncate-state cell 10)
+          (population cell :deer)
+          (population cell :wolves))) | 
| Format one row in the state of a world for printing.+ | (defn- format-world-row
+  [row]
+  (string/join (map format-cell row))) | 
| Print the current state of this world, and return nil.+
+ 
+++worlda world as defined above. | (defn print-world
+  [world]
+  (println)
+  (dorun
+    (map
+      #(println
+         (format-world-row %))
+      world))
+  nil) | 
|  |  | 
|  |  | 
| Simple functions to allow a world to be visualised.+ | (ns ^{:doc 
+      :author "Simon Brooke"}
+  mw-engine.display
+  (:require [hiccup.core :refer [html]]
+            mw-engine.utils
+            mw-engine.world)) | 
| mw-engine: the state/transition engine of MicroWorld.+
+ This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.+
+ This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.+
+ You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
+USA.+
+ Copyright (C) 2014 Simon Brooke+ |  | 
| Base url (i.e., url of directory) from which to load tile images.+ | (def ^:dynamic *image-base*
+  "img/tiles") | 
| + | (defn format-css-class [state]
+  "Format this `state`, assumed to be a keyword indicating a state in the
+   world, into a CSS class"
+  (subs (str state) 1)) | 
| Render this +state, assumed to be a keyword indicating a state in the
+   world, into a path which should recover the corresponding image file. | (defn format-image-path
+  [state]
+  (format "%s/%s.png" *image-base* (format-css-class state))) | 
| + | (defn format-mouseover [cell]
+  (str cell)) | 
| Render this world cell as a Hiccup table cell.+ | (defn render-cell
+  [cell]
+  (let [state (:state cell)]
+    [:td {:class (format-css-class state) :title (format-mouseover cell)}
+     [:a {:href (format "inspect?x=%d&y=%d" (:x cell) (:y cell))}
+      [:img {:alt (:state cell) :width 32 :height 32 :src (format-image-path state)}]]])) | 
| Render this world +rowas a Hiccup table row. | (defn render-world-row
+  [row]
+  (apply vector (cons :tr (map render-cell row)))) | 
| Render this +worldas a Hiccup table. | (defn render-world-table
+  [world]
+  (apply vector
+    (cons :table
+      (map render-world-row world)))) | 
|  |  | 
|  |  | 
|  Utility functions needed by MicroWorld and, specifically, in the
       interpretation of MicroWorld rule. | (ns ^{:doc 
       :author "Simon Brooke"}
@@ -3680,7 +3620,7 @@ USA.
  | (defn init-generation
   [world cell]
   (merge cell {:generation (get-int-or-zero cell :generation)})) | 
| True if x, y are in bounds for this world (i.e., there is a cell at x, y)
-   else false.+   else false. DEPRECATED: it's a predicate, prefer in-bounds?.
 @@ -3688,46 +3628,58 @@ USA.worlda world as defined above;ya number which may or may not be a valid y coordinate within that world. | (defn in-bounds
+  {:deprecated "1.1.7"}
+  [world x y]
+  (and (>= x 0)(>= y 0)(< y (count world))(< x (count (first world))))) | 
| True if x, y are in bounds for this world (i.e., there is a cell at x, y)
+   else false.+
+ 
+++worlda world as defined above;+xa number which may or may not be a valid x coordinate within that world;+ya number which may or may not be a valid y coordinate within that world. | (defn in-bounds?
+  {:added "1.1.7"}
   [world x y]
   (and (>= x 0)(>= y 0)(< y (count world))(< x (count (first world))))) | 
| Wholly non-parallel map world implementation; see documentation for map-world. | (defn map-world-n-n
   ([world function]
-    (map-world-n-n world function nil))
+   (map-world-n-n world function nil))
   ([world function additional-args]
-    (into []
-           (map (fn [row]
-                    (into [] (map
-                             #(apply function
-                                     (cons world (cons % additional-args)))
-                             row)))
-                  world)))) | 
| Wholly parallel map-world implementation; see documentation for +   (into []
+         (map (fn [row]
+                (into [] (map
+                           #(apply function
+                                   (cons world (cons % additional-args)))
+                           row)))
+              world))))map-world. | 
| Wholly parallel map-world implementation; see documentation for map-world. | (defn map-world-p-p
   ([world function]
-    (map-world-p-p world function nil))
+   (map-world-p-p world function nil))
   ([world function additional-args]
-    (into []
-           (pmap (fn [row]
-                    (into [] (pmap
-                             #(apply function
-                                     (cons world (cons % additional-args)))
-                             row)))
-                  world)))) | 
| Apply this +   (into []
+         (pmap (fn [row]
+                 (into [] (pmap
+                            #(apply function
+                                    (cons world (cons % additional-args)))
+                            row)))
+               world))))functionto each cell in thisworldto produce a new world.
-   the arguments to the function will be the world, the cell, and any
-additional-argssupplied. Note that we parallel map over rows but
-   just map over cells within a row. That's because it isn't worth starting
-   a new thread for each cell, but there may be efficiency gains in
-   running rows in parallel. | 
| Apply this functionto each cell in thisworldto produce a new world.
+  the arguments to the function will be the world, the cell, and any
+additional-argssupplied. Note that we parallel map over rows but
+  just map over cells within a row. That's because it isn't worth starting
+  a new thread for each cell, but there may be efficiency gains in
+  running rows in parallel. | (defn map-world
   ([world function]
-    (map-world world function nil))
+   (map-world world function nil))
   ([world function additional-args]
-    (into []
-           (pmap (fn [row]
-                    (into [] (map
-                             #(apply function
-                                     (cons world (cons % additional-args)))
-                             row)))
-                  world)))) | 
| Return the cell a x, y in this world, if any.+   (into []
+         (pmap (fn [row]
+                 (into [] (map
+                            #(apply function
+                                    (cons world (cons % additional-args)))
+                            row)))
+               world)))) | 
| Return the cell a x, y in this world, if any. 
 @@ -3736,7 +3688,7 @@ USA.worlda world as defined above; | (defn get-cell
   [world x y]
-  (cond (in-bounds world x y)
+  (when (in-bounds world x y)
     (nth (nth world y) x))) | 
| Get the value of a property expected to be an integer from a map; if not present (or not an integer) return 0. 
@@ -3745,11 +3697,11 @@ USA.
  | (defn get-int
   [map key]
-  (cond (map? map)
+  (if (map? map)
     (let [v (map key)]
       (cond (and v (integer? v)) v
             true 0))
-        true (throw (Exception. "No map passed?")))) | 
| Return the population of this species in this cell. Currently a synonym for
+    (throw (Exception. "No map passed?")))) | 
| Return the population of this species in this cell. Currently a synonym for
    @@ -3894,104 +3846,81 @@ coordinates [x,y] in this world.
                     (= (:y cell)(:y %2)))
                   (merge %2 cell)
                   %2))
-    world))get-int, but may not always be (depending whether species are later
    implemented as actors) | 
|  |  | 
|  |  | 
| Functions to create and to print two dimensional cellular automata.- | (ns ^{:doc 
-       :author "Simon Brooke"}
-  mw-engine.world
-	(:require [clojure.string :as string :only [join]]
-            [mw-engine.utils :refer [population]])) | 
| mw-engine: the state/transition engine of MicroWorld.+    world)) | 
|  |  |