NetLogo/NetLogo — Issue #92: NetLogo crashed while HubNet clients are logging in...?
Author: davidatnie
Created: 2012-02-24 14:06:23+00:00
State: open

Hello,

We use NetLogo in a school in Singapore (particularly HubNet), and I think we may have run into a bug...
So we used a modified Disease model in a class of about 20 students. Just shortly after the activity was started (when roughly 3/4 of the students have logged in), it suddenly crashed, giving the error message below.

We closed and then restarted the host, and asked the students to log back in, but again after about 3/4 of them have logged in, it crashed again (we had this for 4 times before switching to another model). The error messages are as follows:

Crash 1

error (NullPointerException)
while observer running ASK
called by procedure LISTEN-CLIENTS
called by procedure GO
called by Button 'GO'

NetLogo is unable to supply you with more details about this error. Please report the problem
to bugs@ccl.northwestern.edu, or at https://github.com/NetLogo/NetLogo/issues, and paste the
contents of this window into your report.

java.lang.NullPointerException
at org.nlogo.prim._asm_procedurelistenclients_equal_8.report(:1)
at org.nlogo.nvm.Context.evaluateReporter(Context.java:228)
at org.nlogo.prim._asm_procedurelistenclients_ask_7.perform(:2)
at org.nlogo.nvm.Context.stepConcurrent(Context.java:91)
at org.nlogo.nvm.ConcurrentJob.step(ConcurrentJob.java:82)
at org.nlogo.job.JobThread.org$nlogo$job$JobThread$$runPrimaryJobs(JobThread.scala:143)
at org.nlogo.job.JobThread$$anonfun$run$1.apply$mcV$sp(JobThread.scala:78)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at scala.util.control.Exception$Catch.apply(Exception.scala:88)
at org.nlogo.util.Exceptions$.handling(Exceptions.scala:41)
at org.nlogo.job.JobThread.run(JobThread.scala:75)

NetLogo 5.0RC10
main: org.nlogo.app.AppFrame
thread: JobThread
Java HotSpot(TM) 64-Bit Server VM 1.6.0_29 (Apple Inc.; 1.6.0_29-b11-402-10M3527)
operating system: Mac OS X 10.6.8 (x86_64 processor)
Scala version 2.9.1.final
JOGL: (3D View not initialized)
OpenGL Graphics: (3D View not initialized)
model: Disease GS_v.2.6a

09:14:49.579 SwitchedTabsEvent (org.nlogo.app.Tabs) AWT-EventQueue-0
09:14:49.578 RuntimeErrorEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0
09:14:49.403 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:14:49.403 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:14:49.402 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:14:49.402 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:14:49.402 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:14:49.402 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:14:49.402 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:14:49.402 PeriodicUpdateEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0

Crash 2
error (NullPointerException)
while observer running ASK
called by procedure LISTEN-CLIENTS
called by procedure GO
called by Button 'GO'

NetLogo is unable to supply you with more details about this error. Please report the problem
to bugs@ccl.northwestern.edu, or at https://github.com/NetLogo/NetLogo/issues, and paste the
contents of this window into your report.

java.lang.NullPointerException
at org.nlogo.prim._asm_procedurelistenclients_equal_8.report(:1)
at org.nlogo.nvm.Context.evaluateReporter(Context.java:228)
at org.nlogo.prim._asm_procedurelistenclients_ask_7.perform(:2)
at org.nlogo.nvm.Context.stepConcurrent(Context.java:91)
at org.nlogo.nvm.ConcurrentJob.step(ConcurrentJob.java:82)
at org.nlogo.job.JobThread.org$nlogo$job$JobThread$$runPrimaryJobs(JobThread.scala:143)
at org.nlogo.job.JobThread$$anonfun$run$1.apply$mcV$sp(JobThread.scala:78)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at scala.util.control.Exception$Catch.apply(Exception.scala:88)
at org.nlogo.util.Exceptions$.handling(Exceptions.scala:41)
at org.nlogo.job.JobThread.run(JobThread.scala:75)

NetLogo 5.0RC10
main: org.nlogo.app.AppFrame
thread: JobThread
Java HotSpot(TM) 64-Bit Server VM 1.6.0_29 (Apple Inc.; 1.6.0_29-b11-402-10M3527)
operating system: Mac OS X 10.6.8 (x86_64 processor)
Scala version 2.9.1.final
JOGL: (3D View not initialized)
OpenGL Graphics: (3D View not initialized)
model: Disease GS_v.2.6a

