Technically this is a bunch of (admittedly related) questions, rather than a single question (as is preferred on StackOverflow). But I'll see if I can make a coherent answer.
Here is a runnable version of the final code with all the changes for anyone interested.
First, the simplest way to control turtle movement is to use the patch-ahead primitive to check where they would be moving to, and then changing their destination if necessary. This is easiest when using forward 1 instead of a random amount, so I start with that. I then use face one-of neighbors with [pcolor = red] to get the turtle facing a "good" patch. Again, that only works with the forward 1.
I also added __change-topology false false to prevent a turtle from wrapping around the world, as some of the patches do touch at the edges.
to setup
clear-all
resize-world -100 100 -100 100 ; 1 unit = 1 mm
; make sure the turtles can't wrap at the patches at the edges that touch
__change-topology false false
set-patch-size 2
ask patches [set pcolor black] ; outside arena | how to designate this patch color as "forbidden"?
ask patch 0 0 [ask patches in-radius 100 [set pcolor red]] ; outer zone
ask patch 0 0 [ask patches in-radius 85 [set pcolor gray]] ; inner zone
create-turtles 10 [set size 15]
ask turtles [
set color one-of base-colors ; assign color to each turtle without repeats?
pen-down
]
reset-ticks
end
to go
if ticks = 1200 [stop] ; each tick = 1 second
move-turtles
tick
end
to move-turtles
ask turtles [
if random-float 1 > 0.05 ; 5% probability of pause per tick
[
;equal chance of right or left turn
if random-float 1 > 0.50 [right random-normal 30 10]
if random-float 1 < 0.50 [left random-normal 30 10]
]
; Item #1 - outer zone blocked
; if turtles only move `1` at time, they cannot "skip" past a patch
; so to prevent moving into the black, all we have to do is point them somewhere else
if [pcolor] of patch-ahead 1 = black [
face one-of neighbors with [pcolor = red]
]
forward 1
]
end
The second item was a sticky inner zone from the outer. We use the same technique as above with a couple small tweaks. I have no more changes to setup or go, so just the move-turtles is presented from here on out:
to move-turtles
ask turtles [
if random-float 1 > 0.05 ; 5% probability of pause per tick
[
;equal chance of right or left turn
if random-float 1 > 0.50 [right random-normal 30 10]
if random-float 1 < 0.50 [left random-normal 30 10]
]
; to control turtle movement, we're going to use `patch-ahead` to check the patch color
; before moving. if turtles only move `1` at time, they cannot "skip" past a patch, which
; is necessary to use this technique.
; Item #1 - outer zone blocked
; so to prevent moving into the black, all we have to do is point them somewhere else
if [pcolor] of patch-ahead 1 = black [
face one-of neighbors with [pcolor = red]
]
; Item #2 - inner zone stickiness
; if we're in the outer zone and our target patch is inner zone, don't keep moving that way
; if we fail our check
if
pcolor = red ; we're in the outer zone
and [pcolor] of patch-ahead 1 = gray ; our target patch is grey
and random-float 1 < 0.8 ; our random probability to bounce off
[
; then we bounce off
face one-of neighbors with [pcolor = red]
]
forward 1
]
end
The third item is the "pause" you want the turtles to do. I was unclear how this was supposed to work. First, most simply, is just a chance that the turtle will not act for a tick. Here I store the chance in a paused variable that I use for both turning and then forward. It's very hard to see the result as the ticks run so quickly, but they do pause for a moment.
to move-turtles
ask turtles [
; Item 3a - single tick pause - 5% chance to pause and not move forward
let paused (random-float 1) <= 0.05
if not paused
[
;equal chance of right or left turn
if random-float 1 > 0.50 [right random-normal 30 10]
if random-float 1 < 0.50 [left random-normal 30 10]
]
; to control turtle movement, we're going to use `patch-ahead` to check the patch color
; before moving. if turtles only move `1` at time, they cannot "skip" past a patch, which
; is necessary to use this technique.
; Item #1
; so to prevent moving into the black, all we have to do is point them somewhere else
if [pcolor] of patch-ahead 1 = black [
face one-of neighbors with [pcolor = red]
]
; Item #2
; if we're in the outer zone and our target patch is inner zone, don't keep moving that way
; if we fail our check
if
pcolor = red ; we're in the outer zone
and [pcolor] of patch-ahead 1 = gray ; our target patch is grey
and random-float 1 < 0.8 ; our random probability to bounce off
[
; then we bounch off
face one-of neighbors with [pcolor = red]
]
if not paused [
forward 1
]
]
end
Since it is hard to see that effect and because you mentioned wanting to pause for n ticks, I also did a version where each turtle tracks how long the pause should be. To do this we need to add a turtles-own [ pause ] variable at the top of the file to count the ticks it sits still for. If a turtle hits the random chance, instead of moving it sets the pause variable and on future ticks will just count that back down to 0 and then start moving again.
to move-turtles
ask turtles [
; `pause = 0` to keep them from spinning in place when paused
if pause = 0 and random-float 1 > 0.05 ; 5% probability of pause per tick
[
;equal chance of right or left turn
if random-float 1 > 0.50 [right random-normal 30 10]
if random-float 1 < 0.50 [left random-normal 30 10]
]
; to control turtle movement, we're going to use `patch-ahead` to check the patch color
; before moving. if turtles only move `1` at time, they cannot "skip" past a patch, which
; is necessary to use this technique.
; Item #1 - outer zone barrier
; so to prevent moving into the black, all we have to do is point them somewhere else
if [pcolor] of patch-ahead 1 = black [
face one-of neighbors with [pcolor = red]
]
; Item #2 - inner zone stickiness
; if we're in the outer zone and our target patch is inner zone, don't keep moving that way
; if we fail our check
if
pcolor = red ; we're in the outer zone
and [pcolor] of patch-ahead 1 = gray ; our target patch is grey
and random-float 1 < 0.8 ; our random probability to bounce off
[
; then we bounch off
face one-of neighbors with [pcolor = red]
]
; Item #3b - counting pause
; if we are paused, just decrement the pause and take no action
ifelse pause > 0 [
set pause (pause - 1)
] [
ifelse random-float 1 > 0.05 [
; 95% chance to move forward
forward 1
] [
; 5% chance to pause 5 ticks
set pause 5
]
]
]
end
Your final item was exporting turtle data to CSV or text. You have two options. You can use the CSV extension or you can use BehaviorSpace to run your model as an "experiment". Either will work. You already had the right idea with the show list xcor ycor statement in your move-turtles procedure, you just need to get the data for all turtles to output to CSV or with the BehaviorSpace reporters: [(list who xcor ycor)] of turtles. I include who number so the data is easier to track/sort by turtle.
Edit:
As noted in the comments, the prior version can throw a runtime error. This NOBODY error is because I disabled wrapping, meaning a turtle could face a world edge and do patch-ahead 1 which returns NOBODY and I forgot to check for it. I'll add a check for that, but since you want the variable step length version, let's add that add the same time.
One problem we have using random-normal 10 4 is that it can generate arbitrarily large numbers. (As an aside, it seems to me having a pause for each turtle also makes them move a random amount of distance per time already, I'm not convinced the random distance adds much over that.) If we want the turtle to move more than 1 space at a time, but we want to keep the relatively simple logic of just checking the patches ahead, we can just move the forward 1 into a loop, decrementing the distance as we go. We also, then, have to move the bounce/sticky check into that loop as we could march from the edge of the black back across the inner border.
I also made a more robust face-red-patch procedure to try to make sure we never jump into the black.
You can run the model online to test it out.
to move-turtles
ask turtles [
; `pause = 0` to keep them from spinning in place when paused
if pause = 0 and random-float 1 > 0.05 ; 5% probability of pause per tick
[
;equal chance of right or left turn
if random-float 1 > 0.50 [right random-normal 30 10]
if random-float 1 < 0.50 [left random-normal 30 10]
]
; to control turtle movement, we're going to use `patch-ahead` to check the patch color
; before moving. if turtles only move `1` at time, they cannot "skip" past a patch, which
; is necessary to use this technique.
; Item #1 - outer zone barrier
; so to prevent moving into the black, all we have to do is point them somewhere else
if patch-ahead 1 = nobody or [pcolor] of patch-ahead 1 = black [
face-red-patch
]
; Item #3 - pause
; if we are paused, just decrement the pause and take no action
ifelse pause > 0 [
set pause (pause - 1)
] [
ifelse random-float 1 > 0.05 [
; 95% chance to move forward
; Item #5 - variable length moves
let forward-amount random-normal 10 4
while [patch-ahead 1 != nobody and [pcolor] of patch-ahead 1 != black and forward-amount > 0] [
; Item #2 - inner zone stickiness
; if we're in the outer zone and our target patch is inner zone, don't keep moving that way
; if we fail our check
if
pcolor = red ; we're in the outer zone
and [pcolor] of patch-ahead 1 = gray ; our target patch is grey
and random-float 1 < 0.8 ; our random probability to bounce off
[
; then we bounce off
face-red-patch
]
forward 1
set forward-amount (forward-amount - 1)
]
] [
; 5% chance to pause 5 ticks
set pause 5
]
]
]
end
to face-red-patch
; this kind of looping code can be dangerous, but if we're careful to use it only when we know it
; will terminate it should be okay. Use Tools > Halt if you think it hit a bad state and is in an
; infinite loop
while [patch-ahead 1 = nobody or [pcolor] of patch-ahead 1 != red] [
set heading random 360
]
end