How to get the id number of a new turtle just created? - netlogo

I have the following code where I hatch a new agent,
to t-of-slowdown [ es-poi ]
if we-look > 0 [
set we-look (we-look - 1)
if (we-look <= 0) [
if es-poi and (not any? events-here) [
hatch-events 1 [
set color green
set size 5
set is-poi? true
set new-poi true
let m [[ end2 ] of cur-link] of myself
move-to m ]
set events-x ([who] of events-here)
show events-x
set we-poi-var va-geometric (1 / 1500) + we-ticks poi
set sera-poi false
]
set impregna true
set color red
set seguir true
set we-look random-normal 120 20 ;time to watch an event
]
]
end
which is run in a turtle context (walkers breed)
A walker is moving by a 'link' (another procedure which calls this one), and when a counter is <0,
this code generates a new event (events breed) and places it in the same place where the walker is (cur-link is the current walker link).
After that, the walker must get the id number of the new event
set events-x ([who] of events-here)
The problem here is that variable events-x get an empty list []. The next time the walker passes by the same event it does get the number-id of the event.
Something must be wrong but I can not guess what it is.
I would appreciate very much if someone could take a look and point me some help.
Regards

You could:
let child-who -1
hatch-events 1 [
...
set child-who who
...
]
set events-x child-who
Or:
hatch-events 1 [
...
let child-who who
ask myself [ set events-x my-who ]
...
]
Both of these are a bit clunky, sadly. The second one avoids needing to initialize child-who to a meaningless value, but it requires using myself, a primitive that is likely to mystify the reader.
You could avoid both problems with:
let parent self
hatch-events 1 [
...
let child-who who
ask parent [ set events-x child-who ]
...
]
(But note that using who numbers at all, for anything, is rarely the best and most idiomatic solution to any problem. It's almost always better to store a reference to the turtle itself.)

Related

How to implement a timer for each turtle in netlogo

I am trying to implement a timer for each turtle in Netlogo
so I can take the minimum value, maximum and average time taken for each turtle.
Can anyone help
You haven't said what you actually want timed (or given any code attempt). Any time you need a turtle to remember anything from one tick to the next, you need a variable. The simplest code for a timer is to have a variable that you set to the current value of ticks when the process starts and subtract that start time from the current value of ticks when the process stops. Here is a complete model example:
turtles-own
[ start-time
time-taken
]
to setup
clear-all
create-turtles 20
[ set start-time 2 + random 10
set time-taken -1
]
reset-ticks
end
to go
let movers turtles with [time-taken = -1 and start-time <= ticks]
ask movers
[ set heading random 360
forward 1 + random 3
if random-float 1 < 0.05 [ set time-taken ticks - start-time ]
]
tick
end
And check out the new Time extension if you want your timers to use real time units (seconds, minutes, years...) and have non-integer values.
https://github.com/NetLogo/Time-Extension
Look at primitives such as time:difference-between
For example, you could do this coding that flags the turtle you want to monitor and increments the flag variable when an event occurs. You can then monitor it in the BehaviorSpace and analyses the results output in a csv file. For example, the following codes:
globals [ID]
turtles-own [special-turtle]
to create-turtle
crt 1 [
setxy min-pxcor 0
set heading 90
set special-turtle false
set ID who]
end
to go
;omitted
special-turtles
tick
end
to special-turtles
ask turtles-on patch 0 0 [set ID who]
ask max-one-of turtles [who] [set special-turtle true]
ask turtles with [special-turtle = true][set special-turtle (special-turtle + 1)]
end
I think there is something that none of the previous answers considered: the way you implement your timer depends on how you want to use the measurement.
1 - If you want to read the measurement only after the measurement is completed
The expression "after the measurement is completed" can mean both that you want to read it at some point later during the model, or maybe even just from some model's output.
The approach I'd take in this case is similar to what JenB suggested, but I believe you can put it a bit simpler because here I only use one extra turtle variable (apart from my-variable, that is there only to represent something that you already have in your model):
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10
end
to go
; Here you have your normal code. When you need, just include
; 'start-timer' and 'stop-timer'. For simplicity, let's
; say you want to count how long does each turtle take
; to get from a value of 1 to a value of 5 for my-variable.
; You can just do:
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
start-timer
]
if (my-variable = 5) [
stop-timer
type "I am turtle " type who type " and it took me " type my-timer print " ticks."
die
]
]
tick
if (not any? turtles) [stop]
end
to start-timer
set my-timer ticks
end
to stop-timer
set my-timer (ticks - my-timer)
end
Note that most of the code is there only to make a full reproducible example, but the actual implementation only consists of my-timer, to start-timer and to stop-timer.
You can take this approach because the hypothesis here is that you will be interested in reading the measurement only after to stop-timer happened.
Otherwise, see point 2.
2 - If you want to be able to read the measurement at any moment during the simulation
In this case, you need to make the timer progress as time progresses (as opposed to point 1, where you could just take the initial and final time, and make the difference between the two).
I guess the easiest way to do this is to conditionally increment the timer every time there is a tick.
Taking the same example as before, it would be something like:
turtles-own [
my-variable ; This represents something you have in your model, to be used as a condition for the timer
timer-active?
my-timer
]
to setup
clear-all
reset-ticks
create-turtles 10 [
set timer-active? FALSE
]
end
to go
ask turtles [
if (random 10 < 2) [
set my-variable (my-variable + 1)
]
if (my-variable = 1) [
set timer-active? TRUE
]
if (my-variable = 5) [
set timer-active? FALSE
]
]
tick
ask turtles with [timer-active?] [
set my-timer (my-timer + 1)
]
if (count turtles with [my-variable < 5] = 0) [stop]
end
This way, you will be able to see at any moment what is the current value of my-timer for each turtle.