09:15:58.218 SwitchedTabsEvent (org.nlogo.app.Tabs) AWT-EventQueue-0
09:15:58.213 RuntimeErrorEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:15:58.065 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:15:58.065 PeriodicUpdateEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0

crassh3
error (NullPointerException)
while observer running ASK
called by procedure LISTEN-CLIENTS
called by procedure GO
called by Button 'GO'

NetLogo is unable to supply you with more details about this error. Please report the problem
to bugs@ccl.northwestern.edu, or at https://github.com/NetLogo/NetLogo/issues, and paste the
contents of this window into your report.

java.lang.NullPointerException
at org.nlogo.prim._asm_procedurelistenclients_equal_8.report(:1)
at org.nlogo.nvm.Context.evaluateReporter(Context.java:228)
at org.nlogo.prim._asm_procedurelistenclients_ask_7.perform(:2)
at org.nlogo.nvm.Context.stepConcurrent(Context.java:91)
at org.nlogo.nvm.ConcurrentJob.step(ConcurrentJob.java:82)
at org.nlogo.job.JobThread.org$nlogo$job$JobThread$$runPrimaryJobs(JobThread.scala:143)
at org.nlogo.job.JobThread$$anonfun$run$1.apply$mcV$sp(JobThread.scala:78)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at scala.util.control.Exception$Catch.apply(Exception.scala:88)
at org.nlogo.util.Exceptions$.handling(Exceptions.scala:41)
at org.nlogo.job.JobThread.run(JobThread.scala:75)

NetLogo 5.0RC10
main: org.nlogo.app.AppFrame
thread: JobThread
Java HotSpot(TM) 64-Bit Server VM 1.6.0_29 (Apple Inc.; 1.6.0_29-b11-402-10M3527)
operating system: Mac OS X 10.6.8 (x86_64 processor)
Scala version 2.9.1.final
JOGL: (3D View not initialized)
OpenGL Graphics: (3D View not initialized)
model: Disease GS_v.2.6a

09:18:00.771 SwitchedTabsEvent (org.nlogo.app.Tabs) AWT-EventQueue-0
09:18:00.766 RuntimeErrorEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0
09:18:00.753 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:18:00.753 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:18:00.752 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:18:00.752 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:18:00.752 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:18:00.752 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:18:00.752 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:18:00.752 PeriodicUpdateEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0

crash after androids added

error (NullPointerException)
while observer running ASK
called by procedure LISTEN-CLIENTS
called by procedure GO
called by Button 'GO'

NetLogo is unable to supply you with more details about this error. Please report the problem
to bugs@ccl.northwestern.edu, or at https://github.com/NetLogo/NetLogo/issues, and paste the
contents of this window into your report.

java.lang.NullPointerException
at org.nlogo.prim._asm_procedurelistenclients_equal_8.report(:1)
at org.nlogo.nvm.Context.evaluateReporter(Context.java:228)
at org.nlogo.prim._asm_procedurelistenclients_ask_7.perform(:2)
at org.nlogo.nvm.Context.stepConcurrent(Context.java:91)
at org.nlogo.nvm.ConcurrentJob.step(ConcurrentJob.java:82)
at org.nlogo.job.JobThread.org$nlogo$job$JobThread$$runPrimaryJobs(JobThread.scala:143)
at org.nlogo.job.JobThread$$anonfun$run$1.apply$mcV$sp(JobThread.scala:78)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at org.nlogo.job.JobThread$$anonfun$run$1.apply(JobThread.scala:76)
at scala.util.control.Exception$Catch.apply(Exception.scala:88)
at org.nlogo.util.Exceptions$.handling(Exceptions.scala:41)
at org.nlogo.job.JobThread.run(JobThread.scala:75)

NetLogo 5.0RC10
main: org.nlogo.app.AppFrame
thread: JobThread
Java HotSpot(TM) 64-Bit Server VM 1.6.0_29 (Apple Inc.; 1.6.0_29-b11-402-10M3527)
operating system: Mac OS X 10.6.8 (x86_64 processor)
Scala version 2.9.1.final
JOGL: (3D View not initialized)
OpenGL Graphics: (3D View not initialized)
model: Disease GS_v.2.6a

