Reputation: 1152
Suppose I have a beach and an ocean, denoted by patch colors gray and cyan respectively. I have some turtles (fish) whose starting location I constrained randomly somewhere in the ocean. Now each tick the fish move following a random walk with step length drawn from a normal distribution (mean=0, SD=1). Logically, when moving the fish should stay within the ocean and not move onto the beach. I tried the same while []
that i used to constrain the starting locations of fish to the ocean, but this doesn't seem to work here i.e. the fish don't move at all. Any thoughts?
EDIT: In addition to having 2 fishes in the water, i have 2 other turtles (e.g., cow and sheep) on land that, similarly to the fishes, cannot/shouldn't enter the water when they move (in fact I have 3 such 'habitats' total where turtles shouldn't leave the habitats in which they started). When I incorporate the solution by LeirsW for the fish and for the cows/sheep, my Netlogo freezes and i have to force quit. Any thoughts on this?
EDIT 2: the x0 and y0 are no mistakes and need to be kept in the code.
Updated code below:
breed [ fishes fish ]
fishes-own
[
x0 y0 xcur ycur
]
to setup
clear-all
reset-ticks
ask patches [set pcolor gray]
ask patches with [ pycor < (max-pycor / 2) ] [ set pcolor cyan ]
create-fishes 4
[
setxy random-xcor random-ycor
set x0 xcor
set y0 ycor
ifelse who <= ( 3 * 0.5 )
[ set shape "fish" set size 2 ]
[ set shape "fish" set size 3 ]
set color white
while [ pcolor != cyan ] [ setxy random-xcor random-ycor ]
]
create-fishes 4
[
setxy random-xcor random-ycor
set x0 xcor
set y0 ycor
ifelse who <= ( 4 - 1 + 4 * 0.5 )
[ set shape "sheep" set size 2 set color yellow ]
[ set shape "cow" set size 2 set color yellow]
;set color white
while [ pcolor != gray ] [ setxy random-xcor random-ycor ] ]
end
to go
fish-move
tick
end
to fish-move
ask fishes with [pcolor = cyan]
[
ifelse (random-float 1) < 0.95
[
let destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
while [ [pcolor] of destination != cyan ]
[
set destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
]
move-to destination
set xcur xcor
set ycur ycor
]
[
let destination patch random-xcor random-ycor
while [ [pcolor] of destination != cyan ]
[
set destination patch random-xcor random-ycor
]
move-to destination
set xcur xcor
set ycur ycor
]
]
ask fishes with [pcolor = gray]
[
ifelse (random-float 1) < 0.95
[
let destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
while [ [pcolor] of destination != gray ]
[
set destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
]
move-to destination
set xcur xcor
set ycur ycor
]
[
let destination patch random-xcor random-ycor
while [ [pcolor] of destination != gray ]
[
set destination patch random-xcor random-ycor
]
move-to destination
set xcur xcor
set ycur ycor
]
]
end
Upvotes: 1
Views: 563
Reputation: 121
In NetLogo, patches are identified with integer coordinates. That is, patch 0.4 0.4
is the same as patch 0 0
. NetLogo rounds the given coordinates to the nearest integer when locating patches. So, if your code involves adding a random value between 0 and 1 to each of the coordinates of a patch, chances are that the newly calculated coordinates refer to the same old patch. This may justify why turtles given a newly calculated destination seem to remain in their old place.
An alternative approach to your problem is to ask turtles to move forward by a distance. Here is an example in which I tell turtles to check where it is headed, and to change course if necessary:
ask turtles with [pcolor = cyan] [
let dist random-normal 0 1
while ([pcolor] of patch-at-heading-and-distance heading dist) != cyan [
set heading random-float 360
]
fd dist
]
In the above code, variable dist
is defined as the distance of movement (with negative values causing backward movement), heading
is the property of turtles which indicates their orientation, and fd
is the NetLogo function that tells turtles to move forward in the direction of their heading.
As a side note, random-normal
and random-float
are two different functions. Specifically, note that random-normal 0 1
draws random numbers from a normal distribution with mean 0 and standard deviation 1, whereas random-float 1
gives a random number between 0 and 1.
Upvotes: 1
Reputation: 2305
Note: As the question has been changed, I feel it warrants a new answer rather than editing the previous answer which is in and off itself still correct. However, as I have only joined stackoverflow relatively recently, I will follow someone elses judgement and append this to my previous post if requested.
In your new version, the x0
and y0
are creating your problems. You define them before shuffeling your turtles around to find a good initial position. This means that a fish can have its x0
and y0
set to the land. Since your code has them looking for a destination around that point, rejecting all gray destinations, you will be stuck in an endless searching. Moving x0
and y0
to the end of the create-fishes
block solves this problem.
create-fishes 4
[
setxy random-xcor random-ycor
ifelse who <= ( 3 * 0.5 ) ; Set proportion of fishes in lagoon determined by slider
[ set shape "fish" set size 2 ]
[ set shape "fish" set size 3 ]
set color white
while [ pcolor != cyan ] [ setxy random-xcor random-ycor ]
set x0 xcor
set y0 ycor
]
Now for some further general suggestions
I added a fishes-own variable called habitat. This variable is set to a color at creating of the fishes and determines which color of patches they can move to. By making this a variable tied to the turtles, you don't need a new movement code for each new type of turtle.
I added Matteo's suggestion of more efficiently choosing their initial patch by having them move-to one-of patches with [pcolor = [habitat] of myself]
.
I grouped all the initial moving together in a separate code block, just to not have to rewrite it for every different type of turtle you want to add.
Do xcur
and ycur
have any specific goal? You can already access xcor
and ycor
on all turtles so I don't see any specific need for them.
Is there any specific goal for the fishes breed? Otherwise you could just use the general agentset turtles
instead and define turtles-own
instead of fishes-own
. Even if you have multiple breeds, any variable defined as turtles-own
can also be used by your breeds so you won't have to define them for each breed separately.
breed [ fishes fish ]
fishes-own
[
x0 y0 xcur ycur habitat
]
to setup
clear-all
reset-ticks
ask patches [set pcolor gray]
ask patches with [ pycor < (max-pycor / 2) ] [ set pcolor cyan ]
create-fishes 4 ;create the water animals
[
ifelse who <= ( 3 * 0.5 )
[ set shape "fish" set size 2 ]
[ set shape "fish" set size 3 ]
set color white
set habitat cyan
]
create-fishes 4 ;create the land animals
[
ifelse who <= ( 4 - 1 + 4 * 0.5 )
[ set shape "sheep" set size 2 ]
[ set shape "cow" set size 2 ]
set color yellow
set habitat gray
]
ask fishes [ ;move all animals to their prefered habitat
move-to one-of patches with [pcolor = [habitat] of myself]
set x0 xcor
set y0 ycor
]
end
to go
fish-move
tick
end
to fish-move
ask fishes
[
ifelse (random-float 1) < 0.95
[
let destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
while [ [pcolor] of destination != habitat ]
[
set destination patch (x0 + random-normal 0 1) (y0 + random-normal 0 1)
]
move-to destination
set xcur xcor
set ycur ycor
]
[
let destination patch random-xcor random-ycor
while [ [pcolor] of destination != habitat ]
[
set destination patch random-xcor random-ycor
]
move-to destination
set xcur xcor
set ycur ycor
]
]
end
Upvotes: 1
Reputation: 2305
The problem with your code is that you ask your fishes to only move while they are on a non-cyan tile. Since they all start on a cyan tile, non of them will move.
A first way to go about this would be to simply ask them to move once, and then move again as long as they are on the grey
to fish-move
ask fishes
[
setxy (x0 + random-normal 0 1 ) (y0 + random-normal 0 1 )
while [ pcolor != cyan ]
[
setxy (x0 + random-normal 0 1 ) (y0 + random-normal 0 1 )
]
]
end
Now this brings with it its own set of problems, because it means that fishes that come near the grey may move onto it and travel a long distance before finally ending in a cyan tile again. That is why I prefer to split the problem into three parts: Choosing the destination, evaluating the destination, moving to the destination.
For this, you can use let
to create a local variable that is creatively named "destination":
let destination patch (xcor + random-normal 0 1 ) (ycor + random-normal 0 1 )
Then we continue by evaluating whether or not destination is a viable patch and, if necessary, choosing a new destination:
while [ [pcolor] of destination != cyan ] [ set destination <...> ]
And then finally, after a satisfying destination has been found, moving to it:
move-to destination
Now I did also notice that you give each fish a x0
and y0
and you never update them. Are the fish meant to continuously hover around the same patch? I assumed not so I removed them and let the fishes determine their destination based on their current location instead (xcor
and ycor
)
breed [ fishes fish ]
to setup
clear-all
reset-ticks
ask patches [set pcolor gray]
ask patches with [ pycor < (max-pycor / 2) ] [ set pcolor cyan ]
create-fishes 4
[
setxy random-xcor random-ycor
set shape "fish" set size 2.5 set color white
while [ pcolor != cyan ] [ setxy random-xcor random-ycor ]
]
end
to go
fish-move
tick
end
to fish-move
ask fishes
[let destination patch (xcor + random-normal 0 1 ) (ycor + random-normal 0 1 )
while [ [pcolor] of destination != cyan ]
[
set destination patch (xcor + random-normal 0 1 ) (ycor + random-normal 0 1 )
]
move-to destination
]
end
As a last note, you could also use
let destination patch-at (random-normal 0 1) (random-normal 0 1)
which is a slightly shorter way of writing it.
Upvotes: 2