如何使人们前往特定的补丁并在前往目的地的途中避开某些补丁?

How to make people go towards a specific patch and avoid certain patches on the way to the destination?

我正在为我的大学演讲厅建造一个疏散模型。我面临的问题是,即使我在代码中包含了避免墙壁的程序,人们总是会走过不应该走过的灰色补丁。这是我的疏散模型的当前代码。乌龟是否有可能在到达出口时停止移动,在这种情况下是绿色补丁?

breed [people person]

to setup
  clear-all
  reset-ticks
  setup-patches
  setup-people
end

to setup-people
  set-default-shape people "person"
  ask n-of n-people (patches with [pcolor = white]) [sprout-people 1]
  ask people [set color cyan]
end

to setup-patches
  draw-wall
  draw-exit

  ;change the color of the floor for better visibility
  ask patches[
  if pcolor = black [set pcolor white ]
  ]
end

to draw-wall

  ; Make 4 boundary walls
  ask patches with [ pycor >= -25  and pycor >= 25][ set pcolor gray ]
  ask patches with [ pycor <= -25  and pycor <= 25][ set pcolor gray ]
  ask patches with [ pxcor >= -25  and pxcor >= 25][ set pcolor gray ]
  ask patches with [ pxcor <= -25  and pxcor <= 25][ set pcolor gray ]

  ; make rows of walls inside that look like seats in a lecture hall
  ; left rows of chairs 
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 20][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 18][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 16][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 14][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 12][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 10][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 8][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 6][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 4][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 2][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = 0][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = -2][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = -4][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = -6][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = -8][set pcolor gray]
  ask patches with [pxcor <= 21 and pxcor >= 13 and pycor = -10][set pcolor gray]

  ; middle rows of chairs 
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 20][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 18][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 16][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 14][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 12][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 10][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 8][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 6][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 4][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 2][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = 0][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = -2][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = -4][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = -6][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = -8][set pcolor gray]
  ask patches with [pxcor >= -9 and pxcor <= 9 and pycor = -10][set pcolor gray]

  ; right rows of chairs
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 20][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 18][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 16][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 14][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 12][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 10][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 8][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 6][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 4][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 2][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = 0][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = -2][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = -4][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = -6][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = -8][set pcolor gray]
  ask patches with [pxcor >= -21 and pxcor <= -13 and pycor = -10][set pcolor gray]

end

to draw-exit

  ; Setting 4 exits assuming all UTAR lecture halls have 4 exits
  ; two at the top left and right and two at the bottom left and right
  ask patches with [pxcor <= 23 and pxcor >= 21 and pycor = 25][set pcolor green]
  ask patches with [pxcor >= -23 and pxcor <= -21 and pycor = 25][set pcolor green]
  ask patches with [pxcor <= 23 and pxcor >= 21 and pycor = -25][set pcolor green]
  ask patches with [pxcor >= -23 and pxcor <= -21 and pycor = -25][set pcolor green]

end

to go
  let hall patches with [pycor <= 0 and pycor >= -25 and pxcor <= 0 and pxcor >= -25 ]
  ask people[
    move-people
    avoid-walls
  ]
  tick
end

to move-people
  face min-one-of patches with [pcolor = green ] [distance myself ]
  fd 0.1 
end

 to avoid-walls
  ifelse [pcolor] of patch-ahead 1 = gray 
  [lt random-float 360 ] ;; we see a gray patch ahead of us. We turn a random amount
  [fd 0.1] ;; otherwise, it is safe to move forward  
end

你运行“移动”海龟面向一个方向,然后移动。 然后你运行“避开”海龟寻找灰色并转向的地方。

所以你的海龟在寻找灰色之前已经移动了。

我的建议:瞄准,然后纠正,然后移动。请注意,这个非常简单的导航规则不会像人那样移动。

to aim
  ;; face nearest green patch
  face min-one-of patches with [pcolor = green ] [distance myself ]
end

to correct
  ;;if about to step on a gray patch, turn away from it
  if ([ pcolor ] of patch-ahead .1 = gray)
  [ ;; where is the center of the next patch?
    let towards-patch-center towards patch-ahead .1
    ;; calculate a direction away from the center of the patch
    let diff subtract-headings towards-patch-center heading
    ;; turn left (CCW) or right (CW)
    if (diff >= 0 ) ;; it's ahead or clockwise
    [ set heading heading - 1 ] ;; turn counter-clockwise
    if (diff < 0 ) ;; its counter-clockwise
    [ set heading heading + 1 ] ;; turn clockwise
  ]
end

to walk
   jump .1
end

to navigate
   aim
   correct
   walk
end
  

这将是一个很长的答案,但我想逐步指导您。

让我们从您面临不良行为的原因开始。

go中,首先要求人们移动(move-people),然后才要求他们避开墙壁(avoid-walls)。

即使仔细观察,您也可以看到您的 avoid-walls 程序对您的人的步行没有任何影响。让我们从您代理的角度来阅读您的代码:

  • 我是一个人,我进入move-people程序,这让我面对最近的出口。我面前有一堵墙,但代码中没有任何内容告诉我应该关心它:实际上下一行代码是 forward 0.1,所以我只是向前移动。
  • 现在我进入avoid-walls程序。正如我所说,我面前有一堵墙,所以我随机改变了航向。啊,我面前没有墙了!但是我不会朝这个新的方向前进,因为现在我改变了标题,没有一行代码告诉我这样做。
  • 我退出avoid-walls这意味着我还需要退出go中的ask people [...]命令块。我已经完成了这次迭代的操作。
  • 我们在下一次迭代中。我现在正朝着没有墙壁的方向前进(因为我在上一次迭代中从 avoid-walls 中随机选择了这个方向)...但是,在我朝这个正确的方向移动之前,我又在 move-people ,我再次被要求改变我的航向以面对最近的绿色补丁。这意味着我回到了最初的情况,当时我面前有一堵墙!下一行代码让我移动forward 0.1,所以我继续在墙上移动...
  • 等等,等等……

