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]
Related
Is it possible to subtract previously diffused values?
I have a land-use model where residential use (yellow patches) diffuses its land value with the diffuse primitive:
diffuse land-value 1
In the first image below, land value is represented as white tones, the brighter the tone, the higher the land value. Residential use sometimes abandons the patch, but their land value influence stays (second image). Is there a way that, when the land use disappears, the value it previously diffused to all patches be subtracted and also disappear?
Following comments under the question and following Luke's suggestion of framing the diffusion of land-value as a function of distance instead of a recurring diffuse, I have set up the following solution (in point 1).
Below (in point 2), you find a possible approach (not fully coded, but sketched-out enough) for addressing the issue if you want to stick to diffuse.
1 - Approach with function of distance
What happens here is that, when a patch gains residential status (to create-residence), all other patches in a certain radius calculate how much spill-over land-value they get based on the residential value of the new residential patch and on how much it is distant (to-report diffused-value).
The advantage of this approach is that this calculation is fully replicable at any moment because it is based on two constants: the distance between patches and the initial residential value of the patch in question (for which I created the patches-own own-residential-value, distinct from the general land-value).
For this reason, when a patch loses residential use (to dismantle-residence) it is possible to perform the same calculation but, instead of having patches add diffused-value to their land-value, they will subtract it.
I think the code I place below best illustrates its functionality if you create the create-residence and dismantle-residence buttons in the Interface, and play with them to see how overlapping land-values add and subtract in the View.
globals [
; Agentsets for patches.
residence
non-residence
]
patches-own [
land-value
own-residential-value
]
to setup
clear-all
set non-residence (patch-set patches)
set residence (patch-set)
end
to create-residence
let new-res one-of non-residence
ask new-res [
set non-residence (patch-set other non-residence)
set residence (patch-set self residence)
set own-residential-value (random 10) + 1
set land-value (land-value + own-residential-value)
set pcolor yellow
diffuse-value
]
update-colours
end
to diffuse-value
ask other patches in-radius 10 [
set land-value (land-value + diffused-value)
]
end
to dismantle-residence
let target one-of residence
ask target [
set residence (patch-set other residence)
set non-residence (patch-set self non-residence)
; As opposed to 'to create-residence', where 'diffuse-value' is at the end of this block of commands,
; here 'subtract-value' has to be placed before the patch updates its 'own-residential-value' to 0,
; because that value is needed to calculate 'diffused-value'.
subtract-value
set land-value (land-value - own-residential-value)
set own-residential-value 0
]
update-colours
end
to subtract-value
ask other patches in-radius 10 [
set land-value (land-value - diffused-value)
]
end
to-report diffused-value
; Here, 'myself' is the new residential patch (as 'new-res' in 'to create-residence') or
; the new non-residential patch (as 'target' in 'to dismantle-residence').
let d distance myself
let v [own-residential-value] of myself
report v * (0.9 / d) ; Just an arbitrary function of value and distance.
end
to update-colours
ask non-residence [
set pcolor scale-color white land-value 0 15
]
end
2 - Approach if sticking to diffuse
I have though of an approach for this case too, but I also want to understand if diffuse really is what you want to use.
As we know, diffuse is a zero-sum game: what is diffused by a patch is also lost by a patch.
Therefore, I imagine you will not be just using diffuse land-value 1, because in that case land-value of the residential patch will be 0 after one tick, will very slightly recover on the subsequent tick, and will then progressively approach 0 from the third tick on.
For example, the following code gives the results as in the table below:
patches-own [
land-value
]
to setup
clear-all
reset-ticks
ask patch 0 0 [set land-value 50]
end
to go
diffuse land-value 1
tick
end
I doubt this is anything you are interested in replicating, so I assume the approach would be something like:
patches-own [
land-value
temp
]
to setup
clear-all
reset-ticks
ask patch 0 0 [set land-value 50]
end
to go
diffuse-value
tick
end
to diffuse-value
ask patches [
set temp land-value
]
diffuse land-value 1
ask patches [
set land-value (land-value + temp)
]
end
However, I think that even in this case diffuse seems to be not fit for representing a residential value spreading to near-by areas. By using the code above, in fact, the result is the following:
The table above shows that, in 15 ticks, the patch which should be the one diffusing some value in the area experienced a 93593% increase (no, I didn't forget any decimal point!) in its land value. I know of course this might be mitigated with some formula, but I think it shows the tendency of diffuse in this case: to create an escalating positive feedback between patches, so that a small residential value grows without control.
I'm not the expert of residential values here, but I felt these results (from both the former and the latter use of diffuse) were worth pointing out from a NetLogo perspective.
That said, if the idea is to stick to diffuse...
patches-own [
land-value
own-residential-value
residential-start
temp
]
to setup
; Some code.
end
to go
; Some code.
end
to create-residence ; Executed by the observer. This procedure cannot be executed by the patch becoming residence because it contains 'diffuse'.
let target ; <- Identify here the patch that needs to become residence.
ask target [
; Set 'own-residential-value' to something.
set land-value (land-value + own-residential-value)
set residential-start ticks
]
; Have some code here that uses 'diffuse own-residential-value'.
end
to dismantle-residence ; Executed by the observer. This procedure cannot be executed by the patch being dismantled because it contains 'diffuse'.
ask patches [set temp 0] ; This is crucial in order to avoid any overlap among patches when using 'diffuse'.
let target ; <- Identify here the patch that needs to be dismantled.
let time-as-residence (ticks - [residential-start] of target)
ask target [
set temp own-residential-value
]
repeat time-as-residence [
; Insert here the exact same code that
; was used for using 'diffuse' but
; diffusing the 'temp' variable instead
; (e.g. 'diffuse temp 1').
]
ask patches with [temp > 0] [
set land-value (land-value - temp)
]
end
What happens above is that, whenever a patch loses residential use, the program performs exactly the same number of diffuse operations as it performed when actually diffusing land-value during the residential life of the patch at stake, but on temp instead of land-value. This way, all the surrounding patches will store in temp the same value they gained over time from the patch being dismantled - so they can subtract this value from their current land-value.
The success of this approach depends on the ask patches [set temp 0] statement: given that diffuse operates on each patch, by setting all temp to 0 and then doing ask target [set temp own-residential-value] we make sure that we only reproduce the pattern of value-diffusion that can be attributed to the patch being dismantled - avoiding any overlap that might have occurred over time, when patches may have gathered (and then re-diffused) value from other residential patches.
(This is based on the assumption that you use diffuse at every tick, as you said in a comment to the question. Even if that ceases to be the case, it will be easy to set time-as-residence in an alternative way according to the number of times that diffuse took place since a particular patch became residential)
Potential problem This is something that you will have to untangle yourself, but consider that there remains a possible issue: you have to decide whether you want to diffuse own-residential-value or land-value, with both options presenting some problem.
Diffusing own-residential-value seems intuitive to me, since that is the added value; however, this means that the diffused value would go into own-residential-value of the other patches (and not into their land-value) even if they really do not have any residential value of their own, which will create the need for extra computation (a possible option could be to rename own-residential-value to something more appropriate, like residential-value, and create a further tot-value patches-own variable that is updated at every tick as set tot-value land-value + residential-value).
On the other hand, diffusing land-value would be more straightforward in terms of coding (land-value would just propagate to other patches' land-value) but seems less precise based on what I can understand, given residential patches would be propagating land-value which often will not be just the new residential value that they bring, but also the result of that positive feedback discussed before, building on other patches' residential values.
Conclusions
While I'm quite confident that the second approach is viable and technically good, I definitely prefer the first based on the doubts that I expressed over the use of diffuse for this particular goal (at least based on the understanding I have of your intentions, which I might not understand fully) - and the feeling that a function of distance looks like a neat approach to diffusion of value in this scenario.
The model I am working on simulates a group of workers working on a team project. I am trying to add a on/off switch titled "replacement." The intended outcomes are:
When it is on:
30% of existing turtles of breed employees die, and equal number of new turtles are introduced.
When it is off:
No turtles die, and all turtles generated at setup will work on the project from start to finish.
The purpose of killing off the turtles is the turtle-own variable "skills." I am trying to simulate a scenario where people resign from a company and new people are hired, which will result in a change of skill level.
If it is easier to change the skill level of 30% of turtles every 20 ticks instead of killing/regenerating, that would be perfect, but I was unable to figure it out.
My attempt at this problem is shown below. It runs without any errors, but I confirmed that it's not killing/respawning 30% of turtles every set number of ticks. Any helpful guidance will be much appreciated.
to go
if all? patches [ workload = 0 ] [ stop ]
ifelse replacement [hire] [continue]
recolor
tick
end
to hire
if ticks > 0 and ticks mod 20 = 0 [
ask n-of (count employees * 0.30) employees [die]
create-turtles number_of_workers * 0.30 [
set breed employees
setxy random-xcor random-ycor
set shape "person"
set color black
set size 1
set skills random-float 1]
]
ask employees [move]
ask leaders [move]
end
to continue
ask employees [move]
ask leaders [move]
end
I ended up finding the answer on my own. Removing "ticks > 0 and" from the hire function solved it :)
From your description of the problem, I am not sure why removing the if ticks > 0 and solved it. I am wondering if you perhaps had the "replacement" variable set to false, and the hire procedure would not have been called.
Regardless, you also asked about just changing the skill set every 20 ticks. You could do this:
to go
if all? patches [ workload = 0 ] [ stop ]
if replacement? and ticks mod 20 = 0 [hire]
move-people
recolor
tick
end
to hire
ask n-of (count employees * 0.30) employees
[ set breed employees
set skills random-float 1
]
end
to move-people
ask employees [move]
ask leaders [move]
end
I also reorganised slightly in a way that is intended to make it easier to debug. You had the moving in both the "hire" and "continue" procedures. Clearly you want that to always happen, so that is now explicit in the "go" procedure (and I changed the name to be more descriptive).
Now the "hire" procedure simply changes the skills of existing employees. Note, however, that any other variables (such as leader, size, colour and position) are not affected. If you go this approach, you may want to indicate in some way that they are new hires.
The "hire" procedure is now clearly called when the "replacement?" switch is on and also a multiple of 20 ticks. If you have part of the condition in the calling procedure ("go") and part in the procedure itself ("hire") then it's easy to forget the existence of whichever half you are not looking at.
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
I'm trying to make a simulation exactly the Dining Philosophers in the net logo library but with a different method. I'm trying to create a situation where there are 20 philosophers in a circle with one "fork" in front of each philosopher. The philosophers either eat, think, or get hungry. They can only eat by obtaining 2 forks and after they're done eating, they put the forks down and think until they get hungry. I'm trying to ask the 2 forks within the range of the hungry philosophers to move to the respective philosophers, but I'm not sure how to do it.
Here is my code so far:
breed [philosophers philosopher]
breed [forks fork]
philosophers-own [thinking eating hungry]
globals [x y]
;eating = green
;thinking = blue
;hungry = red
to setup
ca
cro num-philosophers [set breed philosophers
fd 10 set shape "person-1"
set color blue
ask philosophers [
set hungry hungry = false
set thinking thinking = true
set eating eating = false]
set size 3]
cro num-philosophers [set breed forks fd 8
set heading heading + 180 / num-philosophers
fd -1
lt 180
set shape "fork"
set color grey
set size 2.5
]
reset-timer
end
to go
move
end
to move
every .1 [
ask philosophers with [who mod 2 = 0] [set color red
set hungry hungry = true
set thinking thinking = false
set eating eating = false]
ask philosophers with [hungry = true] [
;this following line with in-radius was my attempt to move the forks but it doesn't work
ask [forks in-radius 4] of philosophers with [hungry = true] [setxy x y]
ask fork 21 [setxy x y]
set y [ycor] of one-of philosophers with [hungry = true]
set x [xcor] of one-of philosophers with [hungry = true]
]]
end
any advice on how to solve this is appreciated! Thank you!
First problem is your lines like set hungry hungry = false. In NetLogo, you assign a variable value without an equals sign. Assuming that you want to set the variable named 'hungry' to false, your code should be set hungry false. Also, by convention, NetLogo boolean variable names use a question mark at the end (to remind you they are boolean) so it would be better to have set hungry? false and change the philosophers-own statement accordingly.
This will be causing part of your error because the value of hungry is being tested as true or false, but you didn't assign true or false. So the if statement will always be false.
Second, since you are essentially doing the moving from the perspective of the forks, it is probably best to ask forks for the movement, rather than ask philosophers. Perhaps something like:
ask forks
[ let targets (philosophers in-radius 4) with [hungry?]
if any? targets
move-to target with-min [distance myself]
]
This code is not tested. The basic approach is to check with the fork whether there are any hungry philosophers within a distance of 4. If there are, the fork moves to the location of the closest hungry philosopher. Look up move-to in the NetLogo dictionary. Even if this isn't the answer you want, it's probably the primitive you are looking for. You don't need to be getting the xcor and ycor from one turtle and passing them to the other turtle, you can simply move to the turtle (or face the turtle and then move forward a little).
Finally, I recommend you build your code more gradually. For example, you could turn the philosopher red if it's within 4 distance of a fork. Then you can worry about moving.
On a separate issue, it is extremely unlikely that you actually want to use every. This is only when you want to have real time (such as a number of seconds) for each time step. Instead, you should be thinking with tick to increment the clock. Your model will run much faster because it will be limited by how much processing is required instead of tracking against time in the real world.
I am trying to create a program in netlogo where there are blocks that come down the screen and when their y-coordinate reaches a certain value they reverse their direction and move in the opposite way.
So far I was able to make them move in one direction and then switch directions when they reach the critical y-coordinate value, but once they take one step in the reverse direction it glitches and they get stuck moving one step forward and one step backward.
I wanted to know if there was an else command in netlogo so I could specify that if the while command wasn't fulfilled it could reverse its direction and move without glitching.
Here is my code.
to maze
while [abs pycor < 16 ] [fd 1 wait .1]
bk 1 wait .1
end
There is no separate else keyword in NetLogo, but the ifelse command allows you to specify two blocks: one that is executed if the condition is true, and another (the "else" block) that is executed if the condition is false.
It seems, however, like you should rethink your general approach to the problem. Turtles in NetLogo always face in a particular direction, and you could take advantage of that: instead of having them "back up", you could have them turn around.
Also, it's generally ill-advised to try to do things in a while loop. If you want your turtles to repeat a behavior, a "forever button" is usually the way to go.
In the following example, you should call the go procedure from a forever button:
to setup
clear-all
ask patches with [ pycor = max-pycor - 1 ] [
sprout 1 [
set heading 180 ; head down
]
]
reset-ticks
end
to go
ask turtles [
if abs pycor = max-pycor [
rt 180 ; turn around!
]
fd 1
]
tick
end
This probably doesn't achieve exactly what you wanted, but there is a good chance that you can modify it to fit your needs.
Also note that this will work better using tick-based updates.