Why does n-of in Netlogo selectes the same turtles in my code? - netlogo

I have a pool of turtles and I'm trying to select two random ones to play a game together. I use n-of on the turtles but sometimes n-of selects the same exact turtle twice and I have no idea why, as it should work without repetition. Can anyone help me understand what I'm doing wrong? This is an extract from the code:
to go
if ticks < cycleTime
[
playGame n-of 2 members
tick
]
if ticks = cycleTime
[
reset-ticks
]
end
to playGame[players]
let player1 item 0 [self] of players
let player2 item 1 [self] of players
;;sometimes it prints the exact member twice for player1 and player2
print(player1)
print(player2)
end

Check this reproducible example using global variables, that are easier to monitor:
globals [
players
player1
player2
]
to setup
clear-all
reset-ticks
create-turtles 100
end
to go
set players n-of 2 turtles
playGame players
tick
end
to playGame [plrs]
set player1 item 0 [self] of plrs
set player2 item 1 [self] of plrs
end
If you paste this code in your Code tab, create a monitor in the Interface for the [self] of players reporter, and hit setup+go (or else run repeat 10 [show [self] of players] in the Command Center), you will see that the two turtles' identifiers fluctuate, swapping their positions.
This brought to my mind something that I remember reading somewhere in the NetLogo documentation, but which I am unable to find: NetLogo constantly re-evaluates its variables, even if the model is not running.
When such variable is an agentset (such as players - because note that n-of reports an agentset if you pass it an agentset as input), or consequently depending on agentsets (such as [self] of players), this means that the internal ordering of the variable will be continuously shuffled.
This happens because agentsets are a random sorting of their relevant agents, and this variability is not a problem for NetLogo: on the contrary, it is at the core of its mechanism.
But in your case this means that sometimes the ordering of the players agentset (and therefore of the plrs argument, and therefore of the [self] of plrs list) changed in such a moment that what had been evaluated as item 0 became item 1 by the time item 1 was being evaluated.
How to solve this? What doesn't change its internal ordering are lists, so you can save your players as a list:
set players sort n-of 2 turtles
See that sort always reports a list.
This means that you can do:
set player1 item 0 players
set player2 item 1 players
and always have two different players.
If for some reason you do not want player1 to always be the oldest turtle, just directly set players as the list of selfs (as this will prevent sorting):
set players [self] of n-of 2 turtles

The problem is not n-of selecting the same turtle twice.
Instead, [self] of players is a list that is always generated in a random order. Since you generate this list twice, both lists are not necessarily in the same order. The following should illustrate this:
to playGame[players]
let thePlayers0 [self] of players
let thePlayers1 [self] of players
let thePlayers2 [self] of players
print(thePlayers0)
print(thePlayers1)
print(thePlayers2)
end
Generating the list of who's just once fixes your problem:
to playGame[players]
let thePlayers [self] of players
let player1 item 0 thePlayers
let player2 item 1 thePlayers
print(player1)
print(player2)
end

Related

getting "ASK expected input to be an agent or agentset but got the list [green-players" error in netlogo

