001  (ns ^{:doc "A set of MicroWorld rules describing a simplified natural ecosystem.
002  
003              Since the completion of the rule language this is more or less obsolete -
004              there are still a few things that you can do with rules written in Clojure
005              that you can't do in the rule language, but not many and I doubt they're
006              important. "
007         :author " Simon Brooke "}
008    mw-engine.natural-rules
009    (:require [mw-engine.utils :refer [get-int get-neighbours get-neighbours-with-state member?]]))
010  
011  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
012  ;;;;
013  ;;;; mw-engine: the state/transition engine of MicroWorld.
014  ;;;;
015  ;;;; This program is free software; you can redistribute it and/or
016  ;;;; modify it under the terms of the GNU General Public License
017  ;;;; as published by the Free Software Foundation; either version 2
018  ;;;; of the License, or (at your option) any later version.
019  ;;;;
020  ;;;; This program is distributed in the hope that it will be useful,
021  ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
022  ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
023  ;;;; GNU General Public License for more details.
024  ;;;;
025  ;;;; You should have received a copy of the GNU General Public License
026  ;;;; along with this program; if not, write to the Free Software
027  ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
028  ;;;; USA.
029  ;;;;
030  ;;;; Copyright (C) 2014 Simon Brooke
031  ;;;;
032  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
033  
034  ;; treeline at arbitrary altitude.
035  (def treeline 150)
036  
037  ;; waterline also at arbitrary altitude.
038  (def waterline 10)
039  
040  ;; and finally snowline is also arbitrary.
041  (def snowline 200)
042  
043  ;; Rare chance of lightning strikes
044  (def lightning-probability 500)
045  
046  ;; rules describing vegetation
047  (def vegetation-rules
048    (list
049      ;; Randomly, birds plant tree seeds into grassland.
050      (fn [cell _] (cond (and (= (:state cell) :grassland)(< (rand 10) 1))(merge cell {:state :heath})))
051      ;; heath below the treeline grows gradually into forest, providing browsing pressure is not to high
052      (fn [cell _]
053        (cond (and
054                (= (:state cell) :heath)
055                ;; browsing limit really ought to vary with soil fertility, but...
056                (< (+ (get-int cell :deer)(get-int cell :sheep)) 6)
057                (< (get-int cell :altitude) treeline))
058          (merge cell {:state :scrub})))
059      (fn [cell _] (cond (= (:state cell) :scrub) (merge cell {:state :forest})))
060      ;; Forest on fertile land grows to climax
061      (fn [cell _]
062        (cond
063          (and
064            (= (:state cell) :forest)
065            (> (get-int cell :fertility) 10))
066          (merge cell {:state :climax})))
067      ;; Climax forest occasionally catches fire (e.g. lightning strikes)
068      (fn [cell _] (cond (and (= (:state cell) :climax)(< (rand lightning-probability) 1)) (merge cell {:state :fire})))
069      ;; Climax forest neighbouring fires is likely to catch fire
070      (fn [cell world]
071        (cond
072          (and (= (:state cell) :climax)
073               (< (rand 3) 1)
074               (not (empty? (get-neighbours-with-state world (:x cell) (:y cell) 1 :fire))))
075          (merge cell {:state :fire})))
076      ;; After fire we get waste
077      (fn [cell _] (cond (= (:state cell) :fire) (merge cell {:state :waste})))
078      ;; And after waste we get pioneer species; if there's a woodland seed
079      ;; source, it's going to be heath, otherwise grassland.
080      (fn [cell world]
081        (cond
082          (and (= (:state cell) :waste)
083               (not
084                 (empty?
085                   (flatten
086                     (list
087                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :scrub)
088                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :forest)
089                       (get-neighbours-with-state world (:x cell) (:y cell) 1 :climax))))))
090          (merge cell {:state :heath})))
091      (fn [cell _]
092        (cond (= (:state cell) :waste)
093          (merge cell {:state :grassland})))
094      ;; Forest increases soil fertility
095      (fn [cell _]
096        (cond (member? (:state cell) '(:forest :climax))
097          (merge cell {:fertility (+ (get-int cell :fertility) 1)})))))
098  
099  
100  ;; rules describing herbivore behaviour
101  (def herbivore-rules
102    (list
103      ;; if there are too many deer for the fertility of the area to sustain,
104      ;; some die or move on.
105      (fn [cell _]
106        (cond (> (get-int cell :deer) (get-int cell :fertility))
107          (merge cell {:deer (get-int cell :fertility)})))
108      ;; deer arrive occasionally at the edge of the map.
109      (fn [cell world]
110        (cond (and (< (count (get-neighbours world cell)) 8)
111                   (< (rand 50) 1)
112                   (> (get-int cell :fertility) 0)
113                   (= (get-int cell :deer) 0))
114          (merge cell {:deer 2})))
115      ;; deer gradually spread through the world by breeding or migrating.
116      (fn [cell world]
117        (let [n (apply + (map #(get-int % :deer) (get-neighbours world cell)))]
118          (cond (and
119                  (> (get-int cell :fertility) 0)
120                  (= (get-int cell :deer) 0)
121                  (>= n 2))
122            (merge cell {:deer (int (/ n 2))}))))
123      ;; deer breed.
124      (fn [cell _]
125        (cond
126          (>= (get-int cell :deer) 2)
127          (merge cell {:deer (int (* (:deer cell) 2))})))))
128  
129    ;; rules describing predator behaviour
130    (def predator-rules
131      (list
132       ;; wolves eat deer
133       (fn [cell _]
134        (cond
135         (>= (get-int cell :wolves) 1)
136         (merge cell {:deer (max 0 (- (get-int cell :deer) (get-int cell :wolves)))})))
137  ;;      ;; not more than eight wolves in a pack, for now (hack because wolves are not dying)
138  ;;      (fn [cell world]
139  ;;        (cond (> (get-int cell :wolves) 8) (merge cell {:wolves 8})))
140      ;; if there are not enough deer to sustain the get-int of wolves,
141      ;; some wolves die or move on. (doesn't seem to be working?)
142      (fn [cell _]
143         (cond (> (get-int cell :wolves) (get-int cell :deer))
144           (merge cell {:wolves 0})))
145      ;; wolves arrive occasionally at the edge of the map.
146      (fn [cell world]
147        (cond (and (< (count (get-neighbours world cell)) 8)
148                   (< (rand 50) 1)
149                   (not (= (:state cell) :water))
150                   (= (get-int cell :wolves) 0))
151          (merge cell {:wolves 2})))
152      ;; wolves gradually spread through the world by breeding or migrating.
153      (fn [cell world]
154        (let [n (apply + (map #(get-int % :wolves) (get-neighbours world cell)))]
155          (cond (and
156                  (not (= (:state cell) :water))
157                  (= (get-int cell :wolves) 0)
158                  (>= n 2))
159            (merge cell {:wolves 2}))))
160      ;; wolves breed.
161      (fn [cell _]
162        (cond
163          (>= (get-int cell :wolves) 2)
164          (merge cell {:wolves (int (* (:wolves cell) 2))})))))
165  
166  
167    ;; rules which initialise the world
168    (def init-rules
169      (list
170       ;; below the waterline, we have water.
171       (fn [cell _]
172         (cond (and (= (:state cell) :new) (< (get-int cell :altitude) waterline)) (merge cell {:state :water})))
173       ;; above the snowline, we have snow.
174       (fn [cell _]
175         (cond (and (= (:state cell) :new) (> (get-int cell :altitude) snowline)) (merge cell {:state :snow})))
176       ;; in between, we have a wasteland.
177       (fn [cell _] (cond (= (:state cell) :new) (merge cell {:state :grassland})))))
178  
179  
180  (def natural-rules (flatten
181                      (list
182                       vegetation-rules
183                       herbivore-rules
184                       predator-rules)))