mw-engine/src/mw_engine/drainage.clj
2014-10-20 17:01:40 +01:00

53 lines
2.1 KiB
Clojure

;; Experimental, probably of no interest to anyone else; attempt to compute drainage on a world,
;; assumed to have altitudes already set from a heighmap.
(ns mw-engine.drainage
(:use mw-engine.utils
mw-engine.world))
(def ^:dynamic *sealevel* 10)
(defn rain-world
"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"
[world]
(map-world world (fn [world cell] (merge cell {:rainfall 1}))))
(defn flow-contributors
"Return a list of the cells in this `world` which are higher than this
`cell` and for which this cell is the lowest neighbour"
[world cell]
(remove nil?
(into []
(map
(fn [n]
(cond (= cell (get-least-cell (get-neighbours world n) :altitude)) n))
(get-neighbours-with-property-value world (:x cell) (:y cell) 1
:altitude
(or (:altitude cell) 0) >)))))
(def flow
"Compute the total flow upstream of this `cell` in this `world`, and return a cell identical
to this one but having a value of its flow property set from that computation. The function is
memoised because the consequence of mapping a recursive function across an array is that many
cells will be revisited - potentially many times.
Flow comes from a higher cell to a lower only if the lower is the lowest neighbour of the higher."
(memoize
(fn [world cell]
(cond
(not (nil? (:flow cell))) cell
(<= (or (:altitude cell) 0) *sealevel*) cell
true
(merge cell
{:flow (+ (:rainfall cell)
(apply +
(map (fn [neighbour] (:flow (flow world neighbour)))
(flow-contributors world cell))))})))))
(defn flow-world
"Return a world like this `world`, but with cells tagged with the amount of
water flowing through them."
[world]
(map-world (rain-world world) flow))