+(defvar *current-id* 0)
+
+(defstruct turtle who color heading xcor ycor)
+(defvar *turtles* nil)
+(defvar *myself* nil)
+(defvar *self* nil)
+
+(defun show (value)
+ "SHOW VALUE => RESULT
+
+ARGUMENTS AND VALUES:
+
+ VALUE: a NetLogo value
+ RESULT: undefined
+
+DESCRIPTION:
+
+ A command that prints the given NetLogo value to the command center.
+
+ See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#show"
+ (format t "Showing: ~A~%" (dump-object value)))
+
+(defun world-dimensions ()
+ (list :xmin -10 :xmax 10 :ymin -10 :ymax 10))
+
+(defun create-turtle ()
+ (setf
+ *turtles*
+ (nconc
+ *turtles*
+ (list
+ (make-turtle
+ :who *current-id*
+ :color (coerce (+ 5 (* 10 (clnl-random:next-int 14))) 'double-float)
+ :heading (coerce (clnl-random:next-int 360) 'double-float)
+ :xcor 0d0
+ :ycor 0d0))))
+ (incf *current-id*))
+
+(defun turtles ()
+ "TURTLES => ALL-TURTLES
+
+ARGUMENTS AND VALUES:
+
+ ALL-TURTLES: a NetLogo agentset, all turtles
+
+DESCRIPTION:
+
+ Reports the agentset consisting of all the turtles.
+
+ This agentset is special in that it represents the living turtles
+ each time it's used, so changes depending on the state of the engine.
+
+ See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#turtles"
+ *turtles*)
+
+(defun ask (agent-set fn)
+ "ASK AGENT-SET FN => RESULT
+
+ARGUMENTS AND VALUES:
+
+ AGENT-SET: a NetLogo agentset
+ FN: a function, run on each agent
+ RESULT: undefined, commands don't return
+
+DESCRIPTION:
+
+ ASK is equivalent to ask in NetLogo.
+
+ The specified AGENT-SET runs the given FN. The order in which the agents
+ are run is random each time, and only agents that are in the set at the
+ beginning of the call.
+
+ See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#ask"
+ (let
+ ((iter (shufflerator agent-set)))
+ (loop
+ :for agent := (funcall iter)
+ :while agent
+ :do (let ((*myself* *self*) (*self* agent)) (funcall fn)))))
+
+(defun shufflerator (agent-set)
+ (let
+ ((copy (copy-list agent-set))
+ (i 0)
+ (agent nil))
+ (flet
+ ((fetch ()
+ (let
+ ((idx (when (< i (1- (length copy))) (+ i (clnl-random:next-int (- (length copy) i))))))
+ (when idx (setf agent (nth idx copy)))
+ (when idx (setf (nth idx copy) (nth i copy)))
+ (incf i))))
+ (fetch) ; we pre-fetch because netlogo does, rng sync hype!
+ (lambda ()
+ (cond
+ ((> i (length copy)) nil)
+ ((= i (length copy)) (incf i) (car (last copy)))
+ (t (let ((result agent)) (fetch) result)))))))
+
+(defun random-float (n)
+ "RANDOM-FLOAT N => RANDOM-NUMBER
+
+ARGUMENTS AND VALUES:
+
+ N: a double, the upper bound of the random float
+ RANDOM-NUMBER: a double, the random result
+
+DESCRIPTION:
+
+ Returns a random number strictly closer to zero than N.
+
+ If number is positive, returns a random floating point number greater than
+ or equal to 0 but strictly less than number.
+
+ If number is negative, returns a random floating point number less than or equal
+ to 0, but strictly greater than number.
+
+ If number is zero, the result is always 0.
+
+ See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#random-float"
+ (clnl-random:next-double n))
+
+(defun forward (n)
+ "FORWARD N => RESULT
+
+ARGUMENTS AND VALUES:
+
+ N: a double, the amount the turtle moves forward
+ RESULT: undefined
+
+DESCRIPTION:
+
+ Moves the current turtle forward N steps, one step at a time.
+
+ This moves forward one at a time in order to make the view updates look
+ good in the case of a purposefully slow running instance. If the number
+ is negative, the turtle moves backward.
+
+ If the current agent is not a turtle, it raises an error.
+
+ See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#forward"
+ (when (not (turtle-p *self*)) (error "Gotta call fd in turtle scope, dude (~A)" *self*))
+ (setf (turtle-xcor *self*) (+ (turtle-xcor *self*) (* n (sin (* pi (/ (turtle-heading *self*) 180))))))
+ (setf (turtle-ycor *self*) (+ (turtle-ycor *self*) (* n (cos (* pi (/ (turtle-heading *self*) 180)))))))