Ashfaq
Ashfaq

Reputation: 197

Avoid visited patch netlogo

Sir i am working on a project and time to time i use to post questions here related to that problem. I have created a simulation scenario i which turtles (robots) move around in the space and also each robot keep track of its visited patches. On the movement if patch-ahead 1 is visited patch then i need to turn the robot to 45 degree left and check again for patch-ahead until it checks all 8 neighbors if any one of the 8 is UN-visited then it should move to that patch and continue its exploration. But if all 8 are visited then it should move to patch which is in front of current heading after checking the all 8 neighbors no matter it is visited. Here is the piece of code i am using.

breed [robots robot ]
robots-own[ state memory ]
patches-own [ is-obstacle? ]

to setup

__clear-all-and-reset-ticks
create-robots num [ 
set memory (list patch-here)
]
draw-obstacles
  ask patches [if pxcor = 0 and pycor = 0  [ set pcolor black ]]
end   

to draw-obstacles
   ask patches with [ pxcor mod 6 = 0 and pycor mod 6 = 0 ] [set pcolor red set is-obstacle? true]
  ; set pcolor red
  ask patches [ ifelse pcolor = red [ set is-obstacle? true ][ set is-obstacle? false ] ]
  ask patches with [ count neighbors != 8 ] [ set pcolor red set is-obstacle? true ]
end


to make-obstacle
 if mouse-down?
 [ ask-concurrent patches
   [ if ((abs (pxcor - mouse-xcor)) < 1) and ((abs (pycor - mouse-ycor)) < 1)
     [set pcolor red]]
 ]
end
to remove-obs
 if mouse-down?
 [ ask-concurrent patches
   [ if ((abs (pxcor - mouse-xcor)) < 1) and ((abs (pycor - mouse-ycor)) < 1)
     [set pcolor black]]
 ]
end

to go
  ask patches [if ( pcolor = red )[set is-obstacle? true]]
  ask patches [if ( pcolor = black )[set is-obstacle? false]]
  ask-concurrent robots ; wanderers instructions
  [
   rt random-float rate-of-random-turn 
   lt (rate-of-random-turn  / 2)
   set-state
   move-robots
  ]
  tick 
end

to move-robots ;;turtle proc
 if (not member? state ["disperse" "explore"]) [
    error "Unknown state"
  ]
  if (state = "disperse") [
    disperse
  ]
  if (state = "explore") [
    explore
  ]
end

to set-state ;;turtle proc
  ifelse (any? other turtles in-radius 1) [
    set state "disperse"
  ] [
    set state "explore"
  ]
end
to disperse ;;turtle proc
 avoid-obstacle
 move1

 ; move-to one-of patch-set [neighbors] of neighbors
end

to explore
  move
  ;search-open-room
  avoid-obstacle
  ;move-to one-of neighbors
end

to move
 fd speed
 set memory lput patch-here memory
 if ( (member? patch-ahead 1 memory) or ([is-obstacle?] of patch-ahead 1 ) )
  [ lt random 45

     ]

end

to move1
fd speed
end

to avoid-obstacle
  set memory lput patch-here memory
      if ([is-obstacle?] of patch-ahead 1 )
    [
        ifelse [is-obstacle?] of patch-at-heading-and-distance (heading - 5) 1
        [
           ifelse [is-obstacle?] of patch-at-heading-and-distance (heading + 5) 1
            [ 
                ifelse random 1 = 0
                [ rt 40 ]
                [ lt 40 ]
            ]
            [ rt 60 ]
        ]
        [lt 60]
    ]

end
to search-open-room
  ask robots[
    ifelse ([is-obstacle?] of patches in-cone 2 150 )
      [  rt 45 ] [ move ]

    ]

end

But in the move procedure i am just able to lt random 45. How to change it according to above mentioned scenario. I tried many with while loop and repeat statement but code does not seems to be working for me.

Upvotes: 0

Views: 1309

Answers (1)

Nicolas Payette
Nicolas Payette

Reputation: 14972

You could do it using while or repeat, but I think this a case where recursion works well.

The idea is to have a procedure that keeps on calling itself until the desired state is achieved:

to turn-until-free [ n ]
  let target ifelse-value (patch-ahead 1 = patch-here)
    [ patch-ahead 2 ]
    [ patch-ahead 1 ]
  let seen? member? target memory
  let obstacle? [ is-obstacle? ] of target
  if-else n < 8
    [ if seen? or obstacle? [ lt 45 turn-until-free n + 1 ] ]
    [ if obstacle? [ lt 45 turn-until-free n + 1 ] ]
end

The n parameter represents the number of calls that we've already made to the procedure (or, in other words, the number of neighbors that we've checked so far). When you call the procedure for the first time, you start with n = 0:

to move
  turn-until-free 0
  fd 1
  set memory lput patch-here memory
  ask patch-here [ set pcolor black + 2 ] ; just to show what's visited
end

A couple of things that were not part of your original specification:

  • It can happen that patch-ahead 1 is the same patch that the robot is already on. A patch has sides of length 1, but its diagonal is a bit longer (√2). So if a robot is in the bottom left corner, for example, and facing towards the top right, patch-ahead 1 = patch-here will be true. In these cases, we look a bit further and set the target to patch-ahead 2.

  • It can happen that, after checking all 8 neighbors, you end up facing an obstacle. If that's the case, you need to keep on turning until you're clear of the obstacle. And as a matter of fact, doing this takes care of obstacle avoidance nicely, and you might be able to get rid of the avoid-obstacle procedure in your code.

Edit:

Here is the code needed (in addition to the two procedures above) for a fully working example:

breed [ robots robot ]
robots-own [ memory ]
patches-own [ is-obstacle? ]

to setup
  ca
  ask patches [ set is-obstacle? false ]
  ask patches with [ pxcor mod 6 = 0 and pycor mod 6 = 0 ] [
    set is-obstacle? true
    set pcolor red
  ]
  ask n-of 5 patches with [ not is-obstacle? ] [
    sprout-robots 1 [ set memory [] ]
  ]
  reset-ticks
end

to go
  ask robots [ move ]
  tick
end

If you are having trouble with runtime errors or other unwanted behavior, I suggest you start from this and add back whatever else you had in your simulation one piece at a time. Then, you can see exactly where the problem comes from.

I also changed if-else n < 7 for if-else n < 8 in the turn-until-free procedure above. This way, the robot comes back to its original heading if all neighbors are explored instead of turning a bit right. This avoids going in circles once the whole territory is explored.

Upvotes: 2

Related Questions