1
0
mirror of https://github.com/apachecn/eloquent-js-3e-zh.git synced 2025-05-23 20:02:20 +00:00
This commit is contained in:
wizardforcel 2018-05-05 11:52:59 +08:00
parent ddcd1a7cc1
commit 2115f76626

48
7.md
View File

@ -1,4 +1,4 @@
# Chapter 7Project: A Robot
# 七、项目:机器人
> [...] the question of whether Machines Can Think [...] is about as relevant as the question of whether Submarines Can Swim.
>
@ -181,7 +181,7 @@ function randomRobot(state) {
由于这个机器人不需要记住任何东西,所以它忽略了它的第二个参数(记住,可以使用额外的参数调用 JavaScript 函数而不会产生不良影响)并省略返回对象中的`memory`属性。
为了使这个复杂的机器人工作,我们首先需要一种方法来创建一些包裹的新状态。 静态方法(通过直接向构造函数添加一个属性来编写)是放置该函数的好地方。
为了使这个复杂的机器人工作,我们首先需要一种方法来创建一些包裹的新状态。 静态方法(通过直接向构造函数添加一个属性来编写)是放置该功能的好地方。
```
VillageState.random = function(parcelCount = 5) {
@ -198,9 +198,9 @@ VillageState.random = function(parcelCount = 5) {
};
```
We dont want any parcels that are sent from the same place that they are addressed to. For this reason, the `do` loop keeps picking new places when it gets one thats equal to the address.
我们不想要发往寄出地的任何包裹。 出于这个原因,当`do`循环获取与地址相同的地方时,它会继续选择新的地方。
Lets start up a virtual world.
让我们建立一个虚拟世界。
```
runRobot(VillageState.random(), randomRobot);
@ -210,19 +210,19 @@ runRobot(VillageState.random(), randomRobot);
// → Done in 63 turns
```
It takes the robot a lot of turns to deliver the parcels, because it isnt planning ahead very well. Well address that soon.
机器人需要花费很多时间来交付包裹,因为它没有很好规划。 我们很快就会解决。
For a more pleasant perspective on the simulation, you can use the `runRobotAnimation` function thats available in this chapters programming environment. This runs the simulation, but instead of outputting text, it shows you the robot moving around the village map.
为了更好地理解模拟,您可以使用本章编程环境中提供的`runRobotAnimation`函数。 这将运行模拟,但不是输出文本,而是向你展示机器人在村庄地图上移动。
```
runRobotAnimation(VillageState.random(), randomRobot);
```
The way `runRobotAnimation` is implemented will remain a mystery for now, but after youve read the [later chapters](14_dom.html) of this book, which discuss JavaScript integration in web browsers, youll be able to guess how it works.
`runRobotAnimation`的实现方式现在仍然是一个谜,但是在阅读本书的后面的章节,讨论 Web 浏览器中的 JavaScript 集成之后,您将能够猜到它的工作原理。
## The mail trucks route
## 邮车的路线
We should be able to do a lot better than the random robot. An easy improvement would be to take a hint from the way real-world mail delivery works. If we find a route that passes all places in the village, the robot could run that route twice, at which point it is guaranteed to be done. Here is one such route (starting from the post office).
我们应该能够比随机机器人做得更好。 一个简单的改进就是从现实世界的邮件传递方式中获得提示。 如果我们发现一条经过村庄所有地点的路线,机器人可以通行该路线两次,此时它保证能够完成。 这是一条这样的路线(从邮局开始)。
```
const mailRoute = [
@ -233,7 +233,7 @@ const mailRoute = [
];
```
To implement the route-following robot, well need to make use of robot memory. The robot keeps the rest of its route in its memory and drops the first element every turn.
为了实现路线跟踪机器人,我们需要利用机器人的记忆。 机器人将其路线的其余部分保存在其记忆中,并且每回合丢弃第一个元素。
```
function routeRobot(state, memory) {
@ -244,25 +244,25 @@ function routeRobot(state, memory) {
}
```
This robot is a lot faster already. Itll take a maximum of 26 turns (twice the 13-step route), but usually less.
这个机器人已经快了很多。 它最多需要 26 个回合13 步的路线的两倍),但通常要少一些。
```
runRobotAnimation(VillageState.random(), routeRobot, []);
```
## Pathfinding
## 寻路
Still, I wouldnt really call blindly following a fixed route intelligent behavior. The robot could work more efficiently if it adjusted its behavior to the actual work that needs to be done.
不过,我不会盲目遵循固定的智能寻路行为。 如果机器人为需要完成的实际工作调整行为,它可以更高效地工作。
To do that, it has to be able to deliberately move towards a given parcel, or towards the location where a parcel has to be delivered. Doing that, even when the goal is more than one move away, will require some kind of route-finding function.
为此,它必须能够有针对性地朝着给定的包裹移动,或者朝着包裹必须送达的地点。 尽管如此,即使目标距离我们不止一步,也需要某种寻路函数。
The problem of finding a route through a graph is a typical _search problem_. We can tell whether a given solution (a route) is a valid solution, but we cant directly compute the solution the way we could for 2 + 2\. Instead, we have to keep creating potential solutions until we find one that works.
在图上寻找路线的问题是一个典型的搜索问题。 我们可以判断一个给定的解决方案(路线)是否是一个有效的解决方案,但我们不能像 2 + 2 这样,直接计算解决方案。 相反,我们必须不断创建潜在的解决方案,直到找到有效的解决方案。
The number of possible routes through a graph is infinite. But when searching for a route from _A_ to _B_, we are interested only in the ones that start at _A_. We also dont care about routes that visit the same place twice—those are definitely not the most efficient route anywhere. So that cuts down on the amount of routes that the route finder has to consider.
图上的可能路线是无限的。 但是当搜索`A``B`的路线时,我们只关注从`A`起始的路线。 我们也不关心两次访问同一地点的路线 - 这绝对不是最有效的路线。 这样可以减少查找者必须考虑的路线数量。
In fact, we are mostly interested in the _shortest_ route. So we want to make sure we look at short routes before we look at longer ones. A good approach would be to “grow” routes from the starting point, exploring every reachable place that hasnt been visited yet, until a route reaches the goal. That way, well explore only routes that are potentially interesting, and find the shortest route (or one of the shortest routes, if there are more than one) to the goal.
事实上,我们最感兴趣的是最短路线。 所以我们要确保,查看较长路线之前,我们要查看较短的路线。 一个好的方法是,从起点使路线“生长”,探索尚未到达的每个可到达的地方,直到路线到达目标。 这样,我们只探索潜在的有趣路线,并找到到目标的最短路线(或最短路线之一,如果有多条路线)。
Here is a function that does this:
这是一个实现它的函数:
```
function findRoute(graph, from, to) {
@ -279,15 +279,15 @@ function findRoute(graph, from, to) {
}
```
The exploring has to be done in the right order—the places that were reached first have to be explored first. We cant immediately explore a place as soon as we reach it, because that would mean places reached _from there_ would also be explored immediately, and so on, even though there may be other, shorter paths that havent yet been explored.
探索必须按照正确的顺序完成 - 首先到达的地方必须首先探索。 我们不能到达一个地方就立即探索,因为那样意味着,从那里到达的地方也会被立即探索,以此类推,尽管可能还有其他更短的路径尚未被探索。
Therefore, the function keeps a _work list_. This is an array of places that should be explored next, along with the route that got us there. It starts with just the start position and an empty route.
因此,该函数保留一个工作列表。 这是一系列应该探索的地方,以及让我们到那里的路线。 它最开始只有起始位置和空路线。
The search then operates by taking the next item in the list and exploring that, which means that all roads going from that place are looked at. If one of them is the goal, a finished route can be returned. Otherwise, if we havent looked at this place before, a new item is added to the list. If we have looked at it before, since we are looking at short routes first, weve found either a longer route to that place or one precisely as long as the existing one, and we dont need to explore it.
然后,通过获取列表中的下一个项目并进行探索,来执行搜索,这意味着,会查看从该地点起始的所有道路。 如果其中之一是目标,则可以返回完成的路线。 否则,如果我们以前没有看过这个地方,就会在列表中添加一个新项目。 如果我们之前看过它,因为我们首先查看了短路线,我们发现,到达那个地方的路线较长,或者与现有路线一样长,我们不需要探索它。
You can visually imagine this as a web of known routes crawling out from the start location, growing evenly on all sides (but never tangling back into itself). As soon as the first thread reaches the goal location, that thread is traced back to the start, giving us our route.
你可以在视觉上将它想象成一个已知路线的网,从起始位置爬出来,在各个方向上均匀生长(但不会缠绕回去)。 只要第一条线到达目标位置,其它线就会退回起点,为我们提供路线。
Our code doesnt handle the situation where there are no more work items on the work list, because we know that our graph is _connected_, meaning that every location can be reached from all other locations. Well always be able to find a route between two points, and the search cant fail.
我们的代码无法处理工作列表中没有更多工作项的情况,因为我们知道我们的图是连通的,这意味着可以从其他所有位置访问每个位置。 我们始终能够找到两点之间的路线,并且搜索不会失败。
```
function goalOrientedRobot({place, parcels}, route) {
@ -391,4 +391,4 @@ The class constructor can take such an array as argument, and store it as the
To add a property (`empty`) to a constructor that is not a method, you have to add it to the constructor after the class definition, as a regular property.
You need only one `empty` instance because all empty groups are the same and instances of the class dont change. You can create many different groups from that single empty group without affecting it.
You need only one `empty` instance because all empty groups are the same and instances of the class dont change. You can create many different groups from that single empty group without affecting it.