14.3.4 实现智能动物和捕食者

14.3.4 实现智能动物和捕食者

计算动物和捕食者的新位置的算法,在 C# 和 F# 中,看起来很相似,因为,我们可以使用相同的集合处理函数,来实现它们。在 F# 和其他标准的函数式语言中,这些都属于标准库,在 C# 3.0 中,可使用 LINQ。我们将在接下来的两小节中,来讨论这些算法,每一小节展示一种语言。

在 F# 中移动动物

让我们从一个函数开始,取一个动物和当前状态的位置作为参数值,返回这个动物的新位置。在这个仿真中,我们将有大约 100 个动物,必须计算所有动物的新位置。这意味着,它可能是不值得的,使这个函数在一个调用内,以并行方式运行其逻辑。相反,我们会在稍后并行化许多函数调用。找出在哪里拆分这个计算的,是并行化应用程序的重要组成部分。

清单 14.25 实现了动物行为,在通过仿真世界中,生成 10 个随机地点,找出在哪儿最安全。这是通过看到这个位置的直接路径,计算附近的捕食者有多近实现的。

Listing 14.25 Implementing the animal behavior (F#)

let moveAnimal (state:Simulation) (animPos:Vector) =
let nearestPredatorDistanceF<wbr>rom(pos) =<br> state.Predators<br> |&gt; Seq.map (distance pos) |&gt; Seq.min</wbr>

let nearestPredatorDistanceO<wbr>nPath(target) =<br> getPathPoints(10, animPos, target)<br> |&gt; Seq.map nearestPredatorDistanceF<wbr>rom |&gt; Seq.min</wbr></wbr>

let target =
randomLocations(10)
|> Seq.maxBy nearestPredatorDistanceO<wbr>nPath</wbr>

animPos + (target - animPos) *
(20.0 / (distance target animPos))

清单 14.25 首先实现两个本地的工具函数。第一个函数使用 Seq.map 来计算每个捕食者与指定的位置之间的距离,然后,使用 Seq.min 找出其中的最短距离。第二个函数在这个动物的当前的位置和指定的目标的路径是,查找最近的捕食者,通过检查它们之间路径上的几个点实现。

接下来,我们选择动物的目标位置。我们生成 10 随机的位置,然后选择一个动物可以到达的位置,而呆得尽可能远离捕食者。用 Seq.maxBy 做,返回的元素给指定的函数,返回最大值。在我们的例子中,这个函数将返回最短的距离,在捕食者与从动物的当前位置到随机生成的目标路径之间。最后,我们使用 Vector 类型的重载运算符,计算并返回动物的新位置。每次函数调用,动物在生成的最佳方向上移动 20 点。

我们将使用类似的算法来移动捕食者,但是,显然具有不同的目标。捕食者也将生成随机位置,然后,在最佳的方向上移动。下面一小节显示了代码的 C# 版本。

在 C# 中移动捕食者

确定捕食者的最佳目标的算法有点困难。我们要使捕食者沿着的路径直,有最多的动物和最少的其它捕食者。实现这个算法的 C# 方法展示在清单 14.26。这是Simulation 类的一部分,它可以很容易地访问其它捕食者和动物。(这就是不需要取当前状态作为参数的原因,像我们在 F# 动物行为的函数中所做的;当前状态用 this。)

Listing 14.26 Implementing the predator behavior (C#)

int CountCloseLocations(IEnumerable<Vector> an, Vector pos) {
return an.Where(a =>
Distance(a, pos) < 50).Count();
}

int CountCloseLocationsOnPat<wbr>h(IEnumerable&lt;Vector&gt; an,<br> Vector pfrom, Vector ptarget) {<br> return GetPathPoints(10, pfrom, ptarget)<br> .Sum(pos =&gt; CountCloseLocations(an, pos));<br> }</wbr>

Vector MovePredator(Vector predPos) {
var target = RandomLocations(20).MaxBy(pos =>
CountCloseLocationsOnPat<wbr>h(Animals, predPos, pos) -<br> CountCloseLocationsOnPat<wbr>h(Predators, predPos, pos) * 3);</wbr></wbr>

return predPos + (target - predPos) *
(10.0 / Distance(target, predPos));
}

在动物移动的 F# 代码中,我们首先实现两个本地辅助函数。在 C# 中,我们把类似的辅助函数实现为普通的方法。原则上,我们也可以使用本地 lambda 函数,但是,我们决定使用更典型的 C# 方法,以使代码更简单。

第一个方法取一个向量的集合(可以是动物的集合,也可以是捕食者的集合),计臬出靠近指定点的有多少。第二个辅助函数计算出在整个路径上,有多少捕食者靠近选定点的和。这是通过在路径上生成一个点的集合实现,对每个点调用第一个方法,计算结果的和。如果在路径上有多个点靠近,可以一个捕食者多次。实际上,这并不是问题,因为,如果一个捕食者靠近多个点,它可能更危险。

要实现捕食者的行为,我们生成 20 个随机位置,选择一个有最多的动物、最少捕食者的位置,靠近捕食者的当前位置和目标之间的路径。每个随机位置,我们两次调用 LocationsOnPath,计算这个"分值"。我们把捕食者邻近的数乘以一个常数,使它更明显,因为在整个仿真世界中的捕食者的数量太少。MaxBy 扩展方法返回有最大分值的位置。这个方法并不是一个标准的 LINQ 运算符,但是,你可以在本书的网站上,完整的仿真源代码中找到它的实现。

现在,我们已经有了计算动物和捕食者的新位置的函数,终于可以实现仿真的更大一步的函数。需要计算所有动物和捕食者的新位置,所以,这将是在仿真中引入并行度的最佳地方。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值