Книга: Выразительный JavaScript

Больше форм жизни

Больше форм жизни

Одна из интересных ситуаций, происходящих в мире, случается, когда два существа отскакивают друг от друга. Можете придумать другую интересную форму взаимодействий?

Я придумал существо, двигающееся по стенке. Оно держит свою левую руку (лапу, щупальце, что угодно) на стене и двигается вдоль неё. Это, как оказалось, не так-то просто запрограммировать.

Нам нужно будет вычислять, используя направления в пространстве. Так как направления заданы набором строк, нам надо задать свою операцию dirPlus для подсчёта относительных направлений. dirPlus("n", 1) означает поворот по часовой на 45 градусов на север, что приводит к “ne”. dirPlus("s", -2) означает поворот против часовой с юга, то есть на восток.

var directionNames = Object.keys(directions);
function dirPlus(dir, n) {
  var index = directionNames.indexOf(dir);
  return directionNames[(index + n + 8) % 8];
}
function WallFollower() {
  this.dir = "s";
}
WallFollower.prototype.act = function(view) {
  var start = this.dir;
  if (view.look(dirPlus(this.dir, -3)) != " ")
    start = this.dir = dirPlus(this.dir, -2);
  while (view.look(this.dir) != " ") {
    this.dir = dirPlus(this.dir, 1);
    if (this.dir == start) break;
  }
  return {type: "move", direction: this.dir};
};

Метод act только сканирует окружение существа, начиная с левой стороны и дальше по часовой, пока не находит пустую клетку. Затем он двигается в направлении этой клетки.

Усложняет ситуацию то, что существо может оказаться вдали от стен на пустом пространстве — либо обходя другое существо, либо изначально оказавшись там. Если мы оставим описанный алгоритм, несчастное существо будет каждый ход поворачивать налево, и бегать по кругу.

Так что есть ещё одна проверка через if, что сканирование нужно начинать, если существо только что прошло мимо какого-либо препятствия. То есть, если пространство сзади и слева не пустое. В противном случае сканировать начинаем впереди, поэтому в пустом пространстве он будет идти прямо.

И наконец, есть проверка на совпадение this.dir и start на каждом проходе цикла, чтобы он не зациклился, когда существу некуда идти из-за стен или других существ, и оно не может найти пустую клетку.

Этот небольшой мир показывает существ, двигающихся по стенам:

animateWorld(new World(
  ["############",
   "#     #    #",
   "#   ~    ~ #",
   "#  ##      #",
   "#  ##  o####",
   "#          #",
   "############"],
  {"#": Wall,
   "~": WallFollower,
   "o": BouncingCritter}

Оглавление книги


Генерация: 0.848. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз