Further work on the Falls of Clyde problem, and on optimisation.

This commit is contained in:
Simon Brooke 2015-04-13 20:36:24 +01:00
parent 1c8d8c4219
commit 337d1ae07e
2 changed files with 54 additions and 32 deletions

View file

@ -22,22 +22,45 @@
`cell` and for which this cell is the lowest neighbour, or which are at the `cell` and for which this cell is the lowest neighbour, or which are at the
same altitude and have greater flow" same altitude and have greater flow"
[world cell] [world cell]
(remove nil? (filter #(map? %)
(into [] (map
(map (fn [n]
(fn [n] (cond
(cond (= cell (get-least-cell (get-neighbours world n) :altitude)) n (= cell (get-least-cell (get-neighbours world n) :altitude)) n
(and (= (:altitude cell) (:altitude n))(> (or (:flow n) 0) (or (:flow cell) 0))) n)) (and (= (:altitude cell) (:altitude n))
(get-neighbours-with-property-value world (:x cell) (:y cell) 1 (> (or (:flow n) 0) (or (:flow cell) 0))) n))
:altitude (get-neighbours-with-property-value
(or (:altitude cell) 0) >=))))) world (:x cell) (:y cell) 1 :altitude
(or (:altitude cell) 0) >=))))
(defn is-hollow
"Detects point hollows - that is, individual cells all of whose neighbours
are higher. Return true if this `cell` has an altitude lower than any of
its neighbours in this `world`"
[world cell]
;; quicker to count the elements of the list and compare equality of numbers
;; than recursive equality check on members, I think. But worth benchmarking.
(let [neighbours (get-neighbours world cell)
altitude (or (:altitude cell) 0)]
(= (count neighbours)
(count (get-neighbours-with-property-value
world (:x cell) (:y cell) 1 :altitude >)))))
(defn flood-hollow (defn flood-hollow
"Raise the altitude of a copy of this `cell` of this `world` to one unit above the lowest of these `neighbours`, and reflow." "Raise the altitude of a copy of this `cell` of this `world` to the altitude
[cell world neighbours] of the lowest of its `neighbours`."
(let [lowest (get-least-cell neighbours :altitude)] ([world cell neighbours]
(flow world (merge cell {:altitude (+ (:altitude lowest) 1)})))) (let [lowest (get-least-cell neighbours :altitude)]
;; cell) (merge cell {:state :water :altitude (:altitude lowest)})))
([world cell]
(flood-hollow world cell (get-neighbours world cell))))
(defn flood-hollows
"Flood all local hollows in this `world`. At this stage only floods single
cell hollows."
[world]
(map-world world
#(if (is-hollow %1 %2) (flood-hollow %1 %2) %2)))
(def flow (def flow
"Compute the total flow upstream of this `cell` in this `world`, and return a cell identical "Compute the total flow upstream of this `cell` in this `world`, and return a cell identical
@ -52,17 +75,11 @@
(not (nil? (:flow cell))) cell (not (nil? (:flow cell))) cell
(<= (or (:altitude cell) 0) *sealevel*) cell (<= (or (:altitude cell) 0) *sealevel*) cell
true true
(let [contributors (flow-contributors world cell)] (merge cell
;; (if {:flow (+ (:rainfall cell)
;; (= (count contributors) 8) (apply +
;; local lowspot - lake bottom (map (fn [neighbour] (:flow (flow world neighbour)))
;; (flood-hollow cell world contributors) (flow-contributors world cell))))})))))
;; otherwise...
(merge cell
{:flow (+ (:rainfall cell)
(apply +
(map (fn [neighbour] (:flow (flow world neighbour)))
(flow-contributors world cell))))}))))))
(defn flow-world (defn flow-world
"Return a world like this `world`, but with cells tagged with the amount of "Return a world like this `world`, but with cells tagged with the amount of

View file

@ -106,6 +106,16 @@
[cell species] [cell species]
(get-int cell species)) (get-int cell species))
(def memo-get-neighbours
"Memoised core primitive for `get-neighbours` for efficiency."
(memoize
(fn [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)))))))))
(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 the cell at x, y in this world.
@ -116,12 +126,7 @@
* `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."
([world x y depth] ([world x y depth]
(remove nil? (memo-get-neighbours world x y depth))
(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. "Get the neighbours to distance depth of this cell in this world.
@ -129,7 +134,7 @@
* `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."
(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 "Get the immediate neighbours of this cell in this world