Dememoised get-neighbours, as the optimisation only works in deep

recursion which I'm no longer doing.
This commit is contained in:
simon 2015-04-21 07:56:22 +01:00
parent 5f73b18d12
commit 3c26408a9f

View file

@ -1,4 +1,4 @@
;; Utility functions needed by MicroWorld and, specifically, in the ;; Utility functions needed by MicroWorld and, specifically, in the
;; interpretation of MicroWorld rule. ;; interpretation of MicroWorld rule.
(ns mw-engine.utils (ns mw-engine.utils
@ -21,17 +21,17 @@
[elt col] (some #(= elt %) col)) [elt col] (some #(= elt %) col))
(defn get-int-or-zero (defn get-int-or-zero
"Return the value of this `property` from this `map` if it is a integer; "Return the value of this `property` from this `map` if it is a integer;
otherwise return zero." otherwise return zero."
[map property] [map property]
(let [value (map property)] (let [value (map property)]
(if (integer? value) value 0))) (if (integer? value) value 0)))
(defn init-generation (defn init-generation
"Return a cell like this `cell`, but having a value for :generation, zero if "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 the cell passed had no integer value for generation, otherwise the value
taken from the cell passed. The `world` argument is present only for taken from the cell passed. The `world` argument is present only for
consistency with the rule engine and is ignored." consistency with the rule engine and is ignored."
[world cell] [world cell]
(merge cell {:generation (get-int-or-zero cell :generation)})) (merge cell {:generation (get-int-or-zero cell :generation)}))
@ -124,7 +124,10 @@
(get-int cell species)) (get-int cell species))
(def memo-get-neighbours (def memo-get-neighbours
"Memoised core primitive for `get-neighbours` for efficiency." "Memoised get neighbours is more efficient when running deeply recursive
algorithms on the same world. But it's less efficient when running the
engine in its normal iterative style, because then we will rarely call
get naighbours on the same cell of the same world twice."
(memoize (memoize
(fn [world x y depth] (fn [world x y depth]
(remove nil? (remove nil?
@ -135,28 +138,36 @@
(range (- y depth) (+ y depth 1))))))))) (range (- y depth) (+ y depth 1)))))))))
(defn get-neighbours (defn get-neighbours
"Get the neighbours to distance depth of the cell at x, y in this world. "Get the neighbours to distance depth of a cell in this world.
Several overloads:
* `world` a world, as described in world.clj;
* `cell` a cell within that world
Gets immediate neighbours of the specified cell.
* `world` a world, as described in world.clj;
* `cell` a cell within that world
* `depth` an integer representing the depth to search from the
`cell`
Gets neighbours within the specified distance of the cell.
* `world` a world, as described in world.clj; * `world` a world, as described in world.clj;
* `x` an integer representing an x coordinate in that world; * `x` an integer representing an x coordinate in that world;
* `y` an integer representing an y coordinate in that world; * `y` an integer representing an y coordinate in that world;
* `depth` an integer representing the distance from [x,y] that * `depth` an integer representing the distance from [x,y] that
should be searched." should be searched
Gets the neighbours within the specified distance of the cell at
coordinates [x,y] in this world."
([world x y depth] ([world x y depth]
(memo-get-neighbours world x y depth)) (remove nil?
(map #(get-cell world (first %) (first (rest %)))
(remove #(= % (list x y))
(combo/cartesian-product
(range (- x depth) (+ x depth 1))
(range (- y depth) (+ y depth 1)))))))
([world cell depth] ([world cell depth]
"Get the neighbours to distance depth of this cell in this world.
* `world` a world, as described in world.clj;
* `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that
should be searched."
(memo-get-neighbours world (:x cell) (:y cell) depth)) (memo-get-neighbours world (:x cell) (:y cell) depth))
([world cell] ([world cell]
"Get the immediate neighbours of this cell in this world
* `world` a world, as described in world.clj;
* `cell` a cell within that world."
(get-neighbours world cell 1))) (get-neighbours world cell 1)))
(defn get-neighbours-with-property-value (defn get-neighbours-with-property-value
@ -166,10 +177,10 @@
* `world` a world, as described in `world.clj`; * `world` a world, as described in `world.clj`;
* `cell` a cell within that world; * `cell` a cell within that world;
* `depth` an integer representing the distance from [x,y] that * `depth` an integer representing the distance from [x,y] that
should be searched; should be searched (optional);
* `property` a keyword representing a property of the neighbours; * `property` a keyword representing a property of the neighbours;
* `value` a value of that property (or, possibly, the name of another); * `value` a value of that property (or, possibly, the name of another);
* `op` a comparator function to use in place of `=`. * `op` a comparator function to use in place of `=` (optional).
It gets messy." It gets messy."
([world x y depth property value op] ([world x y depth property value op]
@ -253,7 +264,7 @@
[world cell] [world cell]
(if (in-bounds world (:x cell) (:y cell)) (if (in-bounds world (:x cell) (:y cell))
(map-world world (map-world world
#(if #(if
(and (and
(= (:x cell)(:x %2)) (= (:x cell)(:x %2))
(= (:y cell)(:y %2))) (= (:y cell)(:y %2)))