From 3c26408a9f1a7af2af8d5364104b285798be8d3f Mon Sep 17 00:00:00 2001
From: simon <simon@journeyman.cc>
Date: Tue, 21 Apr 2015 07:56:22 +0100
Subject: [PATCH] Dememoised get-neighbours, as the optimisation only works in
 deep recursion which I'm no longer doing.

---
 src/mw_engine/utils.clj | 55 ++++++++++++++++++++++++-----------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/src/mw_engine/utils.clj b/src/mw_engine/utils.clj
index 3ad2b1f..279ec18 100644
--- a/src/mw_engine/utils.clj
+++ b/src/mw_engine/utils.clj
@@ -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.
 
 (ns mw-engine.utils
@@ -21,17 +21,17 @@
   [elt col] (some #(= elt %) col))
 
 (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."
   [map property]
   (let [value (map property)]
     (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
    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." 
+   taken from the cell passed. The `world` argument is present only for
+   consistency with the rule engine and is ignored."
   [world cell]
   (merge cell {:generation (get-int-or-zero cell :generation)}))
 
@@ -124,7 +124,10 @@
   (get-int cell species))
 
 (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
    (fn [world x y depth]
      (remove nil?
@@ -135,28 +138,36 @@
                             (range (- y depth) (+ y depth 1)))))))))
 
 (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;
     * `x` an integer representing an x coordinate in that world;
     * `y` an integer representing an y coordinate in that world;
     * `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]
-      (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]
-      "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))
     ([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)))
 
 (defn get-neighbours-with-property-value
@@ -166,10 +177,10 @@
     * `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;
+      should be searched (optional);
     * `property` a keyword representing a property of the neighbours;
     * `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."
   ([world x y depth property value op]
@@ -253,7 +264,7 @@
   [world cell]
   (if (in-bounds world (:x cell) (:y cell))
     (map-world world
-               #(if 
+               #(if
                   (and
                     (= (:x cell)(:x %2))
                     (= (:y cell)(:y %2)))