FlyingDutch
FlyingDutch

Reputation: 1152

Netlogo let turtles random walk within an area

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

Answers (3)

Saeed
Saeed

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

LeirsW
LeirsW

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

LeirsW
LeirsW

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

Related Questions