09:28:31.705 SwitchedTabsEvent (org.nlogo.app.Tabs) AWT-EventQueue-0
09:28:31.699 RuntimeErrorEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.app.InterfacePanel$2 (org.nlogo.window.SliderWidget)) AWT-EventQueue-0
09:28:31.561 InterfaceGlobalEvent (org.nlogo.widget.SwitchWidget) AWT-EventQueue-0
09:28:31.561 PeriodicUpdateEvent (org.nlogo.app.App$$anon$1 (org.nlogo.window.GUIWorkspace)) AWT-EventQueue-0

Also, those students who managed to log in mentioned that they're experiencing lag (they were able to move their agent around, though it all appeared jittery)

I'm not exactly sure whether it was caused by our NetLogo code instead of an underlying bug, but just in case, here's the code of the model we ran:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Variable and Breed declarations ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

globals
[
;; variables related to the health of the turtles
old-num-infected ;; number of turtles that had infected? = true during the last pass through the go procedure
clock ;; keeps track of the number of times through the go procedure (if there is at least one turtle infected)
run-number

;; variables used to assign unique color and shape to clients
shape-names ;; list that holds the names of the non-sick shapes a student's turtle can have
colors ;; list that holds the colors used for students' turtles
color-names ;; list that holds the names of the colors used for students' turtles
used-shape-colors ;; list that holds the shape-color pairs that are already being used
max-possible-codes ;; total number of possible unique shape/color combinations

;; quick start instructions variables
quick-start ;; current quickstart instruction displayed in the quickstart monitor
qs-item ;; index of the current quickstart instruction
qs-items ;; list of quickstart instructions

data-as-string ;; holds data to be sent to clients
data-as-list ;; holds data in a list of rows
greatest-tick-in-5-runs ;; holds greatest tick value in the data table, needed for outputting run data horizontally
smallest-tick-in-5-runs ;; holds smallest tick value in the data table, needed for outputting run data horizontally and starting from a non-null infected turtle
last-filled-row ;; needed in filling remaining cells of a colmn with \t if the last row is less than greatest-tick-in-5-runs when a run is ended
first-filled-row ;; needed in filling upper cells of a column with \t if the first row with data is not at top position
recorded-ticks ;; holds ticks at when turtles got infected

num-sick ;; holds number of sick turtles
old-num-sick ;; holds previous number of sick turtles, to facilitate tracking

old-show-sick?
old-show-sick-on-clients?
]

turtles-own
[
infected? ;; if a turtle is sick, infected? is true, otherwise, it is false
base-shape ;; original shape of a turtle
step-size ;; the amount that a turtle will go forward in the current direction
]

breed [ androids android ] ;; created by the CREATE ANDROIDS button; not controlled by anyone, but can become sick and spread sickness
breed [ students student ] ;; created and controlled by the clients

students-own
[
user-id ;; unique id, input by the client when they log in, to identify each student turtle
]

;;;;;;;;;;;;;;;;;;;;;;
;; Setup Procedures ;;
;;;;;;;;;;;;;;;;;;;;;;

to startup
hubnet-set-client-interface "COMPUTER" []
hubnet-reset
make-five-plot-pens
setup-vars
setup-plot
setup-quick-start
end

to setup
reset-ticks
ask androids [ die ]
clear-plot
clear-output
cure-all
setup-vars
setup-plot
end

;; heals all sick turtles, clears and sets up the plot,
;; and clears the lists sent to the calculators
to cure-all
fill-lower-cells

set last-filled-row 0
set first-filled-row -1
set num-sick 0
set old-num-sick 0
set clock 0
ask turtles
[
set infected? false
if breed = students
[ update-sick?-monitor ]
set shape base-shape
]

set old-num-infected 0
set run-number run-number + 1
if( run-number > 5 )
[ set run-number 1 ]
reset-ticks
setup-plot
;;****USING EMBEDDED PLOTS NOW setup-plot
end

;; initialize global variables
to setup-vars
prepare-stage
set run-number 1
reset-data
set old-show-sick? show-sick?
set old-show-sick-on-clients? show-sick-on-clients?
end

to prepare-stage
set clock 0
set old-num-infected 0

set shape-names ["box" "star" "wheel" "target" "cat" "dog"
"butterfly" "leaf" "car" "airplane"
"monster" "key" "cow skull" "ghost"
"cactus" "moon" "heart"]
;; these colors were chosen with the goal of having colors
;; that are readily distinguishable from each other, and that
;; have names that everyone knows (e.g. no "cyan"!), and that
;; contrast sufficiently with the red infection dots and the
;; gray androids
set colors (list white brown green yellow
(violet + 1) (sky + 1))
set color-names ["white" "brown" "green" "yellow"
"purple" "blue"]
set max-possible-codes (length colors * length shape-names)
set used-shape-colors []
end

