Working on getting drainage to actually work - which, inter alia, means

further work on efficiency.
This commit is contained in:
simon 2014-08-30 21:58:48 +01:00
parent dffa617a38
commit 42e6cfac05
3 changed files with 28 additions and 38 deletions

View file

@ -23,12 +23,12 @@
;; that every cell's :x and :y properties reflect its place in the matrix. ;; that every cell's :x and :y properties reflect its place in the matrix.
;; See `world.clj`. ;; See `world.clj`.
;; ;;
;; Each time the world is transformed (see `transform-world`, for each cell, ;; 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 ;; rules are applied in turn until one matches. Once one rule has matched no
;; further rules can be applied. ;; further rules can be applied.
(defn apply-rule (defn apply-rule
"Apply a single `rule` to a `cell`. What this is about is that I want to be able, "Apply a single `rule` to a `cell`. 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 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 fired (and especially so when an exception is thrown. So a rule may be either
@ -41,7 +41,7 @@
(seq? rule) (let [[afn src] rule] (apply-rule cell world afn src)))) (seq? rule) (let [[afn src] rule] (apply-rule cell world afn src))))
([cell world rule source] ([cell world rule source]
(let [result (apply rule (list cell world))] (let [result (apply rule (list cell world))]
(cond (cond
(and result source) (merge result {:rule source}) (and result source) (merge result {:rule source})
true result)))) true result))))
@ -58,11 +58,11 @@
exception is thrown, cache its message on the cell and set it's state to error" exception is thrown, cache its message on the cell and set it's state to error"
[world cell rules] [world cell rules]
(try (try
(merge (merge
(apply-rules world cell rules) (apply-rules world cell rules)
{:generation (+ (or (:generation cell) 0) 1)}) {:generation (+ (or (:generation cell) 0) 1)})
(catch Exception e (catch Exception e
(merge cell {:error (merge cell {:error
(format "%s at generation %d when in state %s" (format "%s at generation %d when in state %s"
(.getMessage e) (.getMessage e)
(:generation cell) (:generation cell)
@ -93,28 +93,10 @@
* `generations` an (integer) number of generations. * `generations` an (integer) number of generations.
Return the final generation of the world." Return the final generation of the world."
[world init-rules rules generations]
(let [state {:world (transform-world world init-rules) :rules rules}]
(:world
(last
(doall
(take generations
(iterate transform-world-state state)))))))
(defn run-world2
"Doesn't work yet"
[world init-rules rules generations] [world init-rules rules generations]
(with-local-vars [r (ref (transform-world world init-rules))] (reduce (fn [world _iteration]
(dotimes [g generations]
(dosync
(ref-set r (transform-world (deref r) rules))))
(deref r)))
(defn run-world3
[world init-rules rules generations]
(reduce (fn [world _iteration]
(transform-world world rules)) (transform-world world rules))
(transform-world world init-rules) (transform-world world init-rules)
(range generations))) (range generations)))

View file

@ -2,9 +2,13 @@
;; assumed to have altitudes already set from a heighmap. ;; assumed to have altitudes already set from a heighmap.
(ns mw-engine.drainage (ns mw-engine.drainage
(:require
[clojure.core.reducers :as r])
(:use mw-engine.utils (:use mw-engine.utils
mw-engine.world)) mw-engine.world))
(def ^:dynamic *sealevel* 10)
(defn rain-world (defn rain-world
"Simulate rainfall on this `world`. TODO: Doesn't really work just now - should "Simulate rainfall on this `world`. TODO: Doesn't really work just now - should
rain more on west-facing slopes, and less to the east of high ground" rain more on west-facing slopes, and less to the east of high ground"
@ -16,12 +20,13 @@
`cell` and for which this cell is the lowest neighbour" `cell` and for which this cell is the lowest neighbour"
[world cell] [world cell]
(remove nil? (remove nil?
(map (into []
(fn [n] (r/map
(cond (= cell (get-least-cell (get-neighbours world n) :altitude)) n)) (fn [n]
(get-neighbours-with-property-value world (:x cell) (:y cell) 1 (cond (= cell (get-least-cell (get-neighbours world n) :altitude)) n))
(get-neighbours-with-property-value world (:x cell) (:y cell) 1
:altitude :altitude
(or (:altitude cell) 0) >)))) (or (:altitude cell) 0) >)))))
(defn flow (defn 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
@ -29,11 +34,14 @@
Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher." Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher."
[world cell] [world cell]
(cond
(> (or (:altitude cell) 0) *sealevel*)
(merge cell (merge cell
{:flow (+ (:rainfall cell) {:flow (+ (:rainfall cell)
(apply + (apply +
(map (fn [neighbour] (:flow (flow world neighbour))) (map (fn [neighbour] (:flow (flow world neighbour)))
(flow-contributors world cell))))})) (flow-contributors world cell))))})
true 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

@ -1,7 +1,7 @@
;; Utility functions needed by MicroWorld and, specifically, in the interpretation of MicroWorld rule. ;; Utility functions needed by MicroWorld and, specifically, in the interpretation of MicroWorld rule.
(ns mw-engine.utils (ns mw-engine.utils
(:require (:require
[clojure.core.reducers :as r] [clojure.core.reducers :as r]
[clojure.math.combinatorics :as combo])) [clojure.math.combinatorics :as combo]))
@ -36,10 +36,10 @@
([world function] ([world function]
(map-world world function nil)) (map-world world function nil))
([world function additional-args] ([world function additional-args]
(into [] ;; vectors are more efficient for scanning, which we do a lot. (into []
(r/map (fn [row] (r/map (fn [row]
(into [] (r/map (into [] (r/map
#(apply function #(apply function
(cons world (cons % additional-args))) (cons world (cons % additional-args)))
row))) row)))
world)))) world))))