模拟

递送机器人观察世界并决定它想要移动的方向。 因此,我们可以说机器人是一个函数,接受VillageState对象并返回附近地点的名称。

因为我们希望机器人能够记住东西,以便他们可以制定和执行计划,我们也会传递他们的记忆,并让他们返回一个新的记忆。 因此,机器人返回的东西是一个对象,包含它想要移动的方向,以及下次调用时将返回给它的记忆值。

  1. function runRobot(state, robot, memory) {
  2. for (let turn = 0;; turn++) {
  3. if (state.parcels.length == 0) {
  4. console.log(`Done in ${turn} turns`);
  5. break;
  6. }
  7. let action = robot(state, memory);
  8. state = state.move(action.direction);
  9. memory = action.memory;
  10. console.log(`Moved to ${action.direction}`);
  11. }
  12. }

考虑一下机器人必须做些什么来“解决”一个给定的状态。 它必须通过访问拥有包裹的每个位置来拾取所有包裹,并通过访问包裹寄往的每个位置来递送,但只能在拾取包裹之后。

什么是可能有效的最愚蠢的策略? 机器人可以在每回合中,向随机方向行走。 这意味着很有可能它最终会碰到所有的包裹,然后也会在某个时候到达包裹应该送达的地方。

以下是可能的样子:

  1. function randomPick(array) {
  2. let choice = Math.floor(Math.random() * array.length);
  3. return array[choice];
  4. }
  5. function randomRobot(state) {
  6. return {direction: randomPick(roadGraph[state.place])};
  7. }

请记住,Math.random()返回 0 和 1 之间的数字,但总是小于 1。 将这样一个数乘以数组长度,然后将Math.floor应用于它,向我们提供数组的随机索引。

由于这个机器人不需要记住任何东西,所以它忽略了它的第二个参数(记住,可以使用额外的参数调用 JavaScript 函数而不会产生不良影响)并省略返回对象中的memory属性。

为了使这个复杂的机器人工作,我们首先需要一种方法来创建一些包裹的新状态。 静态方法(通过直接向构造函数添加一个属性来编写)是放置该功能的好地方。

  1. VillageState.random = function(parcelCount = 5) {
  2. let parcels = [];
  3. for (let i = 0; i < parcelCount; i++) {
  4. let address = randomPick(Object.keys(roadGraph));
  5. let place;
  6. do {
  7. place = randomPick(Object.keys(roadGraph));
  8. } while (place == address);
  9. parcels.push({place, address});
  10. }
  11. return new VillageState("Post Office", parcels);
  12. };

我们不想要发往寄出地的任何包裹。 出于这个原因,当do循环获取与地址相同的地方时,它会继续选择新的地方。

让我们建立一个虚拟世界。

  1. runRobot(VillageState.random(), randomRobot);
  2. // → Moved to Marketplace
  3. // → Moved to Town Hall
  4. // → …
  5. // → Done in 63 turns

机器人需要花费很多时间来交付包裹,因为它没有很好规划。 我们很快就会解决。

为了更好地理解模拟,你可以使用本章编程环境中提供的runRobotAnimation函数。 这将运行模拟,但不是输出文本,而是向你展示机器人在村庄地图上移动。

  1. runRobotAnimation(VillageState.random(), randomRobot);

runRobotAnimation的实现方式现在仍然是一个谜,但是在阅读本书的后面的章节,讨论 Web 浏览器中的 JavaScript 集成之后,你将能够猜到它的工作原理。