;; create a temporary plot pen for the current run
;; cycle through a few colors so it is easy to
;; differentiate the runs.
to setup-plot
if run-number mod 5 = 1 [ ;; clear and reset data after every five runs
clear-plot ;; clears the plot
set run-number 1 ;; reset run-number
reset-data
fill-lower-cells
reset-ticks ;; reset time
set last-filled-row 0
set first-filled-row -1
]
set-current-plot-pen ( word "run " run-number )
end

to reset-data
set data-as-string "Time\tSick1\tSick2\tSick3\tSick4\tSick5\n" ;; reset data
set data-as-list (list )
set data-as-list fput data-as-string data-as-list
set recorded-ticks (list )
set recorded-ticks fput "recorded ticks\n" recorded-ticks
set greatest-tick-in-5-runs 0;
set smallest-tick-in-5-runs 10000

set num-sick 0 ;; reset num-sick
set old-num-sick 0 ;; reset num-sick
end

;; creates turtles that wander at random
to make-androids
let numbertomake number
if( ( count turtles ) + number > max-possible-codes )
[
set numbertomake max-possible-codes - count turtles
user-message ( word "Will only create " numbertomake " androids. Maximum number of turtles reached." )
]
create-androids numbertomake
[
move-to one-of patches
face one-of neighbors4
set infected? false
set-unique-shape-and-color
set step-size 1
]
end

;;;;;;;;;;;;;;;;;;;;;;;;
;; Runtime Procedures ;;
;;;;;;;;;;;;;;;;;;;;;;;;

to go
if( old-show-sick? != show-sick? )
[
if( show-sick? = true )
[
set show-sick-on-clients? true ;; tie show-sick-on-clients? to TRUE if show-sick? is TRUE
ask students with [ infected? ]
[ update-sick?-monitor ]
set old-show-sick-on-clients? show-sick-on-clients?
]
ask turtles with [ infected? ]
[ set-sick-shape ]
set old-show-sick? show-sick?
]

if( old-show-sick-on-clients? != show-sick-on-clients? )
[
if( show-sick-on-clients? = false )
[
set show-sick? false ;; tie show-sick? to FALSE if show-sick-on-clients? is FALSE
ask turtles with [ infected? ]
[ set-sick-shape ]
set old-show-sick? show-sick?
]
ask students with [ infected? ]
[ update-sick?-monitor ]
set old-show-sick-on-clients? show-sick-on-clients?
]

every 0.1
[
listen-clients
display
;;allow the androids to wander around the view
if wander?
[ androids-wander ]

if( count turtles with [infected?] > 0 )
[
ask turtles with [ infected? ]
[ spread-disease ]
ask students
[ update-sick?-monitor ]
]

;; capture the clock (placed at first column) and number of infected turtles for each run (placed at subequent columns)
;; plot data
;; only do those when there are at least one infected turtle
let current-infected count turtles with [infected?]
if( current-infected > 0 )
[
set num-sick current-infected
ifelse( num-sick != old-num-sick )
[ add-data clock run-number current-infected ] ;; add full data if there's change in num-sick
[ add-data clock run-number "\t" ] ;; add a tab if there's no change in num-sick
set old-num-sick num-sick
;; plotxy clock current-infected
set clock clock + 1
]
if( current-infected = count turtles )
[
user-message( "There are no more healthy turtles to infect. Activity paused." )
stop
]
tick
]
end

;; controls the motion of the androids
to androids-wander
every android-delay
[
ask androids
[
;;face one-of neighbors4 ;; jagged move behavior
rt random-float 35 - random-float 35 ;; smoother move behavior
if( can-move? 1 = false )
;;[ rt random-float 145 - random-float 215 ] ;; if can't move forward, try to bounce back
[ set heading heading - 180 ]
fd .1
]
]
end

;; additional check infect called when student moves to new patch
;; added to avoid rewarding movement
to student-move-check-infect
if infected?
[ spread-disease ]

ask other turtles-here with [ infected? ]
[ ask myself [ maybe-get-sick ] ]
end

;; spread disease to other turtles here
to spread-disease
ask other turtles-here [ maybe-get-sick ]
end

