Выразительный JavaScript (Хавербеке) - страница 72

>function randomElement(array) {

>  return array[Math.floor(Math.random() * array.length)];

>}


>function BouncingCritter() {

>  this.direction = randomElement(Object.keys(directions));

>};


>BouncingCritter.prototype.act = function(view) {

>  if (view.look(this.direction) != " ")

>    this.direction = view.find(" ") || "s";

>  return {type: "move", direction: this.direction};

>};

Вспомогательная функция >randomElement просто выбирает случайный элемент массива, используя >Math.random и немного арифметики, чтобы получить случайный индекс. Мы и дальше будем использовать случайность, так как она – полезная штука в симуляциях.

Конструктор >BouncingCritter вызывает >Object.keys. Мы видели эту функцию в предыдущей главе – она возвращает массив со всеми именами свойств объекта. Тут она получает все имена направлений из объекта >directions, заданного ранее.

Конструкция >|| "s" в методе >act нужна, чтобы >this.direction не получил >null, в случае если существо забилось в угол без свободного пространства вокруг – например, окружено другими существами.

Мировой объект

Теперь можно приступать к мировому объекту >World. Конструктор принимает план (массив строк, представляющих сетку мира) и объект >legend. Это объект, сообщающий, что означает каждый из символов карты. В нём есть конструктор для каждого символа – кроме пробела, который ссылается на >null (представляющий пустое пространство).

>function elementFromChar(legend, ch) {

>  if (ch == " ")

>    return null;

>  var element = new legend[ch]();

>  element.originChar = ch;

>  return element;

>}


>function World(map, legend) {

>  var grid = new Grid(map[0].length, map.length);

>  this.grid = grid;

>  this.legend = legend;


>  map.forEach(function(line, y) {

>    for (var x = 0; x < line.length; x++)

>      grid.set(new Vector(x, y),

>               elementFromChar(legend, line[x]));

>  });

>}

В >elementFromChar мы сначала создаём экземпляр нужного типа, находя конструктор символа и применяя к нему >new. Потом добавляем свойство >originChar, чтобы было просто выяснить, из какого символа элемент был создан изначально.

Нам понадобится это свойство >originChar при изготовлении мирового метода >toString. Метод строит карту в виде строки из текущего состояния мира, проходя двумерным циклом по клеткам сетки.

>function charFromElement(element) {

>  if (element == null)

>    return " ";

>  else

>    return element.originChar;

>}


>World.prototype.toString = function() {

>  var output = "";

>  for (var y = 0; y < this.grid.height; y++) {

>    for (var x = 0; x < this.grid.width; x++) {

>      var element = this.grid.get(new Vector(x, y));