1 (in-package #:clnl-nvm)
3 ; Implementations of all the things the nvm can do.
10 VALUE: a NetLogo value
15 A command that prints the given NetLogo value to the command center.
17 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#show"
18 (format t "Showing: ~A~%" (dump-object value)))
20 (defun lookup-color (color)
21 "LOOKUP-COLOR COLOR => COLOR-NUMBER
25 COLOR: a symbol representing a color
26 COLOR-NUMBER: the NetLogo color integer
30 Returns the number used to represent colors in NetLogo.
32 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#Constants"
51 (defun create-turtle (breed &optional base-turtle)
53 ((breed (or breed (and base-turtle (turtle-breed base-turtle)) :turtles))
54 (new-turtle (make-turtle
55 :who (coerce *current-id* 'double-float)
56 :color (if base-turtle
57 (turtle-color base-turtle)
58 (coerce (+ 5 (* 10 (clnl-random:next-int 14))) 'double-float))
59 :heading (if base-turtle
60 (turtle-heading base-turtle)
61 (coerce (clnl-random:next-int 360) 'double-float))
63 :shape (breed-default-shape breed)
64 :xcor (if base-turtle (turtle-xcor base-turtle) 0d0)
65 :ycor (if base-turtle (turtle-ycor base-turtle) 0d0))))
67 ((patch (patch-at (turtle-xcor new-turtle) (turtle-ycor new-turtle))))
68 (setf (patch-turtles patch) (nconc (patch-turtles patch) (list new-turtle))))
69 (setf *turtles* (nconc *turtles* (list new-turtle)))
78 RESULT: undefined, commands don't return
82 The turtle or link dies
84 A dead agent ceases to exist. The effects of this include:
85 - The agent will not execute any further code.
86 - The agent will disappear from any agentsets it was in, reducing the size of those agentsets by one.
87 - Any variable that was storing the agent will now instead have nobody in it.
88 - If the dead agent was a turtle, every link connected to it also dies.
89 - If the observer was watching or following the agent, the observer's perspective resets.
91 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#die"
92 (when (not (turtle-p *self*)) (error "Gotta call die in turtle scope, dude (~A)" *self*))
93 (setf (turtle-who *self*) -1)
94 (setf *turtles* (remove *self* *turtles*)))
97 "PATCHES => ALL-PATCHES
101 ALL-PATCHES: a NetLogo agentset, all patches
105 Reports the agentset consisting of all the patches.
107 This agentset is special in that it represents the living patches
108 each time it's used, so changes depending on the state of the engine.
110 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#patches"
114 "TURTLES => ALL-TURTLES
116 ARGUMENTS AND VALUES:
118 ALL-TURTLES: a NetLogo agentset, all turtles
122 Reports the agentset consisting of all the turtles.
124 This agentset is special in that it represents the living turtles
125 each time it's used, so changes depending on the state of the engine.
127 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#turtles"
130 (defun turtles-here (&optional breed)
131 "TURTLES-HERE => TURTLES
133 ARGUMENTS AND VALUES:
139 Returns the agentset consisting of all the turtles sharing the patch
140 with the agent in by *self*
142 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#turtles-here"
143 (when (not (turtle-p *self*)) (error "Gotta call turtles-here with a turtle"))
145 ((patch-turtles (patch-turtles (patch-at (turtle-xcor *self*) (turtle-ycor *self*)))))
147 (if breed (remove breed patch-turtles :key #'turtle-breed :test-not #'eql) patch-turtles)
148 (or breed :turtles))))
150 (defun ask (agent-or-agentset fn)
151 "ASK AGENT-OR-AGENTSET FN => RESULT
153 AGENT-OR-AGENTSET: AGENT | AGENTSET
155 ARGUMENTS AND VALUES:
157 FN: a function, run on each agent
158 RESULT: undefined, commands don't return
159 AGENT: a NetLogo agent
160 AGENTSET: a NetLogo agentset
164 ASK is equivalent to ask in NetLogo.
166 The specified AGENTSET or AGENT runs the given FN. In the case of an
167 AGENTSET, the order in which the agents are run is random each time,
168 and only agents that are in the set at the beginning of the call.
170 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#ask"
172 ((agentset-p agent-or-agentset)
174 ((iter (shufflerator (agentset-list agent-or-agentset))))
176 :for agent := (funcall iter)
178 :do (let ((*myself* *self*) (*self* agent)) (with-stop-handler (funcall fn))))))
179 ((agent-p agent-or-agentset)
180 (let ((*myself* *self*) (*self* agent-or-agentset)) (with-stop-handler (funcall fn))))
182 (error "Ask requires an agentset or agent but got: ~A" agent-or-agentset))))
184 (defun count (agentset)
187 ARGUMENTS AND VALUES:
189 AGENTSET: a NetLogo agentset
194 COUNT is equivalent to count in NetLogo. Returns N, the number of
197 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#count"
198 (coerce (length (agentset-list agentset)) 'double-float))
203 ARGUMENTS AND VALUES:
209 Clears ticks, turtles, patches, globals (unimplemented).
211 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#clear-all"
219 ARGUMENTS AND VALUES:
225 As of yet, this does nothing. A placeholder method for forced dipslay
226 updates from the engine.
228 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#display"
234 ARGUMENTS AND VALUES:
240 Returns from the current stop block, which will halt the currently running
241 thing, be that the program, current ask block, or procedure. Stop has odd
242 semantics that are best gleaned from the actual NetLogo manual.
244 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#stop"
245 (error (make-condition 'stop)))
247 (defun of (fn agent-or-agentset)
248 "OF FN AGENT-OR-AGENTSET => RESULT
250 AGENT-OR-AGENTSET: AGENT | AGENTSET
251 RESULT: RESULT-LIST | RESULT-VALUE
253 ARGUMENTS AND VALUES:
255 FN: a function, run on each agent
256 AGENT: a NetLogo agent
257 AGENTSET: a NetLogo agentset
259 RESULT-VALUE: a single value
263 OF is equivalent to of in NetLogo.
265 The specified AGENTSET or AGENT runs the given FN. In the case of an
266 AGENTSET, the order in which the agents are run is random each time,
267 and only agents that are in the set at the beginning of the call.
269 RESULT-LIST is returned when the input is an AGENTSET, but RESULT-VALUE
270 is returned when only passed an AGENT.
272 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#of"
274 ((agentset-p agent-or-agentset)
276 ((iter (shufflerator (agentset-list agent-or-agentset))))
278 :for agent := (funcall iter)
280 :collect (let ((*myself* *self*) (*self* agent)) (funcall fn)))))
281 ((agent-p agent-or-agentset)
282 (let ((*myself* *self*) (*self* agent-or-agentset)) (funcall fn)))
284 (error "Of requires an agentset or agent but got: ~A" agent-or-agentset))))
286 (defun with (agentset fn)
287 "WITH AGENTSET FN => RESULT-AGENTSET
289 ARGUMENTS AND VALUES:
291 AGENTSET: a NetLogo agentset
292 FN: a boolean function, run on each agent to determine if included
293 RESULT-AGENTSET: an agentset of valid agents
297 WITH is equivalent to with in NetLogo.
299 Returns a new agentset containing only those agents that reported true
302 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#with"
306 (let ((*myself* *self*) (*self* agent)) (funcall fn)))
307 (agentset-list agentset))
308 (agentset-breed agentset)))
310 (defun shufflerator (agentset-list)
312 ((copy (copy-list agentset-list))
318 ((idx (when (< i (1- (length copy))) (+ i (clnl-random:next-int (- (length copy) i))))))
319 (when idx (setf agent (nth idx copy)))
320 (when idx (setf (nth idx copy) (nth i copy)))
322 (fetch) ; we pre-fetch because netlogo does, rng sync hype!
325 ((> i (length copy)) nil)
326 ((= i (length copy)) (incf i) (car (last copy)))
327 (t (let ((result agent)) (fetch) result)))))))
329 (defun random-float (n)
330 "RANDOM-FLOAT N => RANDOM-NUMBER
332 ARGUMENTS AND VALUES:
334 N: a double, the upper bound of the random float
335 RANDOM-NUMBER: a double, the random result
339 Returns a random number strictly closer to zero than N.
341 If number is positive, returns a random floating point number greater than
342 or equal to 0 but strictly less than number.
344 If number is negative, returns a random floating point number less than or equal
345 to 0, but strictly greater than number.
347 If number is zero, the result is always 0.
349 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-float"
350 (clnl-random:next-double n))
353 "RANDOM N => RANDOM-NUMBER
355 ARGUMENTS AND VALUES:
357 N: an integer, the upper bound of the random
358 RANDOM-NUMBER: an integer, the random result
362 Returns a random number strictly closer to zero than N.
364 If number is positive, returns a random integer greater than or equal to 0,
365 but strictly less than number.
367 If number is negative, returns a random integer less than or equal to 0,
368 but strictly greater than number.
370 If number is zero, the result is always 0.
372 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random"
373 (coerce (clnl-random:next-long (truncate n)) 'double-float))
375 (defun random-xcor ()
376 "RANDOM-XCOR => RANDOM-NUMBER
378 ARGUMENTS AND VALUES:
380 RANDOM-NUMBER: a float, the random result
384 Returns a random floating point number in the allowable range of turtle
385 coordinates along the x axis.
387 These range from min-pxcor - 0.5 (inclusive) to max-pxcor + 0.5 (exclusive)
389 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-cor"
391 ((min (- (min-pxcor) 0.5d0))
392 (max (+ (max-pxcor) 0.5d0)))
393 (+ min (clnl-random:next-double (- max min)))))
395 (defun random-ycor ()
396 "RANDOM-YCOR => RANDOM-NUMBER
398 ARGUMENTS AND VALUES:
400 RANDOM-NUMBER: a float, the random result
404 Returns a random floating point number in the allowable range of turtle
405 coordinates along the y axis.
407 These range from min-pycor - 0.5 (inclusive) to max-pycor + 0.5 (exclusive)
409 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-cor"
411 ((min (- (min-pycor) 0.5d0))
412 (max (+ (max-pycor) 0.5d0)))
413 (+ min (clnl-random:next-double (- max min)))))
415 (defun one-of (list-or-agentset)
416 "ONE-OF LIST-OR-AGENTSET => RESULT
418 LIST-OR-AGENTSET: LIST | AGENTSET
419 RESULT: RANDOM-VALUE | RANDOM-AGENT | :nobody
421 ARGUMENTS AND VALUES:
424 AGENTSET: An agent set
425 RANDOM-VALUE: a value in LIST
426 RANDOM-AGENT: an agent if AGENTSET is non empty
430 From an AGENTSET, returns a RANDOM-AGENT. If the agentset is empty, returns :nobody.
431 From a list, returns a RANDOM-VALUE. If the list is empty, an error occurs.
433 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#one-of"
435 ((agentset-p list-or-agentset)
437 ((agentset-list (agentset-list list-or-agentset))
438 (length (length agentset-list)))
439 (if (zerop length) :nobody (nth (clnl-random:next-int length) agentset-list))))
440 ((listp list-or-agentset)
442 ((length (length list-or-agentset)))
444 (error "one-of requires a nonempty list")
445 (nth (clnl-random:next-int length) list-or-agentset))))
446 (t (error "one-of requires a list or agentset"))))
449 (when (not (turtle-p *self*)) (error "Gotta call jump in turtle scope, dude (~A)" *self*))
450 (with-patch-update *self*
454 (+ (turtle-xcor *self*) (* n (using-cached-sin (turtle-heading *self*))))))
458 (+ (turtle-ycor *self*) (* n (using-cached-cos (turtle-heading *self*))))))))
463 ARGUMENTS AND VALUES:
471 Sets the x-coordinate and y-coordinate for the turle. Equivalent to
472 set xcor x set ycor y, except it happens in one step inside of two.
474 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#setxy"
475 (when (not (turtle-p *self*)) (error "Gotta call setxy in turtle scope, dude (~A)" *self*))
476 (setf (turtle-xcor *self*) (wrap-x *topology* x))
477 (setf (turtle-ycor *self*) (wrap-y *topology* y)))
479 (defun set-default-shape (breed shape)
480 "SET-DEFAULT-SHAPE BREED SHAPE => RESULT
482 ARGUMENTS AND VALUES:
490 Specifies a default initial shape for a BREED. When a turtle, or it changes breeds,
491 its shape is set to the given shape.
493 SET-DEFAULT-SHAPE doesn't affect existing agents, only agents you create afterwards.
495 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#set-default-shape"
496 (when (not (breed-p breed)) (error "Need a valid breed"))
497 (setf (breed-default-shape breed) shape))
502 ARGUMENTS AND VALUES:
504 N: a double, the amount the turtle moves forward
509 Moves the current turtle forward N steps, one step at a time.
511 This moves forward one at a time in order to make the view updates look
512 good in the case of a purposefully slow running instance. If the number
513 is negative, the turtle moves backward.
515 If the current agent is not a turtle, it raises an error.
517 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#forward"
518 (when (not (turtle-p *self*)) (error "Gotta call fd in turtle scope, dude (~A)" *self*))
522 ((< (abs i) 3.2e-15) nil)
523 ((< (abs i) 1d0) (jump i))
524 (t (jump (if (> i 0d0) 1d0 -1d0)) (internal (- i (if (> i 0d0) 1d0 -1d0)))))))
527 (defun turn-right (n)
528 "TURN-RIGHT N => RESULT
530 ARGUMENTS AND VALUES:
532 N: a double, the amount the turtle turns
537 The turtle turns right by number degrees. (If number is negative, it turns left.)
539 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#right"
540 (when (not (turtle-p *self*)) (error "Gotta call fd in turtle scope, dude (~A)" *self*))
542 ((new-heading (+ (turtle-heading *self*) n)))
543 (setf (turtle-heading *self*)
545 ((< new-heading 0) (+ (mod new-heading -360) 360))
546 ((>= new-heading 360) (mod new-heading 360))
550 "TURN-LEFT N => RESULT
552 ARGUMENTS AND VALUES:
554 N: a double, the amount the turtle turns
559 The turtle turns left by number degrees. (If number is negative, it turns right.)
561 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#right"
564 (defun create-turtles (n &optional breed fn)
565 "CREATE-TURTLES N &optional BREED FN => RESULT
567 ARGUMENTS AND VALUES:
569 N: an integer, the numbers of turtles to create
571 FN: A function, applied to each turtle after creation
576 Creates N new turtles at the origin.
578 New turtles have random integer headings and the color is randomly selected
579 from the 14 primary colors. If FN is supplied, the new turtles immediately
580 run it. If a BREED is supplied, that is the breed the new turtles are set
583 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#create-turtles"
585 ((new-turtles (loop :repeat n :collect (create-turtle breed))))
586 (when fn (ask (list->agentset new-turtles :turtles) fn))))
588 (defun hatch (n &optional fn)
589 "HATCH N &optional FN => RESULT
591 ARGUMENTS AND VALUES:
593 N: an integer, the numbers of turtles to hatch
594 FN: A function, applied to each turtle after creation
599 The turtle in *self* creates N new turtles. Each new turtle inherits of all its
600 variables, including its location, from self.
602 If FN is supplied, the new turtles immediately run it.
604 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#hatch"
605 (when (not (turtle-p *self*)) (error "Can only hatch from turtle scope"))
607 ((new-turtles (loop :repeat n :collect (create-turtle nil *self*))))
608 (when fn (ask (list->agentset new-turtles :turtles) fn))))
610 (defun reset-ticks ()
611 "RESET-TICKS => RESULT
613 ARGUMENTS AND VALUES:
619 Resets the tick counter to zero, sets up all plots, then updates all plots.
621 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#reset-ticks"
625 "RESET-TICKS => RESULT
627 ARGUMENTS AND VALUES:
633 Advances the tick counter by one and updates all plots.
635 If the tick counter has not been started yet with reset-ticks, an error results.
637 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#tick"
639 (when (not *ticks*) (error "reset-ticks must be called"))
643 "TICKS => CURRENT-TICKS
645 ARGUMENTS AND VALUES:
647 CURRENT-TICKS: A positiv double, representing the current number of ticks
651 Reports the current value of the tick counter. The result is always a number and never negative.
653 If the tick counter has not been started yet with reset-ticks, an error results.
655 See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#ticks"
656 (when (not *ticks*) (error "reset-ticks must be called"))
659 (defun clear-patches ()
663 :for y :from (max-pycor) :downto (min-pycor)
665 :for x :from (min-pxcor) :to (max-pxcor)
667 :xcor (coerce x 'double-float)
668 :ycor (coerce y 'double-float)
671 (defun clear-turtles ()
673 (setf *current-id* 0))
675 (defun clear-ticks ()
678 (defun create-world (&key dims globals turtles-own-vars patches-own-vars breeds)
679 "CREATE-WORLD &key DIMS GLOBALS TURTLES-OWN-VARS PATCHES-OWN-VARS BREEDS => RESULT
681 DIMS: (:xmin XMIN :xmax XMAX :ymin YMIN :ymax YMAX)
683 TURTLES-OWN-VARS: TURTLES-OWN-VAR*
684 PATCHES-OWN-VARS: PATCHES-OWN-VAR*
686 GLOBAL: (GLOBAL-NAME GLOBAL-ACCESS-FUNC)
688 ARGUMENTS AND VALUES:
691 XMIN: An integer representing the minimum patch coord in X
692 XMAX: An integer representing the maximum patch coord in X
693 YMIN: An integer representing the minimum patch coord in Y
694 YMAX: An integer representing the maximum patch coord in Y
695 TURTLES-OWN-VAR: Symbol for the turtles own variable in the keyword package
696 PATCHES-OWN-VAR: Symbol for the patches own variable in the keyword package
697 BREED: A list of symbols representing the possible preeds
698 GLOBAL-NAME: Symbol for the global in the keyword package
699 GLOBAL-ACCESS-FUNC: Function to get the value of the global
703 Initializes the world in the NVM.
705 This should be called before using the engine in any real capacity. If
706 called when an engine is already running, it may do somethign weird."
707 (setf *turtles-own-vars* turtles-own-vars)
708 (setf *patches-own-vars* patches-own-vars)
709 (setf *dimensions* dims)
710 (setf *globals* globals)
713 (list (list :turtles "default"))
714 (mapcar (lambda (breed) (list breed "default")) breeds)))
719 ; These match netlogo's dump
720 (defgeneric dump-object (o))
722 (defmethod dump-object ((n double-float))
723 (multiple-value-bind (int rem) (floor n)
725 (format nil "~A" int)
727 ((output (format nil "~D" n)))
728 ; Someday we'll have d<posint>, but this is not that day!
729 (cl-ppcre:regex-replace "d-" (cl-ppcre:regex-replace "d0" output "") "E-")))))
731 (defmethod dump-object ((o string)) (format nil "~A" (cl-ppcre:regex-replace-all "\"" (format nil "~S" o) "\"\"")))
733 (defmethod dump-object ((o (eql t))) "true")
734 (defmethod dump-object ((o (eql nil))) "false")
736 (defmethod dump-object ((o list))
738 ((agentset-p o) (format nil "(agentset, ~A ~A)" (dump-object (count o)) (string-downcase (agentset-breed o))))
739 (t (format nil "[~{~A~^ ~}]" (mapcar #'dump-object o)))))
741 (defmethod dump-object ((o patch))
742 (format nil "(patch ~A ~A)" (dump-object (patch-xcor o)) (dump-object (patch-ycor o))))
744 (defmethod dump-object ((o turtle)) (format nil "(turtle ~A)" (dump-object (turtle-who o))))
745 (defmethod dump-object ((o (eql :nobody))) (format nil "nobody"))
746 (defmethod dump-object ((o (eql :turtles))) (format nil "{all-turtles}"))
747 (defmethod dump-object ((o symbol))
749 ((find o *breeds* :key #'car) (format nil "{breed ~(~A~)}" o))
750 (t (error "Keyword unrecognized by dump object: ~A" o))))
752 (defun current-state ()
753 "CURRENT-STATE => WORLD-STATE
755 ARGUMENTS AND VALUES:
757 WORLD-STATE: A list, the current state of the whole world
761 Dumps out the state of the world.
763 This is useful for visualizations and also storing in a common lisp
764 data structure for easy usage in a common lisp instance. It's preferable
765 to use this when working with the nvm than the output done by export-world.
767 Currently this only dumps out turtle and patch information.
769 This is called CURRENT-STATE because export-world is an actual primitive
775 :color (turtle-color turtle)
776 :xcor (turtle-xcor turtle)
777 :ycor (turtle-ycor turtle)
778 :heading (turtle-heading turtle)
779 :size (turtle-size turtle)))
784 :color (patch-color patch)
785 :xcor (patch-xcor patch)
786 :ycor (patch-ycor patch)))
789 (defun export-turtles ()
793 (format nil "~A~A~{,\"~A\"~}"
794 "\"who\",\"color\",\"heading\",\"xcor\",\"ycor\",\"shape\",\"label\",\"label-color\","
795 "\"breed\",\"hidden?\",\"size\",\"pen-size\",\"pen-mode\""
796 (mapcar #'string-downcase *turtles-own-vars*)))
800 "\"~A\",\"~A\",\"~A\",\"~A\",\"~A\",\"~A\",\"~A\",\"~A\",\"~A\",\"false\",\"~A\",~A~{,\"~A\"~}"
801 (dump-object (turtle-who turtle))
802 (dump-object (turtle-color turtle))
803 (dump-object (turtle-heading turtle))
804 (dump-object (turtle-xcor turtle))
805 (dump-object (turtle-ycor turtle))
806 (dump-object (turtle-shape turtle))
807 (dump-object (turtle-label turtle))
808 (dump-object (turtle-label-color turtle))
809 (dump-object (turtle-breed turtle))
810 (dump-object (turtle-size turtle))
811 "\"1\",\"\"\"up\"\"\""
812 (mapcar #'dump-object (mapcar (lambda (var) (agent-value-inner turtle var)) *turtles-own-vars*))))
815 (defun export-patches ()
819 (format nil "\"pxcor\",\"pycor\",\"pcolor\",\"plabel\",\"plabel-color\"~{,\"~A\"~}"
820 (mapcar #'string-downcase *patches-own-vars*)))
824 "\"~A\",\"~A\",\"~A\",\"\"\"\"\"\",\"9.9\"~{,\"~A\"~}"
825 (dump-object (patch-xcor patch))
826 (dump-object (patch-ycor patch))
827 (dump-object (patch-color patch))
828 (mapcar #'dump-object (mapcar (lambda (var) (agent-value-inner patch var)) *patches-own-vars*))))
831 (defun export-world ()
832 "EXPORT-WORLD => WORLD-CSV
834 ARGUMENTS AND VALUES:
836 WORLD-CSV: A string, the csv of the world
840 Dumps out a csv matching NetLogo's export world.
842 This is useful for serializing the current state of the engine in order
843 to compare against NetLogo or to reimport later. Contains everything needed
844 to boot up a NetLogo instance in the exact same state."
845 (format nil "~{~A~%~}"
847 (format nil "~S" "RANDOM STATE")
848 (format nil "~S" (clnl-random:export))
850 (format nil "~S" "GLOBALS")
851 (format nil "~A~A~{\"~A\"~^,~}"
852 "\"min-pxcor\",\"max-pxcor\",\"min-pycor\",\"max-pycor\",\"perspective\",\"subject\","
853 "\"nextIndex\",\"directed-links\",\"ticks\","
854 (mapcar #'string-downcase (mapcar #'car *globals*)))
855 (format nil "\"~A\",\"~A\",\"~A\",\"~A\",\"0\",\"nobody\",\"~A\",\"\"\"NEITHER\"\"\",\"~A\"~{,\"~A\"~}"
856 (min-pxcor) (max-pxcor) (min-pycor) (max-pycor) *current-id* (dump-object (or *ticks* -1d0))
857 (mapcar #'dump-object (mapcar #'funcall (mapcar #'cadr *globals*))))
859 (format nil "~{~A~^~%~}" (export-turtles))
861 (format nil "~{~A~^~%~}" (export-patches))
863 (format nil "~S" "LINKS")
864 "\"end1\",\"end2\",\"color\",\"label\",\"label-color\",\"hidden?\",\"breed\",\"thickness\",\"shape\",\"tie-mode\""