How to give a score when an element is pulled out from a list?

I would like to implement a part of code where agents can get a score when they pick an element from a list generated from a specific turtle.
I set
breed [playersA playerA]
breed [playersB playerB]
breed [balls ball]
playersA-own[
my-list
new_ball
score
]
playersB-own[
my-list
new_ball
score
]
to setup
clear-all
create-playersA 10
ask playerA 0 [ create-links-with other playersA ]
ask playerA 2 [ create-link-with playerA 1 ]
create-playersB 10
ask playerB 0 [ create-links-with other playersB ]
ask playerB 2 [ create-link-with playerA 1 ]
ask playersA[
set my-list []
set score 0
]
ask playersB[
set my-list []
set score 0
]
end
to go
let selected nobody
let team-player nobody
set selected one-of turtles with [breed=playersA or breed=playersB]
ifelse [breed = playersA] of selected[
ask selected [
set size [count link-neighbors] of self
show size
]
create-balls 1[
hide-turtle
]
]
[ ask selected [
set size [count link-neighbors] of self
show size
]
create-balls 1[
hide-turtle
]
]
set team-player link-neighbors with [breed = playersA]
ask team_player [
set my-list lput my-ball my-list
]
end
The above code should select on random turtle and add a new ball to its neighbours list. What I would need is probably a counter that can compute how many balls were shared between players.
Could you please help me to figure out with it?
Thanks
The code you posted has many problems that prevent it from passing error-checking in the editor. Some of these produce surprising error messages that don't even make sense, and they happen because the logic mixes contexts -- that is, some commands make sense for the "observer" level, some require being in a "turtle" context, etc.
I think you are trying to do too much at once, and trying to add a counter to code that already does not work. First you have to fix the code you have and then you can see where to add a counter.
You absolutely must understand how the unique agent id number "who" works. Each turtle has a unique who number assigned, starting with zero. It doesn't matter whether the breed of turtle is playerA or playerB or a ball, it will have a unique number. Once you create your first 10 turtles, of the PlayerA breed, they will have who numbers 0 through 9. Then, when you create the next 10 turtles, of PlayerB breed, they will get assigned who numbers of 10 through 19. If you then create a ball, say, it will have a who number of 20.
So there will never be a PlayerB with a who number of 0 or 1 or 2. Those numbers will already be used by PlayerA. Your setup will crash with the error:
playera 0 is not a PLAYERB error while observer running PLAYERB
called by Command Center
Even with just PlayerA, it is not clear what kind of network you want to build in the setup code. Why would everyone link to player 0, but then also add a single link between player 1 and player 2? Since players only "see" their linked team-mates, only player zero will see everyone else. Other players will have only one or two link-neighbors, so they will never update everyone else's my-lists.
create-playersA 10
ask playerA 0 [ create-links-with other playersA ]
ask playerA 2 [ create-link-with playerA 1 ]
Anyway, I would suggest that you get this much working correctly before trying to add counting.
I don't think you can do that by just looking at the code. You need to get rid of as much complexity as you can, and then use shapes, colors, and numerous print statements to see whether each command is doing what you think it should do. Complex working code almost always evolves from simple working code.
So get rid of PlayersB entirely ( comment out the code ), only create 5 players A, and change the colors and shapes as you process each step to confirm that it is working. The editor lets you use ctrl-; to comment out entire blocks of code, or un-comment them at once, so comment out everything you possibly can while you are getting one step to work, then uncomment the next section, get that to work, etc.
When you finally get everything working, you can comment out all your print statements that you used in development.
Anyway, I refactored your code, added many comment, and added many print statements, and finally got it to run. If you run just setup and look at the view, you will see what I mean about the network. ( I shut off wrapping in the view so the network looks right.)
Here's my revision of your code. It prints out what is in each player's my-list after each step, so you can see at a glance if it is doing what you want, or not. ( It's not.)
I added the who numbers as a label to each player in the view so you can see what I mean.
It produces helpful output like:
let's confirm that the lists have been updated. Here's the my-lists
for playersA [[5 5 5 5 10] [0 0 0 0 0] [0 8 8] [0 0] [0 9]]
Get the setup step to work correctly and generate the network you want before you even try to fix the go section.
breed [playersA playerA]
breed [playersB playerB]
breed [balls ball]
playersA-own[
my-list
new_ball
score
]
playersB-own[
my-list
new_ball
score
]
to setup
clear-all
;; for debugging, only create 3 players and inspect the results to confirm it's working as you intended
;; use labels to see player numbers in the view
create-playersA 5 [ set size 1 set color blue set shape "square" setxy random-xcor random-ycor set label who]
ask playerA 0 [ create-links-with other playersA [set color blue]]
ask playerA 2 [ create-link-with playerA 1 [set color red]]
create-playersB 5 [ set size 2 set color yellow set shape "person" setxy random-xcor random-ycor set label who]
; comment out this code until create-playersA is working properly
; ask playerB 0 [ create-links-with other playersB ]
; ask playerB 2 [ create-link-with playerA 1 ] ;; copy-and-paste error? link with playerB intended?
ask playersA[
set my-list []
set score 0
]
ask playersB[
set my-list []
set score 0
]
reset-ticks
end
to go
let selected nobody
let team-players nobody
let hot-ball nobody
set selected one-of turtles with [
breed = playersA
;; or breed = playersB ;; always select one of playersA for debugging this code
]
print ( word "At point 1, we selected turtle " [who] of selected " with breed " [breed] of selected)
;; we're still in the observer context here
ifelse [breed = playersA] of selected [ ;; by mentioning breed, we shift into a turtle context silently
print ( word " entering the TRUE part of the if-else statement " )
ask selected [
set size [count link-neighbors] of self
print ( word "at point 2 we set selected player's size to " size )
]
create-balls 1 [
set shape "circle" set size 3 set color blue set label who
set hot-ball who
; hide-turtle ;; for debugging show it so you can click on it and inspect it
print ( word "at point 3 we set created a blue hot-ball with who= " hot-ball )
]
;; it seems you want to update the selected turtle's my-ball variable here with a reference to the ball just created??
print " at point 4 we should set selected agent's my-ball to the ball we just made..."
ask selected [
set new_ball hot-ball
]
print (word " Confirming that selected player got the hot-ball " [new_ball] of selected )
;; ask ball hot-ball [ set hidden? true ]
;; this set of code seems to apply only when selected turtle is one of playersA, so it was moved INSIDE that ask-selected code
;; and put inside another ask selected [ ] context
ask selected [
set team-players link-neighbors with [breed = playersA]
print (word "At point 5, For selected player " who ", here is the team-players agent set :" )
print (sort team-players) ;; using "sort" here just to convert an agent set to a list for display
]
print " ------------- about to ask team-players to update their my-lists and change to triangles ---"
ask team-players [
set shape "triangle" set size 3 ;; to see at a glance that everyone was processed
set my-list lput new_ball my-list
print "... updated one my-list"
]
print " let's confirm that the lists have been updated. Here's the my-lists for playersA "
print map [ i -> [my-list] of i ] sort playersA ;; using "sort" to convert agent-set to a list
print (word "At the end of the go step, we have this many balls: " count balls)
]
;; else we should have breed != playersA
[
error " we should only be looking at one of playersA here for testing" ;; for debugging
]
;; tick
end

Turtle cannot select path to destination in GIS generated network unless duplicate and unconnected nodes are removed

I have been trying to work out how to make a turtle move from one node to another in a network based on a GIS road map. The issue is that the turtle cannot set a path using nw:turtles-on-path-to unless I remove node duplicates and nodes that are not connected (the relevant block of code I used is from someone else's model). Below is the code that works when I remove duplicates and unconnected nodes:
foreach gis:feature-list-of roads-dataset [ vector-feature ->
foreach gis:vertex-lists-of vector-feature [ vertex ->
let previous-turtle nobody
let first-turtle nobody
foreach vertex [point ->
let location gis:location-of point
if not empty? location
[
create-nodes 1
[ set myneighbours n-of 0 turtles
set xcor item 0 location
set ycor item 1 location
set road-type gis:property-value vector-feature "Classification"
;set shape "circle"
;set size 0.5
ifelse previous-turtle = nobody
[ set first-turtle self ]
[ create-link-with previous-turtle ]
set hidden? true
set previous-turtle self ]
]
]
] ]
delete-duplicates
ask nodes [ set myneighbours link-neighbors ]
delete-not-connected
ask nodes [ set myneighbours link-neighbors ]
to delete-duplicates
ask nodes [
if count nodes-here with [ description = "road" ] > 1[
ask other nodes-here with [ description = "road" ][
ask myself [create-links-with other [link-neighbors] of myself]
die]
]
]
end
to delete-not-connected
ask nodes [set test 0]
ask one-of nodes [set test 1]
repeat 500 [
ask nodes with [test = 1]
[ask myneighbours [set test 1]]]
ask nodes with [test = 0][die]
end
to go
ask person [
if destination = 0 [ create-link select-destination ]
if mypath = 0 [ select-path ]
if mypath != 0 [ move ]
]
tick
end
to create-link
create-link-with min-one-of nodes [ distance myself ]
ask links [ set hidden? true ]
end
to select-destination
set destination one-of nodes with [ road-type = "main road" ]
end
to select-path
set mypath nw:turtles-on-path-to destination
end
to move
ifelse length mypath > 0
[ move-to item 0 mypath set mypath remove-item 0 mypath ]
[ stop ]
end
This code works perfectly fine. However, the road network gets distorted after deleting duplicate and unconnected nodes - the road networks does not have the same appearance as the original one. The only way the turtle can move along the network is by keeping the code in the format above. If I exclude delete-duplicatesand delete-not-connected then mypath returns false.
I there a way I can keep the appearance of the original network and at the same allow the turtle to set a path and move along it to reach the destination? What would be the issue that does not allow the turtle to set a path unless delete-duplicatesand delete-not-connected are used?
Your support is much appreciated. Thank you.
Are you sure delete-duplicates is necessary? My guess is that the reason delete-not-connected is necessary is because, without it, select-destination can select a node that is not reachable by the turtle. I'll get to how to fix this in a moment. First, there are a few problems with your code that we should discuss.
First, you have turtles create a link between them and their current location. This is a little weird, because it's essentially saying that this turtle is a road on the road network, which doesn't make sense. Practically, this gets weird if and when you want the turtles to select new destinations. They'll still be linked with the node they started on! This would allow them "teleport" around the network. Not good! Instead, I suggest creating a turtle variable called current-location, which tracks the node that the turtle is on.
So, create-link should be turned into
to set-location
set current-location min-one-of nodes [ distance myself ]
end
move then becomes (I deleted the stop from your code because it's unnecessary):
to move
if not empty? mypath [
set current-location first mypath
move-to current-location
set mypath but-first mypath
]
end
and select-path becomes:
to select-path
set mypath [ nw:turtles-on-path-to destination ] of current-location
end
Actually, we can simplify this further. Because the turtle is keeping track of its current location, you don't need to keep track of the path yourself anymore. Instead, delete mypath and select-path and change move to:
to move
if current-location != destination [
let next-node first [ nw:turtles-on-path-to destination ] of current-location
set current-location next-node
move-to current-location
]
end
and change go to:
to go
ask person [
if destination = 0 [
set-location
select-destination
]
move
]
tick
end
Much simpler! Note that this should still be fast as nw remembers the shortest path between nodes. If you have a really big network or something, you can still keep track of the path yourself if you want, but I'd try this first.
Okay, now we're ready to fix the disconnected nodes problem without deleting anything in the network. Basically, select-destination should only choose a destination that the turtle can get to. That looks like this:
(Edit: This code is incorrect. See below)
to select-destination
set destination one-of nodes with [
road-type = "main road" and
is-number? [ nw:distance-to [current-location] of myself ] of myself
]
end
The [ nw:distance-to myself ] of myself in there will get the distance from the current-location (which is what the first myself refers to) to the potential destination (which is what the second myself refers to). nw:distance-to will return a number (the distance) if the target node is reachable from the source node; otherwise it returns false. So is-number? checks to make sure it actually gave us a number back.
Hopefully this helps solve your problem while also simplifying your code. The duplicates thing really shouldn't matter. If it does, either reply with a comment or edit your question, and I'll take a look.
Edit:
Thanks for uploading your model and data! I realized I actually messed up the select-destination procedure. It should be:
to select-destination
set destination one-of [ nodes with [
road-type = "road" and
is-number? [ nw:distance-to myself ] of myself
] ] of current-location
end
That is, the person was supposed to be querying the current-location for a reachable road. Obviously, since the person is not connected to the network, they can't get a reachable road directly.
Next, it looks like a significant problem is actually the data is extremely disconnected. The network that you're creating contains 5619 disconnected components which each only contain 3-5 nodes. So it's no wonder that the turtle can't find a destination it can reach!
I think you may be interpreting the data incorrectly. I would expect that the various the nodes created from different feature lists should be connected somehow, but you're not doing that (which is why you end up with so many disconnected components). Unfortunately, this is where we hit the limit of my knowledge; I don't know much about GIS. I remember one of my colleagues that was working on a similar project had to do something like merging vertices that were on top of each other. This would turns the network generation code into the following:
foreach gis:feature-list-of roads-dataset [ vector-feature ->
foreach gis:vertex-lists-of vector-feature [ vertex ->
let previous-turtle nobody
foreach vertex [point ->
let location gis:location-of point
if not empty? location
[
let x item 0 location
let y item 1 location
let current-node one-of (turtles-on patch x y) with [ xcor = x and ycor = y ]
if current-node = nobody [
create-nodes 1 [
setxy x y
set shape "circle"
set size 0.5
set road-type "road"
set hidden? true
set current-node self
]
]
ask current-node [
if is-turtle? previous-turtle [
create-link-with previous-turtle
]
set previous-turtle self
]
]
]
]
]
This appears to behave correctly. (I also cleaned up a few things that we're doing anything) That is, it looks to see if there's already a node at that exact location, and connects to that one if so, otherwise it creates a new node.
Here's the full updated code: https://gist.github.com/qiemem/b59f3657bea34b9aa67648760b9c7471
I also tweaked a few other things: The person now sets their location in setup, which makes sense: their location should update correctly after that. I added tick to the end of go, which all models should have. You might want to change view updates to "on ticks". Finally, I made the person choose a new location upon getting to their destination for testing. You might want to make go a forever button now; you'll the person going from place to place.
Hope that helps!

Directing an agent on a specific path (Netlogo)

there is a question that I want to ask that is when I trying to type this code, I got the error that is
The > operator can only be used on two numbers, two strings, or two agents of the same type, but not on a number and a list.
What I want to ask is how can I fix this, the false happen at this line on the code :
if pri-lev > [pri-lev] of oppoint1 and pri-lev > [pri-lev] of oppoint2
I tried to change it into "cars-on" or "cars with" but they are all useless. I also try to find on the Netlogo dictionary but I found no results on the code for directing an agent on a specific path.
What I am trying to do here is when an agent comes to a specific section, it will check if any agents listed as "oppoint1"; "oppoint2"; "oppoint3"; "oppoint4" and then compare a value call pri-lev to others value for setting its decision on keeping on moving or stopping and wait for others.
These are the part of my code:
ask cars
[
let oppoint1 (cars-at (xcor + 2) (ycor + 2))
let oppoint2 (cars-at (xcor - 1) (ycor + 1))
let oppoint3 (cars-at (xcor - 2) (ycor + 1))
let oppoint4 (cars-at (xcor - 3) (ycor + 1))
ifelse oppoint1 != nobody and oppoint2 != nobody
[
if pri-lev > [pri-lev] of oppoint1 and pri-lev > [pri-lev] of oppoint2
[
set pri-lev 4
speed-up
]
]
[
if oppoint2 = nobody and oppoint3 = nobody and oppoint4 = nobody
[
set speed 1
fd speed
if turning = "Rtrue"
[
set heading heading + 90
speed-up
]
]
]
]
Sincerely, Minh
it seems that the reason you are getting this error is that you are comparing the attribute of one (the current car) to the attributes of many (the oppoint agent-sets). Your code now says something like "If my privilege is greater than the privilege of that group, do this thing..." The problem is that [pri-lev] of oppoint1 returns a list of the pri-lev of all members of the oppoint1 agentset, like [ 10 12 13 24 ], and Netlogo won't automatically iterate over that list and compare each item to the attribute of the asking turtle.
There are several ways to deal with this. For example, you could make sure that you only ever compare two turtles- maybe by making sure that you only ever have one turtle per patch at a given time. If you are going to potentially compare one agent to an agent-set, you can use the any? primitive to check if any members of the group you're looking at satisfy your conditional statement. For example, given this setup:
turtles-own [
pri-lev
]
to setup
ca
reset-ticks
crt 10 [
set pri-lev 1 + random 10
]
end
You can ask one-of your turtles to check if not any? of the turtles on the current patch have a higher pri-lev than the asking turtle. If none of them do, the current turtle will move forward. Otherwise, it will print that there is another turtle with a higher pri-lev on the current patch.
to compare-with
ask one-of turtles [
let other-turtles other turtles-here
ifelse not any? other-turtles with [ pri-lev > [pri-lev] of myself ] [
fd 1
]
[
print ("A turtle here has a higher pri-lev than I do." )
]
]
tick
end

NetLogo: create a dynamic number of breeds

how can i create a dynamic number of breeds at runtime?
I want my user to be able to choose the amount of breeds.
I thought about something like
to setup_breeds
let j 1
while[j <= n_groups][
breed[j]
]
end
where n_groups is the number of breeds whick is taken from a slider.
But unfortunatly i cannot use breed inside a method...
Any ideas?
Thanks!
You need to explicitly declare each breed with the breed keyword, so the short answer is: no, you can't have a dynamic number of breeds.
But do you really need actual NetLogo breeds? The main purpose of having different breeds is to have different variables for each breed. If that is not case, perhaps you can get away with having a group-id turtle variable. To create a certain number of turtles for each of n_groups, you could just do something like:
turtles-own [ group-id ]
to setup
clear-all
let n_groups 10
let n-turtles-per-group 5
foreach n-values n_groups [ ? ] [
create-turtles 10 [ set group-id ? ]
]
ask turtles [ set label group-id ]
; do something with only turtles of, e.g., group 2:
ask turtles with [ group-id = 2 ] [
fd 5
]
end
If you think you really need breeds, edit your question to tell us why, and we'll see if we can find a solution for you.
Side note:
I used foreach n-values n_groups [ ? ] to loop through your n groups. That's the equivalent of:
let i 0
while [ i < n_groups ] [
set i i + 1
]
...but arguably more "NetLogo-ish".