diff --git a/resources/public/docs/mw-engine/uberdoc.html b/resources/public/docs/mw-engine/uberdoc.html index d6bc7f0..72c4e57 100644 --- a/resources/public/docs/mw-engine/uberdoc.html +++ b/resources/public/docs/mw-engine/uberdoc.html @@ -3029,548 +3029,5 @@ net.brehaut.ClojureTools = (function (SH) { }; })(SyntaxHighlighter);
mw-engine0.1.2-SNAPSHOTCellular automaton world builder. -dependencies
| (this space intentionally left almost blank) | ||||||||||||
Functions to transform a world and run rules. - | |||||||||||||
| - | (ns mw-engine.core - (:use mw-engine.utils) - (:require [mw-engine.world :as world])) | ||||||||||||
Every rule is a function of two arguments, a cell and a world. If the rule -fires, it returns a new cell, which should have the same values for :x and -:y as the old cell. Anything else can be modified. - -While any function of two arguments can be used as a rule, a special high
-level rule language is provided by the A cell is a map containing at least values for the keys :x, :y, and :state; -a transformation should not alter the values of :x or :y, and should not -return a cell without a keyword as the value of :state. Anything else is -legal. - -A world is a two dimensional matrix (sequence of sequences) of cells, such
-that every cell's :x and :y properties reflect its place in the matrix.
-See Each time the world is transformed (see | |||||||||||||
Apply a single | (defn apply-rule
- ([world cell rule]
- (cond
- (ifn? rule) (apply-rule cell world rule nil)
- (seq? rule) (let [[afn src] rule] (apply-rule cell world afn src))))
- ([cell world rule source]
- (let [result (apply rule (list cell world))]
- (cond
- (and result source) (merge result {:rule source})
- true result)))) | ||||||||||||
Derive a cell from this | (defn- apply-rules - [world cell rules] - (cond (empty? rules) cell - true (let [result (apply-rule world cell (first rules))] - (cond result result - true (apply-rules world cell (rest rules)))))) | ||||||||||||
Derive a cell from this | (defn- transform-cell
- [world cell rules]
- (try
- (merge
- (apply-rules world cell rules)
- {:generation (+ (or (:generation cell) 0) 1)})
- (catch Exception e
- (merge cell {:error
- (format "%s at generation %d when in state %s"
- (.getMessage e)
- (:generation cell)
- (:state cell))
- :state :error})))) | ||||||||||||
Return a world derived from this | (defn transform-world - [world rules] - (map-world world transform-cell (list rules))) | ||||||||||||
Consider this single argument as a map of | (defn- transform-world-state
- [state]
- (let [world (transform-world (:world state) (:rules state))]
- (world/print-world world)
- {:world world :rules (:rules state)})) | ||||||||||||
Run this world with these rules for this number of generations. - -
| (defn run-world
- [world init-rules rules generations]
- (let [state {:world (transform-world world init-rules) :rules rules}]
- (take generations (iterate transform-world-state state)))) | ||||||||||||
Functions to apply a heightmap to a world. - -Heightmaps are considered only as greyscale images, so colour is redundent (will be -ignored). Darker shades are higher. - | |||||||||||||
| - | (ns mw-engine.heightmap - (:import [java.awt.image BufferedImage]) - (:use mw-engine.utils - mw-engine.world - [mikera.image.core :only [load-image filter-image get-pixels]] - [mikera.image.filters])) | ||||||||||||
Surprisingly, Clojure doesn't seem to have an abs function, or else I've - missed it. So here's one of my own. Maps natural numbers onto themselves, - and negative integers onto natural numbers. Also maps negative real numbers - onto positive real numbers. - -
| (defn- abs - [n] - (cond (< n 0) (- 0 n) true n)) | ||||||||||||
Set the | (defn tag-gradient
- [world cell]
- (let [heights (remove nil? (map #(:altitude %) (get-neighbours world cell)))
- highest (cond (empty? heights) 0 ;; shouldn't happen
- true (apply max heights))
- lowest (cond (empty? heights) 0 ;; shouldn't
- true (apply min heights))
- gradient (- highest lowest)]
- (merge cell {:gradient gradient}))) | ||||||||||||
Set the | (defn tag-gradients - [world] - (map-world world tag-gradient)) | ||||||||||||
Set the altitude of this cell from the corresponding pixel of this heightmap. - If the heightmap you supply is smaller than the world, this will break. - -
| (defn tag-altitude
- ([world cell heightmap]
- (tag-altitude cell heightmap))
- ([cell heightmap]
- (merge cell
- {:altitude
- (+ (get-int cell :altitude)
- (- 256
- (abs
- (mod
- (.getRGB heightmap
- (get-int cell :x)
- (get-int cell :y)) 256))))}))) | ||||||||||||
Apply the image file loaded from this path to this world, and return a world whose - altitudes are modified (added to) by the altitudes in the heightmap. It is assumed that - the heightmap is at least as large in x and y dimensions as the world. - -
| (defn apply-heightmap - ([world imagepath] - (let [heightmap (filter-image (grayscale)(load-image imagepath))] - (map-world - (map-world world tag-altitude (list heightmap)) - tag-gradient))) - ([imagepath] - (let [heightmap (filter-image (grayscale)(load-image imagepath)) - world (make-world (.getWidth heightmap) (.getHeight heightmap))] - (map-world - (map-world world tag-altitude (list heightmap)) - tag-gradient)))) | ||||||||||||
manifest.clj: a mechanism - | (ns mw-engine.manifest) | ||||||||||||
| - | (def manifest {
- :build-signature {
- :build-signture-version "0.1.2-SNAPSHOT"
- :build-signature-user "unset"
- :build-signature-email "unset"
- :build-signature-timestamp "unset"
- ;; NOTE: it's important that the closing brace not be on the same
- ;; line as the build-signature fields, because of how the buildall
- ;; script constructs the build signature.
- }
- }) | ||||||||||||
A set of MicroWorld rules describing a simplified natural ecosystem. - -Since the completion of the rule language this is more or less obsolete - -there are still a few things that you can do with rules written in Clojure -that you can't do in the rule language, but not many and I doubt they're -important. - | |||||||||||||
| - | (ns mw-engine.natural-rules - (:use mw-engine.utils - mw-engine.world)) | ||||||||||||
treeline at arbitrary altitude. - | (def treeline 150) | ||||||||||||
waterline also at arbitrary altitude. - | (def waterline 10) | ||||||||||||
and finally snowline is also arbitrary. - | (def snowline 200) | ||||||||||||
Rare chance of lightning strikes - | (def lightning-probability 500) | ||||||||||||
rules describing vegetation - | (def vegetation-rules
- (list
- ;; Randomly, birds plant tree seeds into grassland.
- (fn [cell world] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
- ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
- (fn [cell world]
- (cond (and
- (= (:state cell) :heath)
- ;; browsing limit really ought to vary with soil fertility, but...
- (< (+ (get-int cell :deer)(get-int cell :sheep)) 6)
- (< (get-int cell :altitude) treeline))
- (merge cell {:state :scrub})))
- (fn [cell world] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
- ;; Forest on fertile land grows to climax
- (fn [cell world]
- (cond
- (and
- (= (:state cell) :forest)
- (> (get-int cell :fertility) 10))
- (merge cell {:state :climax})))
- ;; Climax forest occasionally catches fire (e.g. lightning strikes)
- (fn [cell world] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
- ;; Climax forest neighbouring fires is likely to catch fire
- (fn [cell world]
- (cond
- (and (= (:state cell) :climax)
- (< (rand 3) 1)
- (not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire))))
- (merge cell {:state :fire})))
- ;; After fire we get waste
- (fn [cell world] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
- ;; And after waste we get pioneer species; if there's a woodland seed
- ;; source, it's going to be heath, otherwise grassland.
- (fn [cell world]
- (cond
- (and (= (:state cell) :waste)
- (not
- (empty?
- (flatten
- (list
- (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub)
- (get-neighbours-with-state world (:x cell) (:y cell) 1 :forest)
- (get-neighbours-with-state world (:x cell) (:y cell) 1 :climax))))))
- (merge cell {:state :heath})))
- (fn [cell world]
- (cond (= (:state cell) :waste)
- (merge cell {:state :grassland})))
- ;; Forest increases soil fertility
- (fn [cell world]
- (cond (member? (:state cell) '(:forest :climax))
- (merge cell {:fertility (+ (get-int cell :fertility) 1)}))))) | ||||||||||||
rules describing herbivore behaviour - | (def herbivore-rules
- (list
- ;; if there are too many deer for the fertility of the area to sustain,
- ;; some die or move on.
- (fn [cell world]
- (cond (> (get-int cell :deer) (get-int cell :fertility))
- (merge cell {:deer (get-int cell :fertility)})))
- ;; deer arrive occasionally at the edge of the map.
- (fn [cell world]
- (cond (and (< (count (get-neighbours world cell)) 8)
- (< (rand 50) 1)
- (> (get-int cell :fertility) 0)
- (= (get-int cell :deer) 0))
- (merge cell {:deer 2})))
- ;; deer gradually spread through the world by breeding or migrating.
- (fn [cell world]
- (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))]
- (cond (and
- (> (get-int cell :fertility) 0)
- (= (get-int cell :deer) 0)
- (>= n 2))
- (merge cell {:deer (int (/ n 2))}))))
- ;; deer breed.
- (fn [cell world]
- (cond
- (>= (get-int cell :deer) 2)
- (merge cell {:deer (int (* (:deer cell) 2))}))))) | ||||||||||||
rules describing predator behaviour - | (def predator-rules
- (list
- ;; wolves eat deer
- (fn [cell world]
- (cond
- (>= (get-int cell :wolves) 1)
- (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
-;; ;; not more than eight wolves in a pack, for now (hack because wolves are not dying)
-;; (fn [cell world]
-;; (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8})))
- ;; if there are not enough deer to sustain the get-int of wolves,
- ;; some wolves die or move on. (doesn't seem to be working?)
- (fn [cell world]
- (cond (> (get-int cell :wolves) (get-int cell :deer))
- (merge cell {:wolves 0})))
- ;; wolves arrive occasionally at the edge of the map.
- (fn [cell world]
- (cond (and (< (count (get-neighbours world cell)) 8)
- (< (rand 50) 1)
- (not (= (:state cell) :water))
- (= (get-int cell :wolves) 0))
- (merge cell {:wolves 2})))
- ;; wolves gradually spread through the world by breeding or migrating.
- (fn [cell world]
- (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))]
- (cond (and
- (not (= (:state cell) :water))
- (= (get-int cell :wolves) 0)
- (>= n 2))
- (merge cell {:wolves 2}))))
- ;; wolves breed.
- (fn [cell world]
- (cond
- (>= (get-int cell :wolves) 2)
- (merge cell {:wolves (int (* (:wolves cell) 2))}))))) | ||||||||||||
rules which initialise the world - | (def init-rules
- (list
- ;; below the waterline, we have water.
- (fn [cell world]
- (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
- ;; above the snowline, we have snow.
- (fn [cell world]
- (cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow})))
- ;; in between, we have a wasteland.
- (fn [cell world] (cond (= (:state cell) :new) (merge cell {:state :grassland}))))) | ||||||||||||
| - | (def natural-rules (flatten - (list - vegetation-rules - herbivore-rules - ;; predator-rules))) | ||||||||||||
Utility functions needed by MicroWorld and, specifically, in the interpretation of MicroWorld rule. - | |||||||||||||
| - | (ns mw-engine.utils - (:require [clojure.math.combinatorics :as combo])) | ||||||||||||
True if elt is a member of col. - | (defn member? - [elt col] (some #(= elt %) col)) | ||||||||||||
True if x, y are in bounds for this world (i.e., there is a cell at x, y) - else false. - -
| (defn in-bounds - [world x y] - (and (>= x 0)(>= y 0)(< y (count world))(< x (count (first world))))) | ||||||||||||
Apply this | (defn map-world - ([world function] - (map-world world function nil)) - ([world function additional-args] - (apply vector ;; vectors are more efficient for scanning, which we do a lot. - (for [row world] - (apply vector - (map #(apply function (cons world (cons % additional-args))) - row)))))) | ||||||||||||
Return the cell a x, y in this world, if any. - -
| (defn get-cell - [world x y] - (cond (in-bounds world x y) - (nth (nth world y) x))) | ||||||||||||
Get the value of a property expected to be an integer from a map; if not present (or not an integer) return 0. - -
| (defn get-int - [map key] - (cond (map? map) - (let [v (map key)] - (cond (and v (integer? v)) v - true 0)) - true (throw (Exception. "No map passed?")))) | ||||||||||||
Return the population of this species in this cell. Currently a synonym for
-
| (defn population - [cell species] - (get-int cell species)) | ||||||||||||
Get the neighbours to distance depth of the cell at x, y in this world. - -
- | (defn 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." - (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))) | ||||||||||||
Get the neighbours to distance depth of the cell at x, y in this world which - have this value for this property. - -
-
-It gets messy. - | (defn get-neighbours-with-property-value - ([world x y depth property value op] - (filter - #(eval - (list op - (or (get % property) (get-int % property)) - value)) - (get-neighbours world x y depth))) - ([world x y depth property value] - (get-neighbours-with-property-value world x y depth property value =)) - ([world cell depth property value] - (get-neighbours-with-property-value world (:x cell) (:y cell) depth - property value)) - ([world cell property value] - (get-neighbours-with-property-value world cell 1 - property value))) | ||||||||||||
Get the neighbours to distance depth of the cell at x, y in this world which - have this state. - -
- | (defn get-neighbours-with-state - ([world x y depth state] - (filter #(= (:state %) state) (get-neighbours world x y depth))) - ([world cell depth state] - (get-neighbours-with-state world (:x cell) (:y cell) depth state)) - ([world cell state] - (get-neighbours-with-state world cell 1 state))) | ||||||||||||
If this | (defn- set-cell-property
- [cell x y property value]
- (cond
- (and (= x (:x cell)) (= y (:y cell)))
- (merge cell {property value :rule "Set by user"})
- true
- cell)) | ||||||||||||
Return a world like this | (defn set-property - ([world cell property value] - (set-property world (:x cell) (:y cell) property value)) - ([world x y property value] - (apply - vector ;; we want a vector of vectors, not a list of lists, for efficiency - (map - (fn [row] - (apply - vector - (map #(set-cell-property % x y property value) - row))) - world)))) | ||||||||||||
| - | (ns mw-engine.version - (:gen-class)) | ||||||||||||
Get the implementation version from the package of this namespace, which must - be compiled into a class (see clojure.java.interop) - | (defn get-implementation-version - [namespace-class] - (.getImplementationVersion (.getPackage namespace-class))) | ||||||||||||
| - | (defn -main [] - (get-implementation-version (eval 'mw-engine.version))) | ||||||||||||
Functions to create and to print two dimensional cellular automata. Nothing in this -file should determine what states are possible within the automaton, except for the -initial state, :new. - -A cell is a map containing at least values for the keys :x, :y, and :state. - -A world is a two dimensional matrix (sequence of sequences) of cells, such -that every cell's :x and :y properties reflect its place in the matrix. - | |||||||||||||
| - | (ns mw-engine.world - (:use mw-engine.utils)) | ||||||||||||
Create a minimal default cell at x, y - -
| (defn- make-cell
- [x y]
- {:x x :y y :state :new}) | ||||||||||||
Make the (remaining) cells in a row at this height in a world of this width. - -
| (defn- make-world-row - [index width height] - (cond (= index width) nil - true (cons (make-cell index height) - (make-world-row (+ index 1) width height)))) | ||||||||||||
| - | (defn- make-world-rows [index width height] - "Make the (remaining) rows in a world of this width and height, from this - index. - * `index` y coordinate of the next row to be created; - * `width` total width of the matrix, in cells; - * `height` total height of the matrix, in cells." - (cond (= index height) nil - true (cons (apply vector (make-world-row 0 width index)) - (make-world-rows (+ index 1) width height)))) | ||||||||||||
Make a world width cells from east to west, and height cells from north to - south. - -
| (defn make-world - [width height] - (apply vector (make-world-rows 0 width height))) | ||||||||||||
Truncate the print name of the state of this cell to at most limit characters. - | (defn truncate-state - [cell limit] - (let [s (:state cell)] - (cond (> (count (.toString s)) 10) (subs s 0 10) - true s))) | ||||||||||||
Return a formatted string summarising the current state of this cell. - | (defn format-cell - [cell] - (format "%10s(%2d/%2d)" - (truncate-state cell 10) - (population cell :deer) - (population cell :wolves))) | ||||||||||||
Format one row in the state of a world for printing. - | (defn- format-world-row - [row] - (apply str - (map format-cell row))) | ||||||||||||
Print the current state of this world, and return nil. - -
| (defn print-world - [world] - (println) - (dorun - (map - #(println - (format-world-row %)) - world)) - nil) | ||||||||||||