;; turtle procedure -- roll the dice and maybe get sick
to maybe-get-sick
if not infected? [
if ((random 100) + 1) <= infection-chance
[ get-sick ] ]
end

;; turtle procedure -- set the appropriate variables to make this turtle sick
to get-sick
set infected? true
set-sick-shape
if breed = students
[ update-sick?-monitor ]
end

;; turtle procedure -- change the shape of turtles to its sick shape
;; if show-sick? is true and change the shape to the base-shape if
;; show-sick? is false
to set-sick-shape
ifelse show-sick?
[
;; we want to check if the turtles shape is already a sick shape
;; to prevent flickering in the turtles
if shape != word base-shape " sick"
[ set shape word base-shape " sick" ]
]
[
;; we want to check if the turtles shape is already a base-shape
;; to prevent flickering in the turtles
if shape != base-shape
[ set shape base-shape ]
]
end

;; causes the initial infection in the turtle population --
;; infects a random healthy turtle until the desired number of
;; turtles are infected
to infect-turtles
let healthy-turtles turtles with [ not infected? ]

ifelse count healthy-turtles <= initial-number-sick
[
ask healthy-turtles
[
get-sick
set-sick-shape
]
user-message "There are no more healthy turtles to infect. Activity paused."
stop
]
[
ask n-of initial-number-sick healthy-turtles
[
get-sick
set-sick-shape
]
]
end

;;;;;;;;;;;;;;;;;;;;;;;
;; HubNet Procedures ;;
;;;;;;;;;;;;;;;;;;;;;;;

;; determines which client sent a command, and what the command was
to listen-clients
while [ hubnet-message-waiting? ]
[
hubnet-fetch-message
ifelse hubnet-enter-message?
[ create-new-student ]
[
ifelse hubnet-exit-message?
[ remove-student ]
[
ask students with [ user-id = hubnet-message-source ]
[ execute-command hubnet-message-tag ]
]
]
display
]
end

;; NetLogo knows what each student turtle is supposed to be
;; doing based on the tag sent by the node:
;; step-size - set the turtle's step-size
;; Up - make the turtle move up by step-size
;; Down - make the turtle move down by step-size
;; Right - make the turtle move right by step-size
;; Left - make the turtle move left by step-size
;; Get a Different Turtle - change the turtle's shape and color
to execute-command [command]
if command = "step-size"
[
set step-size hubnet-message
stop
]
if command = "Up"
[ execute-move 0 stop ]
if command = "Down"
[ execute-move 180 stop ]
if command = "Right"
[ execute-move 90 stop ]
if command = "Left"
[ execute-move 270 stop ]
if command = "Change Appearance"
[ execute-change-turtle stop ]
end

;; Create a turtle, set its shape, color, and position
;; and tell the node what its turtle looks like and where it is
to create-new-student
create-students 1
[
setup-student-vars
send-info-to-clients
;; we want to make sure that the clients all have the same plot ranges,
;; so when somebody logs in, set the plot ranges to themselves so that
;; everybody will have the same size plots.
set-plot-y-range plot-y-min plot-y-max
set-plot-x-range plot-x-min plot-x-max
]
end

;; sets the turtle variables to appropriate initial values
to setup-student-vars ;; turtle procedure
set user-id hubnet-message-source
set-unique-shape-and-color
move-to one-of patches
face one-of neighbors4
set infected? false
set step-size 1
end

;; pick a base-shape and color for the turtle
to set-unique-shape-and-color
let code random max-possible-codes
while [member? code used-shape-colors and count students < max-possible-codes]
[
set code random max-possible-codes
]
set used-shape-colors (lput code used-shape-colors)
set base-shape item (code mod length shape-names) shape-names
set shape base-shape
set color item (code / length shape-names) colors
end

;; report the string version of the turtle's color
to-report color-string [color-value]
report item (position color-value colors) color-names
end

;; sends the appropriate monitor information back to the client
to send-info-to-clients
hubnet-send user-id "You are a:" (word (color-string color) " " base-shape)
hubnet-send user-id "Located at:" (word "(" pxcor "," pycor ")")
update-sick?-monitor
end

to update-sick?-monitor
ifelse show-sick-on-clients?
[
let status ""
ifelse( infected? )
[ set status "Yes" ]
[ set status "No" ]
hubnet-send user-id "Sick?" status
]
[ hubnet-send user-id "Sick?" "N/A" ]
end

