圆形竞技场中的运动模拟

Movement Simulation in a Circular Arena

我希望通过 NetLogo 模拟完成以下任务:

创建一个半径为10厘米的三个区域的有界圆形世界

运动行为

边缘跟随行为 - Thigmotaxis

乌龟可以随意进入外区,但以下规则会控制它在那里的行为:

在每个刻度的基础上为每只海龟生成位置报告(二维坐标)

将此报告导出为 CSV 或 TXT 文件

我的代码基于 NetLogo 库中的“Random Walk Example”,包括“per tick”规则,例如转角、移动长度。我试图实现海龟每刻暂停的概率,但我不知道如何合并 n 刻的持续时间。内部和外部区域是不同颜色的补丁。然后,我们可以将乌龟的行为建立在 if pcolor = red [commands go here] 的基础上。此外,当乌龟撞到世界边界时,它往往会被卡住,因为它会蠕动以寻找逃生角度。相反,是否有可能让乌龟在避开禁区(黑色补丁颜色)的同时“变成”世界的弯曲墙?最后,对于数据导出,保存 Commmand Center 输出很容易,但它的格式不便于分析,即 xy 单独列中的坐标等

to setup
  clear-all
  resize-world -100 100 -100 100 ; 1 unit = 1 mm
  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]
  ]
  forward random-normal 10 4
  show list xcor ycor
  ]
end

从技术上讲,这是一堆(公认的相关)问题,而不是单个问题(在 Whosebug 上更受欢迎)。但我会看看我是否能做出连贯的答案。

这里是 a runnable version of the final code,其中包含所有感兴趣的人的所有更改。

首先,控制乌龟移动的最简单方法是使用 patch-ahead 原语来检查它们将移动到哪里,然后在必要时更改它们的目的地。当使用 forward 1 而不是随机数时,这是最简单的,所以我从它开始。然后我使用 face one-of neighbors with [pcolor = red] 让乌龟面对一个“好”的补丁。同样,这仅适用于 forward 1.

我还添加了 __change-topology false false 以防止乌龟环绕世界,因为一些补丁确实在边缘处接触。

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

第二项是从外部观察到的粘性内部区域。我们使用与上述相同的技术并进行一些小调整。我没有对 setupgo 进行更多更改,因此从这里开始只显示 move-turtles

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

第三项是你想让海龟做的“暂停”。我不清楚这应该如何工作。首先,最简单的是,这只是乌龟不为蜱行动的机会。在这里,我将机会存储在一个 paused 变量中,该变量用于转弯和 forward。很难看到结果,因为滴答 运行 如此之快,但它们确实会暂停片刻。

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

由于很难看到这种效果,并且因为您提到要暂停 n 个刻度,所以我还做了一个版本,其中每只海龟都跟踪应该暂停多长时间。为此,我们需要在文件顶部添加一个 turtles-own [ pause ] 变量来计算它静止不动的滴答声。如果乌龟碰上了随机机会,它不会移动,而是设置暂停变量,并且在未来的滴答声中,它将倒计时到 0,然后再次开始移动。

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

您的最后一项是将海龟数据导出为 CSV 或文本。你有两个选择。您可以使用 the CSV extension or you can use BehaviorSpace 到 运行 您的模型作为“实验”。两者都会起作用。您已经在 move-turtles 过程中使用 show list xcor ycor 语句有了正确的想法,您只需要获取所有海龟的数据以输出到 CSV 或使用 BehaviorSpace 报告器:[(list who xcor ycor)] of turtles。我包括 who 数字,这样数据更容易被 turtle track/sort。

编辑:

如评论中所述,先前版本可能会引发 运行时间错误。这个 NOBODY 错误是因为我禁用了环绕,这意味着海龟可能会面对世界边缘并执行 patch-ahead 1 which returns NOBODY 而我忘记检查它了。我会为此添加一个检查,但由于您想要可变步长版本,让我们同时添加它。

我们在使用 random-normal 10 4 时遇到的一个问题是它可以生成任意大的数字。 (顺便说一句,在我看来,每只海龟都有一个暂停也让它们每次移动了一个随机的距离,我不相信随机距离会增加太多。)如果我们想让海龟移动得更多一次多于 1 space,但我们想要保持只检查前面的补丁的相对简单的逻辑,我们可以将 forward 1 移动到一个循环中,随着我们的进行减少距离。然后,我们还必须将 bounce/sticky 检查移动到该循环中,因为我们可以从黑色的边缘向后穿过内部边界。

我还制定了一个更强大的 face-red-patch 程序来确保我们永远不会陷入困境。

你可以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