This is the code of a 2 player game that I manipulated
o play-the-game
if (any-friends-nearby?) [gain-energy]
if (any-opponents-nearby?) [fight-opponent]
end
to-report any-friends-nearby?
report (any? (turtles-on neighbors4) with [breed = [breed] of myself])
end
to-report any-opponents-nearby?
report (any? (turtles-on neighbors4) with [breed != [breed] of myself])
end
to gain-energy
set similar-nearby count ( turtles-on neighbors4 )
with
[color = [color] of myself]
set total-nearby count (turtles-on neighbors)
;
;
if (similar-nearby >= total-nearby - similar-nearby)
[set energy energy + 5]
end
to fight-opponent
let my-breed [breed] of green-players
let my-color [color] of green-players
let opponent-breed [breed] of red-players
;
;;
ask my-breed
[check-random-winner]
end
to check-random-winner
let pick random-float 2
let winner nobody
ask turtles
[if winner = nobody
[ ifelse size > pick
[set winner self ]
[set pick pick - size] ] ]
end
to change-opponent
ask red-players
[ set breed green-players
set color green ]
end
Sorry if it's a bit long but when I setup up and then press go "ASK expected input to be an agent or agentset but got the list [green-players...]"
How can I fix this?
Also I'm very new to Netlogo and StackOverflow, apologies if I haven't asked my question properly.
The error message tells you that you are passing a list (more specifically, a list of breeds) to ask, when it comes to ask my-breed.
This is because the my-breed local variable is determined by
let my-breed [breed] of green-players
Let's see what we have there:
breed is a turtles-own variable: it holds the turtle's breed, and being an agents' variable can be used as a reported in the of construct (see below).
of is a reporter: it takes a reporter (normally an agents' variable) on its left (in your case: breed) and either an agent or an agentset on its right (in your case: green-players). What of reports (i.e. what it outputs) is...
... a single value if there is an agent on the right.
... a list of values if there is an agentset on the right*.
*Think about it: if I ask the color of your eyes (you are a single person, i.e. a single agent), you will tell me a single color. But if I ask the color of your friends' eyes (your friends are a group of people, i.e. an agentset), the only way for you to answer my question is to tell me a list of colors.
green-players is an agentset: all of the agents whose breed is green-players (note that for NetLogo green-players is an agentset even if it contains 1 or 0 agents).
From this, we can see that in this case of reports a list of breeds, because it reports the breed of every agent that is part of green-players, hence it will report the list [green-players green-players green-players green-players ... ] which is as long as the number of green-players in the model. You can verify this by clicking setup and then running [breed] of green-players in the Command Center.
This is a list of breeds (which can also be seen as a list of agentsets), which is not an agent or an agentset (which are the only possible targets of ask).
((note that the exact same thing happens with let my-color [color] of green-players and let opponent-breed [breed] of red-players))
So, how do you construct an agentset based on a variable? The most common way to do it is by using with (read here why).
But how can you fix your code? I don't know because I don't understand what you want to achieve.
I am not sure how you would want to use it in the code you posted, as I'm not even sure you need to use ask in fight-opponent (let alone ask an agentset).
Your fight-opponent procedure is such that, apart from the problem we just discussed, the "my-" things (i.e. my-breed and my-color) always refer to the green players while opponent-breed always refers to the red players - even if fight-opponent is run by a red player! And also, it is not clear what you want to achieve with the check-random-winner procedure and if you want this procedure to be ran by an entire breed. These things make it quite confusing to understand how you could want to fix the fight-opponent procedure.
For example: who do you want to run the check-random-winner command?
A combination of two things would be beneficial: develop your model one step at a time and make sure that every new little piece of code does exactly what you expect it to do; also, when you ask for how to fix something it is useful that you explain what you want your code to do. By doing these two things I believe it will be a lot easier to answer your questions

How to make agent stay at certain patch in netlogo within certain ticks?

I'm doing code for making agents roaming around the world to forage.
After they find it, they should stay at the patch where they find the food for a certain time. But I have a problem to make them stay on the food patch for a certain time.
Certain time: each turtle has its own variable "s", and "s" is a random number generated by NetLogo and the number shouldn't change within each tick, and I have a problem to make "s" doesn't change.
For example, turtle 1 has "s"=60, after turtle 1 find the food, it will stay on the food for 60 ticks. After turtle 1 has stayed for 60 ticks there, it will leave the food and the value of "s" will be reset again to another random value. And each turtle has a different value of "s"
I tried to use timer coding, but the timer only decreases each time the agent come across the food (like they just walk on the food instead of staying there) I can't use bk 1 or fd -1 command because the turtle just keeps on moving forward after they walk backwards for 1 tick.
Any help is appreciated.
here is the code:
turtles-own
[
food
location
s
]
patches-own
[
food-quality
]
to go
move
forage
end
to move
ask turtles
[fd 1]
end
to forage
set s random 100
ask turtles
[ [ if food < food-quality ;meaning that turtle will only keep the best food's value each time they found food
[set food food-quality ;food-quality is patch-own, the food's value
set location patch-here]
if s >= 50
[stay] ]
]
]
end
to stay
set s s - 1 ;decrement-timer
if s = 0
[move
set label ""
reset-s
]
end
to reset-count-down
set s random 100
end
Edit: making the question clearer and update some code.
I think you have a logic problem rather than a coding problem, but it's not particularly clear. If your variable 's' is supposed to be something like a stay-timer (much more descriptive name), then don't set it at the beginning of the forage procedure. Instead, set it when the turtle finds food and then only move/forage if it's not being held by the stay-timer. You also don't have tick anywhere in your code, so you are not advancing the clock. I think you want something like this:
to forage
ask turtles
[ if food < food-quality ; has found food that is more than currently owned
[ set stay-timer random 5 + 20 ; sets number of ticks to stay between 5 and 24
set food food-quality ; food-quality is patch-own, the food's value
set location patch-here
]
set stay-timer stay-timer - 1
]
end
to go
ask turtles with [stay-timer = 0] [ move ]
forage
tick
end

