44 lines
1.4 KiB
Plaintext
44 lines
1.4 KiB
Plaintext
|
(ns jeremy-website.l-system)
|
||
|
|
||
|
;; TODO support context-sensitive grammers? This is where a production
|
||
|
;; rule can apply only if the symbol in question occurs between
|
||
|
;; specific other symbols
|
||
|
|
||
|
(defn rules-for-symbol
|
||
|
[symbol rules]
|
||
|
(filter #(= (:predecessor %) symbol) rules))
|
||
|
|
||
|
(defn choose-rule [random-fn rules]
|
||
|
(let [random (random-fn)
|
||
|
iter-fn (fn [[rule & rules] current-prob]
|
||
|
(cond
|
||
|
(nil? rule) nil
|
||
|
(< random (+ current-prob
|
||
|
(:probability rule))) rule
|
||
|
:else (recur rules (+ current-prob
|
||
|
(:probability rule)))))
|
||
|
selected (iter-fn rules 0)]
|
||
|
(or selected (first rules))))
|
||
|
|
||
|
(defn apply-rules
|
||
|
[rules random-fn symbol]
|
||
|
(let [rules-for-symbol (rules-for-symbol symbol rules)
|
||
|
selected-rule (choose-rule random-fn rules-for-symbol)]
|
||
|
(if selected-rule
|
||
|
(:successor selected-rule)
|
||
|
[symbol])))
|
||
|
|
||
|
(defn step
|
||
|
"Applies the l-system rules once"
|
||
|
[{:keys [rules state random-fn] :as l-system}]
|
||
|
(let [new-state (mapcat (partial apply-rules rules random-fn) state)]
|
||
|
(assoc l-system :state (vec new-state))))
|
||
|
|
||
|
(defn instantiate
|
||
|
"Instantiates a new L-system"
|
||
|
[{:keys [rules axiom random-fn] :or {random-fn rand}}]
|
||
|
{:rules rules
|
||
|
:axiom (vec axiom)
|
||
|
:state (vec axiom)
|
||
|
:random-fn random-fn})
|