64567e90e24ef73932a89aab28ae7a22d7e0ae67
[clnl] / src / main / clnl / nvm / agentset.lisp
1 ; Copyright 2022 Frank Duncan (frank@consxy.com) under AGPL3.  See distributed LICENSE.txt.
2 (in-package #:clnl-nvm)
3
4 (defun count (agentset)
5  "COUNT AGENTSET => N
6
7 ARGUMENTS AND VALUES:
8
9   AGENTSET: a NetLogo agentset
10   N: a number
11
12 DESCRIPTION:
13
14   COUNT is equivalent to count in NetLogo.  Returns N, the number of
15   agents in AGENTSET.
16
17   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#count"
18  (coerce (length (agentset-list agentset)) 'double-float))
19
20 (defun of (fn agent-or-agentset)
21  "OF FN AGENT-OR-AGENTSET => RESULT
22
23   AGENT-OR-AGENTSET: AGENT | AGENTSET
24   RESULT: RESULT-LIST | RESULT-VALUE
25
26 ARGUMENTS AND VALUES:
27
28   FN: a function, run on each agent
29   AGENT: a NetLogo agent
30   AGENTSET: a NetLogo agentset
31   RESULT-LIST: a list
32   RESULT-VALUE: a single value
33
34 DESCRIPTION:
35
36   OF is equivalent to of in NetLogo.
37
38   The specified AGENTSET or AGENT runs the given FN.  In the case of an
39   AGENTSET, the order in which the agents are run is random each time,
40   and only agents that are in the set at the beginning of the call.
41
42   RESULT-LIST is returned when the input is an AGENTSET, but RESULT-VALUE
43   is returned when only passed an AGENT.
44
45   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#of"
46  (cond
47   ((agentset-p agent-or-agentset)
48    (let
49     ((iter (shufflerator (agentset-list agent-or-agentset))))
50     (loop
51      :for agent := (funcall iter)
52      :while agent
53      :collect (let ((*myself* *self*) (*self* agent)) (funcall fn)))))
54   ((agent-p agent-or-agentset)
55    (let ((*myself* *self*) (*self* agent-or-agentset)) (funcall fn)))
56   (t
57    (error "Of requires an agentset or agent but got: ~A" agent-or-agentset))))
58
59 (defun one-of (list-or-agentset)
60  "ONE-OF LIST-OR-AGENTSET => RESULT
61
62   LIST-OR-AGENTSET: LIST | AGENTSET
63   RESULT: RANDOM-VALUE | RANDOM-AGENT | :nobody
64
65 ARGUMENTS AND VALUES:
66
67   LIST: A list
68   AGENTSET: An agent set
69   RANDOM-VALUE: a value in LIST
70   RANDOM-AGENT: an agent if AGENTSET is non empty
71
72 DESCRIPTION:
73
74   From an AGENTSET, returns a RANDOM-AGENT. If the agentset is empty, returns :nobody.
75   From a list, returns a RANDOM-VALUE.  If the list is empty, an error occurs.
76
77   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#one-of"
78  (cond
79   ((agentset-p list-or-agentset)
80    (let*
81     ((agentset-list (agentset-list list-or-agentset))
82      (length (length agentset-list)))
83     (if (zerop length) :nobody (nth (clnl-random:next-int length) agentset-list))))
84   ((listp list-or-agentset)
85    (let*
86     ((length (length list-or-agentset)))
87     (if (zerop length)
88      (error "one-of requires a nonempty list")
89      (nth (clnl-random:next-int length) list-or-agentset))))
90   (t (error "one-of requires a list or agentset"))))
91
92 (defun patches ()
93  "PATCHES => ALL-PATCHES
94
95 ARGUMENTS AND VALUES:
96
97   ALL-PATCHES: a NetLogo agentset, all patches
98
99 DESCRIPTION:
100
101   Reports the agentset consisting of all the patches.
102
103   This agentset is special in that it represents the living patches
104   each time it's used, so changes depending on the state of the engine.
105
106   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#patches"
107  :patches)
108
109 (defun turtles ()
110  "TURTLES => ALL-TURTLES
111
112 ARGUMENTS AND VALUES:
113
114   ALL-TURTLES: a NetLogo agentset, all turtles
115
116 DESCRIPTION:
117
118   Reports the agentset consisting of all the turtles.
119
120   This agentset is special in that it represents the living turtles
121   each time it's used, so changes depending on the state of the engine.
122
123   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#turtles"
124  :turtles)
125
126 (defun with (agentset fn)
127  "WITH AGENTSET FN => RESULT-AGENTSET
128
129 ARGUMENTS AND VALUES:
130
131   AGENTSET: a NetLogo agentset
132   FN: a boolean function, run on each agent to determine if included
133   RESULT-AGENTSET: an agentset of valid agents
134
135 DESCRIPTION:
136
137   WITH is equivalent to with in NetLogo.
138
139   Returns a new agentset containing only those agents that reported true
140   when FN is called.
141
142   See http://ccl.northwestern.edu/netlogo/docs/dictionary.html#with"
143  (list->agentset
144   (remove-if-not
145    (lambda (agent)
146     (let ((*myself* *self*) (*self* agent)) (funcall fn)))
147    (agentset-list agentset))
148   (agentset-breed agentset)))