How to dynamically output value in netlogo

I have created a model in which turtles are born and die based on certain parameters. But at any given point, lets say no more than 20 turtles are alive.
With the birth and death of each new turtle, the turtle label keeps increasing incrementally i.e. initially there are 5 turtles, the 3rd turtle dies and in the next tick a new turtle is born. The new turtle born has a label of 6 and thus old labels are retired and replaced with the next label.
If i want to output a metric associated with the turtles into the monitor, is there a way to dynamically ensure that. i.e. since there can't be more than 20 turtles at any tick, can i make netlogo display the turtle metric along with the turtle label automatically. Otherwise i will have to create 100's of monitors and then code with [metric] or turtle 0.....[metric] of turtle n which is not practical.
If you really want a separate monitor for each turtle, you can do something like this:
Using [ metric ] of item 0 sort turtles instead of [ metric ] of turtle 0 (and so on) will insure that you're not depending on the who numbers of the turtles, you're only depending on their position in the sorted list of turtles.
Note that this would be very inefficient, because each monitor would keep re-sorting the turtles over and over again.
That being said, I think there would be many different, better ways to approach this. Here is one fully working example:
turtles-own [ metric ]
to setup
clear-all
create-turtles 20 [ set metric random 10 ]
reset-ticks
end
to go
ask n-of 5 turtles [ die ]
create-turtles 5 [ set metric random 10 ]
tick
end
to-report info [ the-turtle ]
; format this however you want:
report [ (word who ": " metric ", ") ] of the-turtle
end
And then, in a monitor, put:
map info sort turtles
Which will give you something like:
If map is obscure to you, you may want to check its dictionary entry. The basic idea is that we build a new list of strings by applying the info reporter to each element of our list of turtles.
I used a monitor in the example because that's what you were talking about in your question, but for displaying information about multiple turtles like this, maybe a plot or the output widget would be more appropriate. In any case, you could use a similar approach, with either map or foreach.
One word of advice in closing. Your question shows that you're probably aware of that already, but any time you're tempted to refer to turtles by their who number (i.e., turtle 0, turtle 1, turtle 27, etc.), it probably means you're on the wrong track. NetLogo is built to manipulate agentsets and lists; take advantage of that. And when you do need to refer to a particular turtle, use a reference to that turtle (e.g., the-turtle in the example above), never (or almost never) its who number.

Make turtles move ONCE according to their ranked order in a list

This question is built off my previous 2. I've been working to get a rank-ordered list for my turtles, ranked by an owned factor. They're then required to move in ranked order. That part works perfectly fine, and the code can be found at: Assigning turtles a ranked number in netlogo
The problem: using that code, they're moving in the correct order but instead of moving once, the program seems to be continuously re-running it for every turtle in the list so the first turtle in a world of 10 ends up moving 10 times, the second moves 9 times, etc.
I'm completely stumped on this, but I need it to stop. They're supposed to move once and be done for that tick. Ideas?
The list creation code is:
let rank-list sort-on [sociability] turtles
let ranks n-values length rank-list [ ? ]
(foreach rank-list ranks [ask ?1 [set social_rank ?2] ] )
;;you can replicate the problem with this movement proc, or the full code in the link above
ask turtles [foreach rank-list [ask ? [set heading 270 forward 1]]]
In the line:
ask turtles [foreach rank-list [ask ? [set heading 270 forward 1]]]
You're asking each turtle to execute a command for each turtle in your rank-list.
Just drop the ask turtles part.
As a more general note: foreach is to lists what ask is to agentsets. They both do the same basic thing, which is to perform a command for each item of a "collection". Agentsets are unordered collections of unique agents. Lists are ordered collections of possibly duplicated items of any type.

