Release 0.1.1, remove windows/osx release targets
[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 (clnl-nvm:agent-value :pcolor) (clnl-nvm:one-of (list (clnl-nvm:lookup-color :green) (clnl-nvm:lookup-color :brown))))
110     (if (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
111      (setf (clnl-nvm:agent-value :countdown) grass-regrowth-time)
112      (setf (clnl-nvm:agent-value :countdown) (clnl-nvm:random grass-regrowth-time))))))
113  (clnl-nvm:set-default-shape :sheep "sheep")
114  (clnl-nvm:create-turtles initial-number-sheep :sheep
115   (lambda ()
116    (setf (clnl-nvm:agent-value :color) (clnl-nvm:lookup-color :white))
117    (setf (clnl-nvm:agent-value :size) 1.5d0)
118    (setf (clnl-nvm:agent-value :label-color) (- (clnl-nvm:lookup-color :blue) 2.0d0))
119    (setf (clnl-nvm:agent-value :energy) (clnl-nvm:random (* 2.0d0 sheep-gain-from-food)))
120                             (clnl-nvm:setxy
121                              (clnl-nvm:random-xcor)
122                              (clnl-nvm:random-ycor))))
123  (clnl-nvm:set-default-shape :wolves "wolf")
124  (clnl-nvm:create-turtles initial-number-wolves :wolves
125   (lambda ()
126    (setf (clnl-nvm:agent-value :color) (clnl-nvm:lookup-color :black))
127    (setf (clnl-nvm:agent-value :size) 2.0d0)
128    (setf (clnl-nvm:agent-value :energy) (clnl-nvm:random (* 2.0d0 wolf-gain-from-food)))
129    (clnl-nvm:setxy (clnl-nvm:random-xcor) (clnl-nvm:random-ycor))))
130  (display-labels)
131  (setf grass (clnl-nvm:count (clnl-nvm:with (clnl-nvm:patches) (lambda () (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))))))
132  (clnl-nvm:reset-ticks)
133  :undefined)
134
135 (defun go ()
136  (clnl-nvm:with-stop-handler
137   (when (not (> (clnl-nvm:count (clnl-nvm:turtles)) 0)) (clnl-nvm:stop))
138   (clnl-nvm:ask :sheep
139    (lambda ()
140     (move)
141     (when grass?  (setf (clnl-nvm:agent-value :energy) (- (clnl-nvm:agent-value :energy) 1.0d0)) (eat-grass))
142     (death)
143     (reproduce-sheep)))
144   (clnl-nvm:ask :wolves
145    (lambda ()
146     (move)
147     (setf (clnl-nvm:agent-value :energy) (- (clnl-nvm:agent-value :energy) 1.0d0))
148     (catch-sheep)
149     (death)
150     (reproduce-wolves)))
151   (when grass?  (clnl-nvm:ask (clnl-nvm:patches) (lambda () (grow-grass))))
152   (setf grass (clnl-nvm:count (clnl-nvm:with (clnl-nvm:patches) (lambda () (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))))))
153   (clnl-nvm:tick) (display-labels)
154   :undefined))
155
156 (defun move ()
157  (clnl-nvm:turn-right (clnl-nvm:random 50.0d0))
158  (clnl-nvm:turn-left (clnl-nvm:random 50.0d0))
159  (clnl-nvm:forward 1.0d0)
160  :undefined)
161
162 (defun eat-grass ()
163  (when (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
164   (setf (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :brown))
165   (setf (clnl-nvm:agent-value :energy) (+ (clnl-nvm:agent-value :energy) sheep-gain-from-food)))
166  :undefined)
167
168 (defun reproduce-sheep ()
169  (when (< (clnl-nvm:random-float 100.0d0) sheep-reproduce)
170   (setf (clnl-nvm:agent-value :energy) (/ (clnl-nvm:agent-value :energy) 2.0d0))
171   (clnl-nvm:hatch 1.0d0
172    (lambda ()
173     (clnl-nvm:turn-right (clnl-nvm:random-float 360.0d0))
174     (clnl-nvm:forward 1.0d0))))
175  :undefined)
176
177 (defun reproduce-wolves ()
178  (when (< (clnl-nvm:random-float 100.0d0) wolf-reproduce)
179   (setf (clnl-nvm:agent-value :energy) (/ (clnl-nvm:agent-value :energy) 2.0d0))
180   (clnl-nvm:hatch 1.0d0
181    (lambda ()
182     (clnl-nvm:turn-right (clnl-nvm:random-float 360.0d0))
183     (clnl-nvm:forward 1.0d0))))
184  :undefined)
185
186 (defun catch-sheep ()
187  (let*
188   ((prey (clnl-nvm:one-of (clnl-nvm:turtles-here :sheep))))
189   (when (not (equalp prey :nobody))
190    (clnl-nvm:ask prey (lambda () (clnl-nvm:die)))
191    (setf (clnl-nvm:agent-value :energy) (+ (clnl-nvm:agent-value :energy) wolf-gain-from-food))))
192  :undefined)
193
194 (defun death ()
195  (when (< (clnl-nvm:agent-value :energy) 0.0d0) (clnl-nvm:die))
196  :undefined)
197
198 (defun grow-grass ()
199  (when (equalp (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :brown))
200   (if (<= (clnl-nvm:agent-value :countdown) 0.0d0)
201    (progn
202     (setf (clnl-nvm:agent-value :pcolor) (clnl-nvm:lookup-color :green))
203     (setf (clnl-nvm:agent-value :countdown) grass-regrowth-time))
204    (setf (clnl-nvm:agent-value :countdown) (- (clnl-nvm:agent-value :countdown) 1.0d0))))
205  :undefined)
206
207 (defun display-labels ()
208  (clnl-nvm:ask (clnl-nvm:turtles) (lambda () (setf (clnl-nvm:agent-value :label) "")))
209  (when show-energy?
210   (clnl-nvm:ask :wolves
211    (lambda () (setf (clnl-nvm:agent-value :label) (ffloor (+ (clnl-nvm:agent-value :energy) 0.5d0)))))
212   (when grass?
213    (clnl-nvm:ask :sheep
214     (lambda () (setf (clnl-nvm:agent-value :label) (ffloor (+ (clnl-nvm:agent-value :energy) 0.5d0)))))))
215  :undefined)
216
217 (defun boot ()
218  (clnl-random:set-seed 15)
219  (clnl-nvm:create-world :dims
220                         '(:xmin -25 :xmax 25 :ymin -25 :ymax 25 :patch-size 9.0d0)
221                         :globals
222                         (list
223                          (list :initial-number-sheep (lambda () initial-number-sheep))
224                          (list :sheep-gain-from-food (lambda () sheep-gain-from-food))
225                          (list :sheep-reproduce (lambda () sheep-reproduce))
226                          (list :initial-number-wolves (lambda () initial-number-wolves))
227                          (list :wolf-gain-from-food (lambda () wolf-gain-from-food))
228                          (list :wolf-reproduce (lambda () wolf-reproduce))
229                          (list :grass? (lambda () grass?))
230                          (list :grass-regrowth-time (lambda () grass-regrowth-time))
231                          (list :show-energy? (lambda () show-energy?))
232                          (list :grass (lambda () grass)))
233                         :turtles-own-vars '(:energy) :patches-own-vars '(:countdown) :breeds '(:sheep :wolves))
234  (clnl-interface:initialize :dims '(:xmin -25 :xmax 25 :ymin -25 :ymax 25 :patch-size 9.0d0)))
235 ```