;; Kill the turtle, set its shape, color, and position
;; and tell the node what its turtle looks like and where it is
to remove-student
ask students with [user-id = hubnet-message-source]
[
set used-shape-colors remove my-code used-shape-colors
die
]
end

;; translates a student turtle's shape and color into a code
to-report my-code
report (position base-shape shape-names) + (length shape-names) * (position color colors)
end

;; Cause the students to move forward step-size in new-heading's heading
to execute-move [new-heading]
set heading new-heading
fd step-size
hubnet-send user-id "Located at:" (word "(" pxcor "," pycor ")")

;; maybe infect or get infected by turtles on the patch student moved to
student-move-check-infect
end

to execute-change-turtle
ask students with [user-id = hubnet-message-source]
[
set used-shape-colors remove my-code used-shape-colors
show-turtle
set-unique-shape-and-color
hubnet-send user-id "You are a:" (word (color-string color) " " base-shape)
if infected?
[ set-sick-shape ]
]
end

;;; this procedure is handy for testing out additional shapes and colors;
;;; you can call it from the Command Center
to show-gamut
;; (for this model to work with NetLogo's new plotting features,
;; __clear-all-and-reset-ticks should be replaced with clear-all at
;; the beginning of your setup procedure and reset-ticks at the end
;; of the procedure.)
__clear-all-and-reset-ticks
setup-vars
create-ordered-turtles max-possible-codes [
fd max-pxcor * 0.7
if who mod 3 = 0
[ fd max-pxcor * 0.3 ]
if who mod 3 = 1
[ fd max-pxcor * 0.15 ]
set heading 0
set-unique-shape-and-color
]
ask patch 0 0 [
ask patches in-radius 2 [
sprout-androids 1 [
set shape "android"
set color gray
]
]
]
user-message (word length shape-names
" shapes * "
length colors
" colors = "
max-possible-codes
" combinations")
end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Quick Start Procedures ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; instructions to quickly setup the model, and clients to run this activity
to setup-quick-start
set qs-item 0
set qs-items
[
"Teacher: Follow these directions to run the HubNet activity."
"Optional: Zoom In (see Tools in the Menu Bar)"
"Optional: Change any of the settings."
"If you want to add androids press the CREATE ANDROIDS button"
"Press the GO button."
"Everyone: Open up a HubNet Client on your machine and..."
"type your user name, select this activity and press ENTER."
"Teacher: Have the students move their turtles around to..."
"acquaint themselves with the interface."
"Press the INFECT button to start the simulation."
"Everyone: Watch the plot of the number infected."

"Teacher: To run the activity again with the same group,..."
"stop the model by pressing the GO button, if it is on."
"Change any of the settings that you would like."
"Press the CURE-ALL button to keep the androids, or SETUP to clear them"
"Teacher: Restart the simulation by pressing the GO button again."
"Infect some turtles and continue."

"Teacher: To start the simulation over with a new group,..."
"stop the model by pressing the GO button, if it is on..."
"have all the students log out..."
"or press the RESET button in the Control Center"
"start these instructions from the beginning"
]
set quick-start (item qs-item qs-items)
end

;; view the next item in the quickstart monitor
to view-next
set qs-item qs-item + 1
if qs-item >= length qs-items
[ set qs-item length qs-items - 1 ]
set quick-start (item qs-item qs-items)
end

;; view the previous item in the quickstart monitor
to view-prev
set qs-item qs-item - 1
if qs-item < 0
[ set qs-item 0 ]
set quick-start (item qs-item qs-items)
end

to add-data [ t rn cinf ]
let targetrow find-targetrow t
if( first-filled-row = -1 ) ;; this would fire only once every run since first-filled-row is always initialized with -1
[
fill-upper-cells targetrow
set first-filled-row 1
]

let new-row construct-new-data t rn cinf
ifelse ( member? t recorded-ticks = false )
[
set data-as-list insert-item targetrow data-as-list new-row
set recorded-ticks insert-item targetrow recorded-ticks t
ifelse( t < smallest-tick-in-5-runs )
[
set smallest-tick-in-5-runs t
set last-filled-row 1
]
[
ifelse( t > greatest-tick-in-5-runs )
[
set greatest-tick-in-5-runs t
set last-filled-row length data-as-list
]
[
set last-filled-row targetrow
]
]
]
[
set data-as-list replace-item targetrow data-as-list new-row
set last-filled-row targetrow
]
end