In NetLogo how agents actions are performed?

In my go function I have a few conditions which might be true and then call an action, if more than one condition are true does it mean in one tick agents can do more than one action ? or in another case I have a function that agents have to move to a target and after facing the target agent should find the distance and fd 1 until reaches the target, does it mean it should take n ticks to complete?
to move [t]
face t
let n distance self t
repeat n
[fd 1]
end
to go
action 1 = > [move]
action 2
action 3
tick
end
I need the agents to do only one task at the time, and I am not sure how to make sure that for example not all the agents have the same target! sorry if these questions are out of context but I am new to Multi-agent modeling.
This is a great question!
First, specific answers:
if more than one condition are true does it mean in one tick agents can do more than one action ?
Just to be clear, are you talking about a situation like this?
to go
ask turtles [ move ]
tick
end
to move
if xcor > 5 [ fd 1 ]
if ycor > 7 [ rt 15 ]
if color = red [ bk 2 ]
end
If so, then yes, if xcor > 5, ycor > 7, and color = red are all true, the turtle will move forward 1, turn right 15, and move backward 2. The main way to prevent this is by using a sequence of ifelses:
to move
ifelse xcor > 5 [
fd 1
] [
ifelse ycor > 7 [
rt 15
] [
if color = red [ bk 2 ]
]
]
end
That way, the second condition (ycor > 7) will only be looked at if the first condition (xcor > 5) is false. Similarly, the third condition will only be looked at if the first two fail.
I have a function that agents have to move to a target and after facing the target agent should find the distance and fd 1 until reaches the target, does it mean it should take n ticks to complete?
I would recommend taking n ticks to complete it. Otherwise, only one turtle will move to its target at a time! However, repeat n [ fd 1 ] will make the turtle go forward n all at once. In fact, it's the same as fd n. The repeat block will finish before the turtle is done performing the move procedure.
You can edit your move function as follows to get it to take n ticks:
to move [t]
face t
fd 1
end
Then, just have a condition to look for when the turtle gets to its target (for example, distance t < 1) and then do something accordingly.
I recommend just messing around with these various techniques with multiple turtles using them so you can get a feel for the differences.
I am not sure how to make sure that for example not all the agents have the same target!
This depends quite a bit on context. Supposing there is a turtles-own variable called target that stores each turtle's target, you could do something like this:
to-report get-available-target [ possible-targets ]
report one-of possible-targets with [ not any? turtles with [ target = myself ] ]
end
get-available-target will report a random agent from possible-targets that is not anyone's target. one-of just gets random agent from an agentset.
How can I schedule tasks in netlogo, I have conditions and actions but how can I make the agents do one task at the time?
Often this just takes care of itself. For example, say, when an agent is hungry, it should walk over to a food supply and eat. As it's walking over, you don't want it to go off and do anything. However, it will still be hungry, so if you've used an ifelse, it will just keep going to the food supply. Thus, your agent stays focused for free! In general, it's best to design your conditions such that they remain in effect until the agent addresses them. You can order them in an ifelse chain or something similar to establish the general priority of actions (for instance, if the agent walking to the food supply is threatened by a predator, it should still run away).
If you really want to the agent to do something for several ticks, you'll basically just extend this same idea, but in a more artificial way. For instance, if an agent should walk forward three times, have a turtles-own variable set to three. If that variable is greater than zero, the agent walks forward and decreases that variable, and doesn't do anything else.
#Bryan Head already answered your question, I had the same problem when I started Netlogo and agent based modeling, So I have added a current-task variable and in my Go Procedure I have added a function to check all the conditions and set the task of agents and when the task is completed the variable is set to "" again. This might be useful for your case as well.
if current-task = "move" [move]
if current-task = "A1" [A1]
if current-task = "..." [...]
if current-task = "" [select-current-task]