Update documentation after 0.1.1 release
[clnl] / docs / CLNL-as-a-lisp-library.md
1 One way to use CLNL is as a library loaded into a common lisp instance.  Once you have the source release from the releases page loaded up into however you configure asdf, you can start writing models using the clnl-* packages.  However, a good place to begin is by letting CLNL convert a model to common lisp so you can start from a known place.
2
3 Everything that the generated code could use is external in the proper packages, so that you could optionally write the code in pure common lisp without using the generator.
4
5 ## Converting Wolf Sheep Predation as a headless model
6
7 This code creates the wolf sheep common lisp file:
8
9 ```lisp
10 (asdf:load-system :clnl)
11
12 (with-open-file (out "wolfsheep.lisp" :direction :output)
13  (mapcar
14   (lambda (form) (pprint form out))
15   (with-open-file (str "resources/clnl/models/Wolf Sheep Predation.nlogo")
16    (clnl:nlogo->lisp str :wolfsheep 'boot))))
17 ```
18
19 From there, you can boot the model with
20
21 ```
22 sbcl --eval '(asdf:load-system :clnl)' --load 'wolfsheep.lisp' --eval '(wolfsheep::boot)'
23 ```
24
25 Then you can run functions headlessly from the REPL with:
26
27 ```lisp
28 (wolfsheep::setup)
29
30 (wolfsheep::go)
31 ```
32 You can then mix common lisp forms and functions from your model
33
34 ```lisp
35 (loop :repeat 50 :do (wolfsheep::go))
36 ```
37
38 Then you can start doing headless analysis on your model by using clnl-nvm primitives
39
40 ```lisp
41 (wolfsheep::setup)
42
43 (loop
44  :repeat 50 :do (wolfsheep::go)
45  :collect (list (clnl-nvm:count :sheep) (clnl-nvm:count :wolves)))
46 ```
47
48 ## Wolf Sheep as a non headless model
49
50 If, however, you'd rather run with the interface as well, you would use
51
52 ```lisp
53 (asdf:load-system :clnl)
54
55 (with-open-file (out "wolfsheep.lisp" :direction :output)
56  (mapcar
57   (lambda (form) (pprint form out))
58   (with-open-file (str "resources/clnl/models/Wolf Sheep Predation.nlogo")
59    (clnl:nlogo->lisp str :wolfsheep 'boot :initialize-interface t))))
60 ```
61
62 Then load up the model as such:
63
64 ```
65 sbcl --eval '(asdf:load-system :clnl)' --load 'wolfsheep.lisp' --eval '(wolfsheep::boot)'
66 ```
67
68 Then start the interface
69
70 ```lisp
71 (sb-thread:make-thread #'clnl-interface:run)
72 ```
73
74 Then you can do your normal model functions
75
76 ```lisp
77 (wolfsheep::setup)
78
79 (wolfsheep::go)
80 ```
81
82 ## Wolf sheep as a common lisp file after generation
83
84 The following is a hand edited modification of wolf sheep to remove unnecessary things, and clean it up
85
86 ```lisp
87
88 (defpackage :wolfsheep (:use :common-lisp) (:shadow :go))
89 (in-package :wolfsheep)
90
91 (defvar initial-number-sheep 100.0d0)
92 (defvar sheep-gain-from-food 4.0d0)
93 (defvar sheep-reproduce 4.0d0)
94 (defvar initial-number-wolves 50.0d0)
95 (defvar wolf-gain-from-food 20.0d0)
96 (defvar wolf-reproduce 5.0d0)
97 (defvar grass? nil)
98 (defvar grass-regrowth-time 30.0d0)
99 (defvar show-energy? nil)
100 (defvar grass 0.0d0)
101
102 (defun setup ()
103  (clnl-nvm:clear-all)
104  (clnl-nvm:ask (clnl-nvm:patches)
105   (lambda () (setf (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))))
106  (when grass?
107   (clnl-nvm:ask (clnl-nvm:patches)
108    (lambda ()
109     (setf
110      (clnl-nvm:agent-value :pcolor)
111      (clnl-nvm:one-of (list (clnl-nvm:lookup-color :green) (clnl-nvm:lookup-color :brown))))
112     (if (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
113      (setf (clnl-nvm:agent-value :countdown) grass-regrowth-time)
114      (setf (clnl-nvm:agent-value :countdown) (clnl-nvm:random grass-regrowth-time))))))
115  (clnl-nvm:set-default-shape :sheep "sheep")
116  (clnl-nvm:create-turtles initial-number-sheep :sheep
117   (lambda ()
118    (setf (clnl-nvm:agent-value :color) (clnl-nvm:lookup-color :white))
119    (setf (clnl-nvm:agent-value :size) 1.5d0)
120    (setf (clnl-nvm:agent-value :label-color) (- (clnl-nvm:lookup-color :blue) 2.0d0))
121    (setf (clnl-nvm:agent-value :energy) (clnl-nvm:random (* 2.0d0 sheep-gain-from-food)))
122                             (clnl-nvm:setxy
123                              (clnl-nvm:random-xcor)
124                              (clnl-nvm:random-ycor))))
125  (clnl-nvm:set-default-shape :wolves "wolf")
126  (clnl-nvm:create-turtles initial-number-wolves :wolves
127   (lambda ()
128    (setf (clnl-nvm:agent-value :color) (clnl-nvm:lookup-color :black))
129    (setf (clnl-nvm:agent-value :size) 2.0d0)
130    (setf (clnl-nvm:agent-value :energy) (clnl-nvm:random (* 2.0d0 wolf-gain-from-food)))
131    (clnl-nvm:setxy (clnl-nvm:random-xcor) (clnl-nvm:random-ycor))))
132  (display-labels)
133  (setf
134   grass
135   (clnl-nvm:count
136    (clnl-nvm:with
137     (clnl-nvm:patches)
138     (lambda () (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))))))
139  (clnl-nvm:reset-ticks)
140  :undefined)
141
142 (defun go ()
143  (clnl-nvm:with-stop-handler
144   (when (not (> (clnl-nvm:count (clnl-nvm:turtles)) 0)) (clnl-nvm:stop))
145   (clnl-nvm:ask :sheep
146    (lambda ()
147     (move)
148     (when grass?  (setf (clnl-nvm:agent-value :energy) (- (clnl-nvm:agent-value :energy) 1.0d0)) (eat-grass))
149     (death)
150     (reproduce-sheep)))
151   (clnl-nvm:ask :wolves
152    (lambda ()
153     (move)
154     (setf (clnl-nvm:agent-value :energy) (- (clnl-nvm:agent-value :energy) 1.0d0))
155     (catch-sheep)
156     (death)
157     (reproduce-wolves)))
158   (when grass?  (clnl-nvm:ask (clnl-nvm:patches) (lambda () (grow-grass))))
159   (setf
160    grass
161    (clnl-nvm:count
162     (clnl-nvm:with
163      (clnl-nvm:patches)
164      (lambda () (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))))))
165   (clnl-nvm:tick) (display-labels)
166   :undefined))
167
168 (defun move ()
169  (clnl-nvm:turn-right (clnl-nvm:random 50.0d0))
170  (clnl-nvm:turn-left (clnl-nvm:random 50.0d0))
171  (clnl-nvm:forward 1.0d0)
172  :undefined)
173
174 (defun eat-grass ()
175  (when (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
176   (setf (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :brown))
177   (setf (clnl-nvm:agent-value :energy) (+ (clnl-nvm:agent-value :energy) sheep-gain-from-food)))
178  :undefined)
179
180 (defun reproduce-sheep ()
181  (when (< (clnl-nvm:random-float 100.0d0) sheep-reproduce)
182   (setf (clnl-nvm:agent-value :energy) (/ (clnl-nvm:agent-value :energy) 2.0d0))
183   (clnl-nvm:hatch 1.0d0
184    (lambda ()
185     (clnl-nvm:turn-right (clnl-nvm:random-float 360.0d0))
186     (clnl-nvm:forward 1.0d0))))
187  :undefined)
188
189 (defun reproduce-wolves ()
190  (when (< (clnl-nvm:random-float 100.0d0) wolf-reproduce)
191   (setf (clnl-nvm:agent-value :energy) (/ (clnl-nvm:agent-value :energy) 2.0d0))
192   (clnl-nvm:hatch 1.0d0
193    (lambda ()
194     (clnl-nvm:turn-right (clnl-nvm:random-float 360.0d0))
195     (clnl-nvm:forward 1.0d0))))
196  :undefined)
197
198 (defun catch-sheep ()
199  (let*
200   ((prey (clnl-nvm:one-of (clnl-nvm:turtles-here :sheep))))
201   (when (not (equalp prey :nobody))
202    (clnl-nvm:ask prey (lambda () (clnl-nvm:die)))
203    (setf (clnl-nvm:agent-value :energy) (+ (clnl-nvm:agent-value :energy) wolf-gain-from-food))))
204  :undefined)
205
206 (defun death ()
207  (when (< (clnl-nvm:agent-value :energy) 0.0d0) (clnl-nvm:die))
208  :undefined)
209
210 (defun grow-grass ()
211  (when (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :brown))
212   (if (<= (clnl-nvm:agent-value :countdown) 0.0d0)
213    (progn
214     (setf (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
215     (setf (clnl-nvm:agent-value :countdown) grass-regrowth-time))
216    (setf (clnl-nvm:agent-value :countdown) (- (clnl-nvm:agent-value :countdown) 1.0d0))))
217  :undefined)
218
219 (defun display-labels ()
220  (clnl-nvm:ask (clnl-nvm:turtles) (lambda () (setf (clnl-nvm:agent-value :label) "")))
221  (when show-energy?
222   (clnl-nvm:ask :wolves
223    (lambda () (setf (clnl-nvm:agent-value :label) (ffloor (+ (clnl-nvm:agent-value :energy) 0.5d0)))))
224   (when grass?
225    (clnl-nvm:ask :sheep
226     (lambda () (setf (clnl-nvm:agent-value :label) (ffloor (+ (clnl-nvm:agent-value :energy) 0.5d0)))))))
227  :undefined)
228
229 (defun boot ()
230  (clnl-random:set-seed 15)
231  (clnl-nvm:create-world :dims
232                         '(:xmin -25 :xmax 25 :ymin -25 :ymax 25 :patch-size 9.0d0)
233                         :globals
234                         (list
235                          (list :initial-number-sheep (lambda () initial-number-sheep))
236                          (list :sheep-gain-from-food (lambda () sheep-gain-from-food))
237                          (list :sheep-reproduce (lambda () sheep-reproduce))
238                          (list :initial-number-wolves (lambda () initial-number-wolves))
239                          (list :wolf-gain-from-food (lambda () wolf-gain-from-food))
240                          (list :wolf-reproduce (lambda () wolf-reproduce))
241                          (list :grass? (lambda () grass?))
242                          (list :grass-regrowth-time (lambda () grass-regrowth-time))
243                          (list :show-energy? (lambda () show-energy?))
244                          (list :grass (lambda () grass)))
245                         :turtles-own-vars '(:energy) :patches-own-vars '(:countdown) :breeds '(:sheep :wolves))
246  (clnl-interface:initialize :dims '(:xmin -25 :xmax 25 :ymin -25 :ymax 25 :patch-size 9.0d0)))
247 ```