to-report find-targetrow [ t ]
let targetrow 1
;; check if tick t is already in the recorded-ticks list
ifelse ( member? t recorded-ticks = false )
[
;; if no, need to add new row:
;; determine targetrow
ifelse( t < smallest-tick-in-5-runs ) ;; see if its at the top
[
set targetrow 1
report targetrow
]
[
ifelse( t > greatest-tick-in-5-runs ) ;; see if its at the bottom
[
set targetrow length recorded-ticks
report targetrow
]
[ ;; else, find where in the narrow gap between smallest-tick-in-5 runs and first running ticks
let i 1
let pos-next-biggest-after-t 1
while[ i < length recorded-ticks ]
[
let it item i recorded-ticks
if( t > it )
[ set pos-next-biggest-after-t i ]
set i i + 1
]
set targetrow pos-next-biggest-after-t + 1 ;;!!!!
report targetrow
]
]
]
[
report position t recorded-ticks
]
end

to-report construct-new-data [ t rn cinf ]
let data-for-earlier-runs ""
let data-for-current-run word cinf "\n"
ifelse ( member? t recorded-ticks = false )
[
;; construct data for a new line
let i 1
while[ i < rn ]
[
set data-for-earlier-runs ( word data-for-earlier-runs "\t" )
set i (i + 1)
]
let new-row ( word t "\t" data-for-earlier-runs data-for-current-run )
report new-row
]
[
;; append data to the end of an existing line
let tpos find-targetrow t
let old-row item tpos data-as-list
set old-row substring old-row 0 ( ( length old-row ) - 1 )
let new-row ( word old-row "\t" cinf "\n" )
report new-row
]
end

to send-plot-data-to-students
ask-concurrent students [
hubnet-send user-id "plot-data" data-as-string
]
end

to-report break-to-list [ d t ]
let dl (list )
let i 1
while[ i <= ( t * 6 ) - 1 ]
[

let mark1 position "\t" d
let mark2 position "\n" d
let mark min list (mark1) (mark2)
let chunk substring d 0 (mark + 1)
set d substring d (mark + 2) (length d)
set dl lput chunk dl
set i ( i + 1 )
]
set dl lput d dl
report dl
end

to-report join-to-string [ dl ]
let d ""
foreach dl
[
set d ( word d ? )
]
set d word d "0\t0\t0\t0\t0\t0\n"
report d
end

to fill-lower-cells
if( run-number > 1 and length data-as-list > 2) [
let old-row ""
let target-row 0
let new-row ""
while[ last-filled-row < length data-as-list - 1]
[
set target-row last-filled-row + 1
set old-row item target-row data-as-list
set old-row substring old-row 0 ( length old-row - 1)
set new-row (word old-row "\t\n" )
set data-as-list replace-item target-row data-as-list new-row
set last-filled-row last-filled-row + 1
]
]
end

to fill-upper-cells [ stoppos ]
let old-row ""
let target-row 1
let new-row ""
let i 1
while[ i < stoppos ]
[
set target-row i
set old-row item target-row data-as-list
set old-row substring old-row 0 ( length old-row - 1 )
set new-row ( word old-row "\t\n" )
set data-as-list replace-item target-row data-as-list new-row
set i i + 1
]
end
to-report insert-item [ tpos dlist nrow ]
let tempheadlist sublist dlist 0 (tpos )
let temptaillist (list )
if( length dlist > 1 )
[ set temptaillist sublist dlist tpos ( length dlist ) ]
let newdlist tempheadlist
set newdlist lput nrow newdlist
let i 0
while[ i < length temptaillist ]
[
let moverow item i temptaillist
set newdlist lput moverow newdlist
set i i + 1
]
report newdlist
end

to show-data
clear-output
set data-as-string ""
set data-as-string join-to-string data-as-list
output-print data-as-string
end

to clear-data
clear-output
end

to make-five-plot-pens
let i 1
while [ i <= 5 ]
[
create-temporary-plot-pen word "run " run-number
set-plot-pen-color item (run-number mod 5)
[blue red green orange violet]
set i i + 1
]
end

; Copyright 1999 Uri Wilensky and Walter Stroup. All rights reserved.
; The full copyright notice is in the Information tab.

Could it be that this is a bug in HubNet..? Or, if it was caused by my code, I'd really appreciate it if you can suggest any possible solution for it...

Thanks in advance :)

David