Minor changes

This commit is contained in:
Simon Brooke 2014-06-30 22:37:37 +01:00
parent 977947d4b0
commit 0dc6aab59d
4 changed files with 30 additions and 59 deletions

View file

@ -1,5 +1,5 @@
(defproject mw-engine "0.1.0-SNAPSHOT" (defproject mw-engine "0.1.0-SNAPSHOT"
:description "FIXME: write description" :description "Cellular automaton world builder."
:url "http://example.com/FIXME" :url "http://example.com/FIXME"
:license {:name "Eclipse Public License" :license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"} :url "http://www.eclipse.org/legal/epl-v10.html"}

View file

@ -1,5 +1,6 @@
(ns mw-engine.core (ns mw-engine.core
(:use mw-engine.world (:require mw-engine.world
mw-engine.natural-rules
mw-engine.utils)) mw-engine.utils))
;; every rule is a function of two arguments, a cell and a world. If the rule ;; every rule is a function of two arguments, a cell and a world. If the rule
@ -8,60 +9,6 @@
;; ;;
;; Rules are applied in turn until one matches. ;; Rules are applied in turn until one matches.
(def treeline 10)
(def natural-rules
(list
;; Randomly, birds plant tree seeds into pasture.
(fn [cell world] (cond (and (= (:state cell) :pasture)(< (rand 10) 1))(merge cell {:state :scrub})))
;; Scrub below the treeline grows gradually into forest
(fn [cell world]
(cond (and
(= (:state cell) :scrub)
(< (:altitude cell) treeline))
(merge cell {:state :scrub2})))
(fn [cell world] (cond (= (:state cell) :scrub2) (merge cell {:state :forest})))
;; Forest on fertile land at low altitude grows to climax
(fn [cell world]
(cond
(and
(= (:state cell) :forest)
(> (:fertility cell) 10))
(merge cell {:state :climax})))
;; Climax forest occasionally catches fire (e.g. lightning strikes)
(fn [cell world] (cond (and (= (:state cell) :climax)(< (rand 10) 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 scrub, otherwise grassland.
(fn [cell world]
(cond
(and (= (:state cell) :waste)
(not
(empty?
(flatten
(list
(get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub2)
(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 :scrub})))
(fn [cell world]
(cond (= (:state cell) :waste)
(merge cell {:state :pasture})))
;; Forest increases soil fertility
(fn [cell world]
(cond (member? (:state cell) '(:forest :climax))
(merge cell {:fertility (+ (:fertility cell) 1)})))
))
(defn transform-cell (defn transform-cell
"Derive a cell from this cell of this world by applying these rules." "Derive a cell from this cell of this world by applying these rules."
[cell world rules] [cell world rules]
@ -96,3 +43,10 @@
[world rules generations] [world rules generations]
(let [state (list world rules)] (let [state (list world rules)]
(take generations (iterate transform-world-state state)))) (take generations (iterate transform-world-state state))))
(defn animate-world
[world rules generations]
(let [state (list world rules)]
(dorun
(take generations (iterate transform-world-state state)))
nil))

View file

@ -2,4 +2,10 @@
(defn member? (defn member?
"True if elt is a member of col." "True if elt is a member of col."
[elt col] (some #(= elt %) col)) [elt col] (some #(= elt %) col))
(defn population [cell species]
"Return the population of this species in this cell.
Species is assumed to be a keyword whose value in a cell should be an
integer."
(or (get cell species) 0))

View file

@ -1,4 +1,5 @@
(ns mw-engine.world (ns mw-engine.world
(:use mw-engine.utils)
(:require [clojure.math.combinatorics :as combo])) (:require [clojure.math.combinatorics :as combo]))
(defn make-cell (defn make-cell
@ -39,12 +40,19 @@
(nth (nth world y) x))) (nth (nth world y) x)))
(defn get-neighbours (defn get-neighbours
([world x y depth]
"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."
[world x y depth]
(map #(get-cell world (first %) (first (rest %))) (map #(get-cell world (first %) (first (rest %)))
(combo/cartesian-product (combo/cartesian-product
(range (- x depth) (+ x depth)) (range (- x depth) (+ x depth))
(range (- y depth) (+ y depth))))) (range (- y depth) (+ y depth)))))
([world cell depth]
"Get the neighbours to distance depth of this cell in this world."
(get-neighbours world (:x cell) (:y cell) depth))
([world cell]
"Get the immediate neighbours of this cell in this world"
(get-neighbours world cell 1)))
(defn get-neighbours-with-state (defn get-neighbours-with-state
"Get the neighbours to distance depth of the cell at x, y in this world which "Get the neighbours to distance depth of the cell at x, y in this world which
@ -63,7 +71,10 @@
"Format one row in the state of a world for printing" "Format one row in the state of a world for printing"
[row] [row]
(apply str (apply str
(map #(format "%10s" (truncate-state % 10)) row))) (map #(format "%10s(%d/%d)"
(truncate-state % 10)
(population % :deer)
(population % :wolves)) row)))
(defn print-world (defn print-world
"Print the current state of this world, and return nil" "Print the current state of this world, and return nil"