goal-seeking-boids
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
WHAT IS IT?
This models the ability of a swarm to reach a goal based on communication, memory, and observations limited by distance and noise.
The model also allows agents to learn over time what rules seem to work, and co-evolve cultural wisdom which is passed on to new agents.
It can be used to study evolution of cultural shared opinions ( tribes ) as well as robustness of the overall planet to sudden changes in the landscape properties. ( once learned does behavior perseverate ? )
TAGS
computational social-science, education, policy-making, polarization, peer-pressure, cancel-culture, sharing, humility, cultural-evolution, culture-robustness
WHAT IS THE PURPOSE OF THE MODEL AND INTENDED AUDIENCE?
People of all ages might enjoy seeing what kind of problems occur in such a "simple" situation. Everyone can relate.
More serious students of decision-theory could find insight into the understudied question of how to make an optimal decision in a noisy world.
Lessons can be setup at selected points in complexity for maximum Axelrod-impact on segmented audiences by being near to them and familiar
HOW IT WORKS CONCEPTUALLY
there are mountains of "wealth" where higher on the hill represents more wealth. the swarm of agents move across this landscape and seek to get all of them on the highest peak of wealth.
Agents are initally distributed randomly across the landscape. There are no links between agents. Agents cannot see what wealth other agents have.
Agents all have the same set of rules and rules don't change during the run.
Different rules can be selected for testing.
At each tick, one random agent makes a decision about which direction is best to move. They base this decision by trade-offs between
a global observation: where is everyone else ?
- a local observation : which way appears to be "uphill" ?
- memory: which way have I been moving recently?
Then they either move one step forward and their wealth changes too the wealth of the new patch, or they can elect to stay where they are.
The run stops when all agents have reached the highest peak of wealth, or after a maximum time-limit
The same situation can be tested using different rules to see what impact the rules have on the results.
The same rules can be tested against different landscapes to see if they work as well.
WHY IS THIS NON-TRIVIAL?
If there were only one smooth hill of wealth, a very simple hill-climbing rule would succeed: Everyone just move whatever way is locally uphill. You can set that up and see it work.
But, there are real-world complications to finding the best place, and these cause the simple hill-climbing rule to fail.
There might be more than one large-scale hill, so agents will get stuck on the wrong large hill. You can try that out and see.
There might be small-scale variations on the landscape (it may be "noisy" and not smooth ) so agents might get trapped on a local bump. You can see that in action.
The landscape might have blind-alleys where the "go uphill" rule fails on a location that is not even the top of any hill. An example that generates a blind-alley can be tried out.
Finally, there might be actual obstacles to travel in the landscape, such as walls. How well do rules work if there are such obstacles? A few such worlds have been supplied as examples that can be imported into the model to explore. Advanced users could make others to import.
We've all been stuck in a blind-alley or behind an obstacle. Are there rules that can get you unstuck?
WHAT ARE THE INTERESTING QUESTIONS?
This illustrates the problems of trying locate the best point in a noisy fitness landsape. How can agents avoid being trapped on a local maximum?
What are the trade-offs between observation and memory?
Agents can communicate, so strategies that involve jointly locating a best point are useful, such as moving towards each other, but these have a downside of too much coherence, in that everyone may end up into small clusters that are near each other, but still far from the best hill.
Agents can also effectively smooth out the landscape by remembering which way they have been moving, and consider that as important as the local "uphill" measurement in deciding which way is "up".
Is there a "best" algorithm that works for all combinations of long-range and short-range noise?
IMPORTANT LIFE LESSONS THE MODEL HELPS CONVEY
Being "greedy" is not always the best rule. (A series of "best" short-run decisions does not always get you to the best possible long-term result.)
possible application area: public policy, Congressional "progress".
The best rule may still fail in some situations. ( A bad outcome doesn't mean that a bad policy was used.)
possible application: evaluating doctors or policy-makers
Sometimes it pays to be slow to change one's opinion.
What is "obvious" ( locally ) and what is real (globally) may differ.
possible application: intellectual humility
Sometimes you have to just try and see what happens.
pososible application: more tolerance for "mistakes" by self and others
HOW IS THE MODEL IMPLEMENTED IN NETLOGO?
- the world wraps horizontally and vertically
- N turtles are created in random locations. N is a slider choice
- all turtles follow the same rules ( There is no wisdom-distribution )
turtles don't communicate with each other or see each other
*??? agents cannot see what wealth other agents have.
( variant of model, let them discover it and broadcast it as a population, gradually )
each turtle has two local rules at each tick (1) if it is possible to move uphill locally, do so and reset own wealth to the local pcolor value ELSE (2) if turtle is at a local maximum and realizes it is not the current best GLOBAL max, turn blue, and take a leap of size (3 + random 4) in a random direction OTHERWISE ... turn green and stay there
The success of a migration critically depends on ability to get off a local maximum in this version ( hill-climbing-03) the leap step is simply forward (3 + random 4) in a random direction ( varies with iteration ) and is the same for every turtle These "magic numbers" are buried at the bottom of the move-turtles section and were picked for convenience because they worked out for the given hill locations and shapes used for developing the code
HOW TO USE IT
If you want to reuse an older random seed to repeat a run, possibly with different slider values, set the reuse-seed? switch to ON. You can also type the seed you want to reuse directly in the "randomseed" text box at the same time. Otherwise, it will resuse whatever the last random seed was, which is the value show in that box.
[ coming, Feb 2021 ]
THINGS TO NOTICE
[ coming, Feb 2021 ]
THINGS TO TRY
[ coming, Feb 2021 ]
EXTENDING THE MODEL
[ coming, Feb 2021 ]
NETLOGO FEATURES
[ coming, Feb 202 1 ]
RELATED MODELS
The hill creation code is inspired from the "Hill Climbing example" model
CREDITS AND REFERENCES
Copyright (c) 2021 R. Wade Schuette, all rights reserved. wade.schuette@gmail.com
YouTube video is scheduled to be added in February, 2021
Comments and Questions
;; MODEL NAME: goal-seeking-boids-v2-1py ;; DATE: written 14-Nov-2019 ;; HISTORY: ;; 01-Feb-2011 uploaded first version to modeling commons ;; latest version updated 1-Feb-2021 at 6:28 AM CST (Chicago time zone ) ;; 14-Oct-2021 Modified to allow rerunning random-seed values. ;; Tests for running netlogo-web. If local, allows importing landscape and saving snapshots ;; added "maxwealth" and "stepsize" to turtles-own variables ;; ;; TRANSIENT Work in process ;; * migrate local-gorup-horizon to all instances of everyone, wej ust put it in everyone uphill ;; * correction for angles near 360 has only been applied to every plus uphill case ;; known bugs: ;; * prints stopped when all turtles succeeded twice in output ;; * on stop for everyone, neither of the plots are accurate, and the last 45 or so never are caught ;; * motion can get locked up in a corner ;;============ UN-comment the next line if you are running locally! ================= ; extensions [view2.5d] ;; ================================================================================== globals [ stop-now? ;; stop flag for subroutines to back up to the go command patch-count ;; for this size display on-peak-count ;; number of turtles on the peak peak-height ;; height of highest patch my-center ;; weighted centroid of all the agents, or possibly of VISIBLE nearby agents timestamp ;; updated date-and-time to show on interface, only updated when taking snapshot stop-at-tick ;; stop run when ticks >= stop-at-tick filechoice ;; imported landscape jpg file name, if any ;; global variables defined by the interface controls ;; note - these are NOT cleared by "clear-globals" or "clear-all" ;; =============================================== ;; randomseed ;; ( added 13-Oct-2021 ) ;; number-of-hits ;; turtle-count ;; rule-to-use ;; leave-a-trail? ;; run-title ;; turtle-color ;; turtle-shape ;; landscape-source ;; noise? ;; noise-size ;; noise-density ;; group-weight ;; timestamp ;; braking-pct ( insert a wait X seconds into the end of the go loop for fine tuning) ;;; ============== automater's globals begin ==================== ; working-directory ;; the operating system working directory ; command-file ;; where the commands will be read from ; output-file ;; optional, where output from the go step can be written ; log-file ;; a log of what commands were executed ; run-title ;; whatever you want to name this run ; show-commands-as-run? ;; controls whether you want to see commands as they are run ; use-sample-input-file? ;; if true, generates a file called test-01-input.txt to use ; ;; as input for this model. ; ;; This will destroy an existing file of that name! ;;; ================ automater's globals end ===================== ] turtles-own[ maxwealth ;; maximum wealth turtle has ever seen - 10/13/21 wealth ;; just equal to the pcolor of the patch the turtle is on prior-wealth ;; wealth before this latest step on-peak? old-heading ;; actually exponentially smoothed history of prior headings inertia ;; [0,1], turtle specific, weight of old-heading in updated heading, defaults to zero empathy ;; [0,1] actually misnamed to be shorter, susceptibility to group peer pressure step-size-multiplier ;; 10/13/21 good-step-count ;; counts number of steps with improving height my-heading-uphill ;; before step my-heading-group ;; before step ] patches-own [ height basepcolor ] to setup if ( netlogo-web? = false ) [ print "\n ================================== \n If you get an error that VIEW2.5:PATCH-VIEW is undefined, \n uncomment out the EXTENSION definition in the first line of actual code \n ================================== \n"; ] let mystr88 "Test" if ( netlogo-web? = false ) [ run " view2.5d:patch-view mystr88 [ [the-patch] -> [height] of the-patch ] " run " view2.5d:set-z-scale mystr88 zfactor " ] ;; we persist randomseed across runs by putting the prior value in the "local" variable "oldseed" ;; but if that has never been set, we need to set it as well. clear-all if (reuse-seed? = false ) [ set randomseed ( random 999999 ) ] ;; note, if randomseed is not reset above, the value from the interface input box will persist random-seed randomseed set timestamp date-and-time set stop-now? false ;; no-display ( won't work over the web ! ) if landscape-source = "generated" [make-landscape ] if landscape-source = "imported" [import-landscape] make-turtles ;; display( won't work over the web ! ) set my-center (patch 0 0) ;; weighted centroid of the agents, dynamically updated ;;======================================= automaters commands begin ;; setup-automater ;;======================================= automaters commands end prepare-outputs set stop-at-tick max-ticks ;; stop normally if time is reached ask patches [ set basepcolor pcolor ] ask patches [ ifelse ( count turtles-here > 0 ) [ set pcolor green][set pcolor basepcolor]] reset-ticks end to prepare-outputs ;; called once during setup ;; select external log and output files here, if any ;; write experiment title and date to output area output-print run-title output-print timestamp ;; set at start of run, not output date-and-time ! output-print " " output-print (word "turtle-count: " turtle-count) output-print (word "rule-to-use: " rule-to-use) output-print (word "landscape: " landscape-source) if (landscape-source = "imported") [output-print (word "file: " filechoice)] ;; other experimental settings could be output here output-print " " ;; write column headers to the output area (if-else rule-to-use = "single: wander" [ output-print (word "turtle " " ticks " ) ] rule-to-use = "single: go-uphill" [ output-print (word "turtle " " ticks " ) ] rule-to-use = "single: find-everyone" [ output-print (word "turtle " " ticks " " group-weight: " ) ] rule-to-use = "pair: uphill with inertia" [ output-print (word "turtle " " ticks " " inertia " ) ] rule-to-use = "pair: uphill with everyone" [ output-print (word "turtle " " ticks " " group-weight " ) ] rule-to-use = "triple: use all three" [ output-print (word "turtle " " ticks " " group-weight " " inertia " ) ] ; else commands [ error (word " unexpected rule-to-use choice: " rule-to-use) ] ) end to import-landscape ;; only if local. Won't compile in netlogo-web. ifelse ( netlogo-web? = false ) [ let msg1 "starting runstring" let msg2 " no file selected! " let msg3 "Importing image file " let msg4 " failed, so generating the image locally" let msg5 "generated" let msg6 "You asked to import this landscape file: " let runstring ( word " print msg1 " " set filechoice user-file " " if-else filechoice = false " " [ " " print msg2 " " print (word msg3 user-file msg4) " " set landscape-source msg5 " " make-landscape " " ] " " [ " " print (word msg6 filechoice) " " import-pcolors filechoice " " ask max-one-of patches [pcolor] [set peak-height pcolor] " " ask patches [ set height pcolor] " " ] " ) run runstring ] [ print "Landscapes can only be imported if this model is downloaded and run locally! "] end to trackwho inspect turtle monturtle end to go ask patches [ ifelse ( count turtles-here > 0 ) [ set pcolor green][set pcolor basepcolor]] let mystr88 "Test" if ( netlogo-web? = false ) [ run "view2.5d:set-z-scale mystr88 zfactor" run "view2.5d:update-all-patch-views" ] ;; WARNING -- this will not print final output if stopped by interface if stop-now? [ print "Stop was requested by a subroutine" stop ] if ticks > stop-at-tick [wrap-up-run stop] ;; prevent runaway models from consuming computer time if all? turtles [on-peak?] [ wrap-up-run stop ] move-turtles if stop-now? [ print "Stop was requested by a subroutine." stop ] if stop-now? [ error "stop was requested but failed" ] update-status if braking-pct > 0 [ wait ( braking-pct / 100) ] ;; slowdown despite top master speed switch tick end to wrap-up-run ;; wrap up the entire run ;; this is a place-holder ;; print "any wrapping up will go here", such as writing output to a file if (ticks >= stop-at-tick) [ print (word "stopped at time limit, ticks = " ticks) output-print (word "stopped at time limit, ticks = " ticks) ] if (stop-now?) [ print (word "stopped unexpectedly, ticks = " ticks) output-print (word "stopped unexpectedly, ticks = " ticks) ] if-else (all? turtles [on-peak?]) [ print (word "stopped when all turtles succeeded, ticks = " ticks) output-print (word "stopped when all turtles succeeded, ticks = " ticks) ] [ print ( word "count of turtles not yet on the peak: " count turtles with [on-peak? = false] ) output-print ( word "count of turtles not yet on the peak: " count turtles with [on-peak? = false] ) ] ;; for inertia plot, set the time to 100 and plot the straglers if rule-to-use = "pair: uphill with inertia" [ set-current-plot "inertia-influence" ;;plotxy inertia ticks ask turtles with [on-peak? = false ] [ let cluster-show 98 + random-float 2 plotxy inertia cluster-show ; output-print (word " ? " " " cluster-show ) ] ] ;; for group plot, set the time to 100 and plot the straglers if rule-to-use = "pair: uphill with everyone" [ set-current-plot "social-influence" ask turtles with [on-peak? = false ] [ let cluster-show2 98 + random-float 2 plotxy empathy cluster-show2 ; output-print (word " ? " " " cluster-show2 " " 1.0 " (forced) " ) ] ] end to update-status set on-peak-count count turtles with [on-peak?] ;; ======================================================= automater code begins ;; file-open output-file ;; file-print (word "turtles on peak: " on-peak-count) ;;======================================================== automater code ends end to-report local-group-center ;; for each agent, vision limited by horizon ( or links ? ) ;; side-effect: this sets the global variable my-center let sumx 0 let sumy 0 let sumx-wealth 0 let sumy-wealth 0 let numnearby count turtles with [ (distance myself ) < horizon] print ( word "nearby turtle count " numnearby) ask turtles with [ (distance myself ) < horizon] [ set sumx sumx +(pxcor * wealth) set sumx-wealth sumx-wealth + wealth set sumy sumy +(pycor * wealth) set sumy-wealth sumy-wealth + wealth ] ;; at set-up avoid division by zero if-else ( sumx-wealth > 0 ) [ set sumx sumx / sumx-wealth set sumy sumy / sumy-wealth] [ set sumx 0 set sumy 0 ] ;; put centroid in the center on first pass report (patch sumx sumy) ;report (list sumx sumy) end to-report centroid ;; compute center of the swarm, weighted by wealth ;; side-effect: this sets the global variable my-center let sumx 0 let sumy 0 let sumx-wealth 0 let sumy-wealth 0 ask turtles [ set sumx sumx +(pxcor * wealth) set sumx-wealth sumx-wealth + wealth set sumy sumy +(pycor * wealth) set sumy-wealth sumy-wealth + wealth ] ;; at set-up avoid division by zero if-else ( sumx-wealth > 0 ) [ set sumx sumx / sumx-wealth set sumy sumy / sumy-wealth] [ set sumx 0 set sumy 0 ] ;; put centroid in the center on first pass set my-center (patch sumx sumy) report (list sumx sumy) end ; =========== turtle movement commands =============== to wrap-up-step ;; Utility, called by every rule, in every step, in a turtle context set wealth height ; transfer patch parameter to a turtle parameter ;; This output relies on the various move steps ONLY being called for ;; turtles that were not already at peak height. Otherwise, this ;; will generate way too much output!! if height = peak-height ;; did we just reach the peak? [ set on-peak? true set color green set label "" (if-else rule-to-use = "single: wander" [ output-print (word who " " ticks ) ] rule-to-use = "single: go-uphill" [ output-print (word who " " ticks ) ] rule-to-use = "single: find-everyone" [ output-print (word who " " ticks " " group-weight ) ] rule-to-use = "pair: uphill with inertia" [ output-print (word who " " ticks " " inertia ) set-current-plot "inertia-influence" set-current-plot-pen "default" plotxy inertia ticks ] rule-to-use = "pair: uphill with everyone" [ output-print (word who " " ticks " " group-weight ) set-current-plot "social-influence" set-current-plot-pen "default" plotxy empathy ticks ] rule-to-use = "triple: use all three" [ output-print (word who " " ticks " " group-weight " " inertia ) set-current-plot "inertia-influence" set-current-plot-pen "default" plotxy inertia ticks set-current-plot "social-influence" set-current-plot-pen "default" plotxy empathy ticks ] ; else commands [ error (word " unexpected rule-to-use choice: " rule-to-use) ] ) ] end to go-wander ask turtles with [not on-peak?] [ set heading heading + random 45 set heading heading - random 45 step-or-reverse ( 1 ) ;;set wealth height wrap-up-step ] end to step-or-reverse [ size-of-step ] set prior-wealth height if-else can-move? size-of-step [forward (size-of-step * step-size-multiplier)][ set heading heading + 180 forward ( size-of-step * step-size-multiplier) ] ifelse ( dynamic-speed? = true ) [ ;; following variable step-size control is experimental 14-Oct-2021 set wealth height if ( wealth > maxwealth) [ set maxwealth wealth ] ifelse ( wealth > prior-wealth ) [ if ( good-step-count < 0) [set good-step-count 0] set good-step-count ( good-step-count + 1 ) ] [ if ( good-step-count > 0) [set good-step-count 0] set good-step-count ( good-step-count - 1 ) ] set step-size-multiplier ( 1 + ( good-step-count / 5 ) ) if ( step-size-multiplier > 5 ) [ set step-size-multiplier 5] if ( step-size-multiplier < 0.2) [ set step-size-multiplier 0.2 ] ] [ set step-size-multiplier 1 ] end to-report uphill-heading ;; heading is in degrees , 0 to 360 ;; hard-codes a search radius let search-radius 2.5 ;; ask turtles with [not on-peak?] [ let old-patch patch-here let neighborhood patches with [ distance myself < search-radius ] let target max-one-of neighborhood [height ] face target ;; WARNING -- side-effect report heading ;; ] end to go-uphill ;; hard-codes a step size let step-size 1 ask turtles with [not on-peak?] [ set heading uphill-heading step-or-reverse ( 1 ) wrap-up-step ] end to go-find-everyone ;; centroid and my-center needs to be refactored ;; first, comput the weighted centroid of all the turtles let new-centroid (list 0 0) set new-centroid centroid ;; sets global my-center as side-effect ;; computes new-centroid but only uses the side effect ;; WARNING -- twisted way of simply setting my-center ask turtles with [not on-peak?] [ ;; let old-patch patch-here ;; obsolete?? face my-center step-or-reverse ( 1 ) wrap-up-step ] end to go-uphill-inertia ;; draft ask turtles with [not on-peak?] [ set label inertia let old-patch patch-here ;; used???? let heading-uphill uphill-heading set heading ( inertia * old-heading) + (1 - inertia) * heading-uphill step-or-reverse ( 1 ) set old-heading heading ;; this is a turtle-own variable wrap-up-step ] end to go-use-all-rules ;; runs but not validated, not even one full walk-through ;; first, compute the weighted centroid of all the turtles let new-centroid (list 0 0) if ticks > 1 [ set new-centroid centroid ] ;; can't run on first tick because weath is zero and get division error ;; type "centroid is " show new-centroid ask turtles with [not on-peak?] [ let old-patch patch-here ;; let's find what heading goes uphill let target max-one-of neighbors [height] face target let heading-uphill heading ;; ok soften that with inertia set heading-uphill ( inertia * old-heading) + (1 - inertia) * heading-uphill set old-heading heading ;; this is a turtle-own variable face my-center let heading-group heading set heading (empathy)*(heading-group) + (1 - empathy)*(heading-uphill) ;; set heading (group-weight)*(heading-group) + (1 - group-weight)*(heading-uphill) step-or-reverse ( 1 ) set old-heading heading ;; this is a turtle-own variable wrap-up-step ] end to go-uphill-everyone ;;draft ;; first, comput the weighted centroid of all the turtles let new-centroid (list 0 0) if ticks > 1 [ set new-centroid centroid ] ;; can't run on first tick because weath is zero and get division error ;; type "centroid is " show new-centroid ask turtles with [not on-peak?] [ let old-patch patch-here ;; let's find what heading goes uphill let target max-one-of neighbors [height] face target let heading-uphill heading ifelse ( limit-horizon? = true ) [ face local-group-center ] [ face my-center] face my-center ;; <&&&&&&&&&&&&&&&&&&&&&& if we limit horizon I think it can create polarization , split up groups. let heading-group heading set my-heading-uphill heading-uphill set my-heading-group heading-group if (( heading-uphill > 270) and ( heading-group < 90 )) [ set heading-uphill ( heading-uphill - 360 ) ] if (( heading-uphill < 90 ) and ( heading-group > 270 )) [ set heading-group ( heading-group - 360 ) ] set heading (empathy)*(heading-group) + (1 - empathy)*(heading-uphill) ;; set heading (group-weight)*(heading-group) + (1 - group-weight)*(heading-uphill) step-or-reverse ( 1 ) wrap-up-step ] end ;================end of turtle movement commands ======= to snapshot ;; save a picture of the whole interface to disk, bare bones draft only ;; ask for a file-name ;; This should set a directory and base file name then increment a number add .jpg and save silently set timestamp date-and-time ifelse ( netlogo-web? = true ) [ print " export snapshot only works locally " ] [ run "export-interface user-new-file" ] ;; UNCOMMENT the next line to save a snapshot of the image to disk only works locally won't compile netlogo web ;; export-interface user-new-file ;; print OK end to apologize print " that function is not yet working!" set stop-now? true end to move-turtles if-else leave-a-trail? [ ask turtles [ pen-down ]] [ ask turtles [ pen-up ]] (if-else rule-to-use = "single: wander" [ go-wander ] rule-to-use = "single: go-uphill" [ go-uphill ] rule-to-use = "single: find-everyone" [ go-find-everyone ] rule-to-use = "pair: uphill with inertia" [ go-uphill-inertia ] rule-to-use = "pair: uphill with everyone" [ go-uphill-everyone ] rule-to-use = "triple: use all three" [ go-use-all-rules ] ; else commands [ error (word " unexpected rule-to-use choice: " rule-to-use) ] ) ;;set stop-now? false end to make-landscape set patch-count count patches; ask patch -7 -4 [set pcolor 125] ;; always make at least one hill if number-of-hills >= 2 [ ask patch 3 6 [set pcolor 95] ] if number-of-hills >= 3 [ ask patch 7 -5 [set pcolor 75] ] repeat 15 [ diffuse pcolor 1] ;; smooth that out somewhat if noise? [ ask N-of ( noise-density * patch-count) patches [set pcolor pcolor + noise-size] ] repeat 2 [ diffuse pcolor 1] ;; smooth the noise ask max-one-of patches [pcolor] [set peak-height pcolor] ask patches [ set height pcolor] ask patches [ set pcolor scale-color red height 0 peak-height ] end to make-turtles ; set the turtle color from the user menu let use-color green ;; default if turtle-color = "green" [ set use-color green ] if turtle-color = "white" [ set use-color white ] if turtle-color = "black" [ set use-color black ] if turtle-color = "red" [ set use-color red ] create-turtles turtle-count [ ;; turtle-count is set by a slider setxy random-xcor random-ycor set on-peak? FALSE set color use-color set size 2 set shape turtle-shape set wealth 0 set maxwealth 0 set good-step-count 0 set step-size-multiplier 1.0 if-else ( randomize-inertia? ) [ set inertia precision (random-float 1) 2 ] [ set inertia inertia-static ] if-else ( randomize-group-weight? ) [set empathy precision (random-float 1) 2 ] ;; set to random uniform on [0,1] [set empathy group-weight] ;; set in slider ] end to help ;; UNCOMMENT this section if you have a help file on your local PC ;if-else file-exists? "help-for-goals.txt" ; [ ; file-open "help-for-goals.txt" ; while [not file-at-end? ] ; [print file-read-line] ; file-close ; ] ; [ print "The help file 'help-for-goals.txt' was not found!" ; ] end
There are 10 versions of this model.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
goal-seeking-boids.png | preview | Preview for 'goal-seeking-boids' | over 4 years ago, by R. Wade Schuette | Download |
This model does not have any ancestors.
This model does not have any descendants.