让我们一步一步地看看如何解决这个问题。

首先,让我们整理几件事:

  1. 您的 people 是执行 move-people 程序的代理,因此此程序的更好名称是 move 这样您就可以拥有 ask people [move].
  2. 为了让特工在到达出口时停止移动,您只需确保只有在绿色补丁上的特工才会被要求移动: ask people with [pcolor != green] [move](注意海龟可以直接读取和修改它们所站的补丁的 patches-own 变量,这就是我们能够在海龟的上下文中使用 pcolor 的原因)。
  3. 您可能还希望让您的模型在每个人都到达出口时停止,因此您可以在 go 过程的开头添加一个停止条件:if (not any? people with [pcolor != green]) [stop].

以上三点的结果就是下面的go过程:

to go
  if (not any? people with [pcolor != green]) [stop]

  ask people with [pcolor != green] [
    move
  ]

  tick
end

现在,回到move的内容。

如您所见,我在 go 中只有 move(即我删除了任何特定于避免墙壁目标的程序)。这是因为,按照我们上面描述的人的旅程,避免墙壁的动作必须而不是之后执行移动,但在选择移动位置时。 同样重要的是要确保当一个人找到一个没有墙壁的方向时,它必须朝那个方向移动,然后再被要求面对出口。

因此,第一个想法可能是:

to move
  face min-one-of patches with [pcolor = green] [distance myself]
  
  while [[pcolor] of patch-ahead 1 = gray] [
    right random 360
  ]
  
  forward 1
end

这样,我们确保在 go 的每次迭代中,人们将:

  1. 面向最近的出口。
  2. 如果他们前面的补丁很清楚,他们将忽略while循环并直接跳转到forward 1
  3. 如果他们前面的补丁有墙,他们将进入循环,只有在找到明确的方向时才会退出循环(即当 while 循环的条件评估为 false 时)。

在任何情况下,在 go 的每次迭代中,每只海龟都将在没有墙壁的方向上精确移动 1。在 go 的下一次迭代中,每只海龟将简单地重新开始,面向最近的出口并再次测试墙壁状况。

这是有效的,它类似于 NetLogo 库中的 Look Ahead Example 模型(不同之处在于,这里的 while 循环使它成为可能每只海龟在 go 的每次迭代中移动,而不必花费完整的迭代仅在需要时改变航向)。然而,如果你尝试一下,你会发现结果是发现自己位于墙线之间的人会随机移动,直到他们找到出路。这不是很现实,但我们可以让它更现实。

例如,我们可以确保找到一堵墙的人不会完全随机移动以寻找远离墙的路,而是会稍微向墙的方向倾斜最近的出口。

一个想法可以是将360°光谱分成四个象限(0°-89°;90°-179°;180°-269°;270°-359°),这样每个人面对一个墙可以:

  1. 记下第i象限最近的出口是哪个;
  2. 如果前面有墙,在同一象限内寻找新的方向。

这样,人们的漫游就不会那么随机了(也就是说,我们会看到更少的来回走动,更多的是绕过障碍物)。 为此,让我们创建一个名为 new-direction 的新记者。要使用它,我们可以创建一个名为 targetpeople-own 变量(以避免重复 min-one-of patches with [pcolor = green] [distance myself]):

people-own [
  target
]


to move
  set target min-one-of patches with [pcolor = green] [distance myself]
  face target

  while [[pcolor] of patch-ahead 1 = gray] [
    set heading new-direction
  ]

  forward 1
end


to-report new-direction
  let direction-quadrant ceiling (towards target / 90)
  if (direction-quadrant = 0) [
    set direction-quadrant 1
  ]

  report random 91 + (90 * (direction-quadrant - 1))
end

您可以自己计算一下,发现 new-direction 总是报告一个新航向,该航向与最近出口的方向位于同一象限(包括其边界)。鉴于这发生在 while 循环内,每个智能体只有在找到 或多或少 朝向最近的出口并且可以避免墙。一旦他们找到它,他们就会继续前进。

然而你也会看到,有时人们会陷入一个循环:当他们发现自己处于一个位置时,再向前一步会导致最近的出口改变象限(正如我们从海龟),随后向前的一步导致最近的出口返回到前一个象限。

我们可以通过确保人们记住他们在上一步中所站在的确切补丁是什么来解决这个问题(我在下面的代码中称之为 last-patch)。如果这样的补丁与他们现在计划前往的补丁相同(用 (patch-ahead 1 = last-patch) 检查),则意味着他们陷入了循环。在那种情况下,他们不执行 forward 1 而执行 forward -1 ,这基本上意味着“向后移动 1”。考虑到此时 forward 指的是海龟在退出 while 块后获得的航向,这意味着通过这种方式海龟被强制跳出循环:

to move
  let last-patch patch-at-heading-and-distance (heading) (-1)

  set target min-one-of patches with [pcolor = green] [distance myself]
  face target

  while [[pcolor] of patch-ahead 1 = gray] [
    set heading new-direction
  ]

  ifelse (patch-ahead 1 = last-patch)
    [forward -1]
    [forward 1]
end

请注意,此解决方案是可改进的:它适用于您的场景,但对于更复杂的大厅和墙壁设计可能不够。