2013-12-26 2 views
0

Это код из книги Eloquent Javascript. Он создает 2D-объект под названием Terrarium, где у насекомых может двигаться. Насекомые перемещаются с использованием функции: terrarium.step. Но когда я запускаю его, он говорит, что «центр не определен». center - аргумент функции: Terrarium.prototype.listSurroundings. Эта функция вызывает другую функцию, которая использует метод центра в качестве аргумента. Что может быть неправильным? Я прилагаю весь код здесь, включая инициализацию террариум и т.д.Код Terrarium в Eloquent Javascript не работает

function forEach(array,action) { 
    for(var i=0;i<array.length;i++) 
    {action(array[i]);} 
} 

function forEachIn(object, action) { 
    for (var property in object) { 
     if (Object.prototype.hasOwnProperty.call(object, property)) 
     action(property, object[property]); 
    } 
} 

function Dictionary(startValues) { 
    this.values = startValues || {}; 
} 
Dictionary.prototype.store = function(name, value) { 
    this.values[name] = value; 
}; 
Dictionary.prototype.lookup = function(name) { 
    return this.values[name]; 
}; 

Dictionary.prototype.contains = function(name) { 
    return Object.prototype.propertyIsEnumerable.call(this.values, name); 
}; 
Dictionary.prototype.each = function(action) { 
    forEachIn(this.values, action); 
}; 

function Point(x, y) { 
    this.x = x; 
    this.y = y; 
} 
Point.prototype.add = function(other) { 
    return new Point(this.x + other.x, this.y + other.y); 
}; 

function Grid(width, height) { 
    this.width = width; 
    this.height = height; 
    this.cells = new Array(width * height); 
} 
Grid.prototype.valueAt = function(point) { 
    return this.cells[point.y * this.width + point.x]; 
}; 
Grid.prototype.setValueAt = function(point, value) { 
    this.cells[point.y * this.width + point.x] = value; 
}; 
Grid.prototype.isInside = function(point) { 
    return point.x >= 0 && point.y >= 0 && 
    point.x < this.width && point.y < this.height; 
}; 
Grid.prototype.moveValue = function(from, to) { 
    this.setValueAt(to, this.valueAt(from)); 
    this.setValueAt(from, undefined); 
}; 

Grid.prototype.each = function(action) { 
    for (var y = 0; y < this.height; y++) { 
     for (var x = 0; x < this.width; x++) { 
      var point = new Point(x, y); 
      action(point, this.valueAt(point)); 
     } 
    } 
}; 

var directions = new Dictionary(
{"n": new Point(0, -1), 
"ne": new Point(1, -1), 
"e": new Point(1, 0), 
"se": new Point(1, 1), 
"s": new Point(0, 1), 
"sw": new Point(-1, 1), 
"w": new Point(-1, 0), 
"nw": new Point(-1, -1)}); 

function StupidBug() {}; 
StupidBug.prototype.act = function(surroundings) { 
    return {type: "move", direction: "s"}; 
}; 

var wall = {}; 

function elementFromCharacter(character) { 
    if (character == " ") 
     return undefined; 
    else if (character == "#") 
     return wall; 
    else if (character == "o") 
     return new StupidBug(); 
} 

function Terrarium(plan) { 
    var grid = new Grid(plan[0].length, plan.length); 
    for (var y = 0; y < plan.length; y++) { 
     var line = plan[y]; 
     for (var x = 0; x < line.length; x++) { 
      grid.setValueAt(new Point(x, y), elementFromCharacter(line.charAt(x))); 
     } 
    } 
    this.grid = grid; 
} 

wall.character = "#"; 
StupidBug.prototype.character = "o"; 
function characterFromElement(element) { 
    if (element == undefined) 
     return " "; 
    else 
    return element.character; 
} 

Terrarium.prototype.toString = function() { 
    var characters = []; 
    var endOfLine = this.grid.width - 1; 
    this.grid.each(function(point, value) { 
     characters.push(characterFromElement(value)); 
     if (point.x == endOfLine) 
     characters.push("\n"); 
    }); 
    return characters.join(""); 
}; 

function bind(func, object) { 
    return function(){ 
     return func.apply(object, arguments); 
    }; 
} 

function method(object, name) { 
    return function() { 
     object[name].apply(object, arguments); 
    }; 
} 

Terrarium.prototype.listActingCreatures = function() { 
    var found = []; 
    this.grid.each(function(point, value) { 
     if (value != undefined && value.act) 
     found.push({object: value, point: point}); 
    }); 
    return found; 
}; 

Terrarium.prototype.listSurroundings = function(center) { 
    var result = {}; 
    var grid = this.grid; 
    directions.each(function(name, direction) { 
     var place = center.add(direction); 
     if (grid.isInside(place)) 
     result[name] = characterFromElement(grid.valueAt(place)); 
     else result[name] = "#"; 
    }); 
    return result; 
}; 

Terrarium.prototype.processCreature = function(creature, point) { 
    var action = creature.act(this.listSurroundings(point)); 
    if (action.type == "move" && directions.contains(action.direction)) { 
     var to = point.add(directions.lookup(action.direction)); 
     if (this.grid.isInside(to) && this.grid.valueAt(to) == undefined) 
      this.grid.moveValue(point, to); 
    } 
    else { 
     throw new Error("Unsupported action: " + action.type); 
    } 
}; 

Terrarium.prototype.step = function() { 
    forEach(this.listActingCreatures(), bind(this.processCreature, this)); 
}; 

var thePlan = 
["############################", 
"#  # #  o  ##", 
"#       #", 
"#   #####   #", 
"##   # # ##  #", 
"###   ##  #  #", 
"#   ###  #  #", 
"# ####     #", 
"# ##  o    #", 
"# o #   o  ### #", 
"# #      #", 
"############################"] 
var terrarium = new Terrarium(thePlan); 
terrarium.step(); 
alert(terrarium); 
+0

Благодаря gthacoder для редактирования – Dushyant

ответ

1

Я изменил ваш метод processCreature немного:

Terrarium.prototype.processCreature = function(creature) { 
    var action = creature.object.act(this.listSurroundings(creature.point)); 
    if (action.type == "move" && directions.contains(action.direction)) { 
    var to = creature.point.add(directions.lookup(action.direction)); 
    if (this.grid.isInside(to) && this.grid.valueAt(to) == undefined) 
     this.grid.moveValue(creature.point, to); 
    } 
    else { 
    throw new Error("Unsupported action: " + action.type); 
    } 
}; 

я выполнил, что в Firefox, и она работает. Я не уверен, работает ли он так, как предполагалось, но он что-то предупреждает.

+0

аргументы при условии, когда функция вызывается в: «Foreach (this.listActingCreatures(), связываются (this.processCreature, это));» 'this.listActingCreatures()' возвращает массив объектов, каждый из которых содержит значение существа и местоположение существа. Поэтому нет необходимости давать больше аргументов. – Dushyant

+0

Хорошая точка. Ты прав. Виноват. Я обновил ответ. Теперь это похоже на какой-то рабочий код. – gthacoder

+0

Да, это работает сейчас. Я не понимаю, почему вы написали: «creature.object.act» вместо «creature.act». Это заставляет код работать и не работает с «creature.act». Для меня код не работает, как предполагается, но ошибка лежит в другом месте, я думаю. Сейчас он дает некоторые результаты. – Dushyant

1

Полный исходный код здесь и его работа.

// forEachIn 
function forEachIn(object, action) { 
    for (var property in object) { 
    if (Object.prototype.hasOwnProperty.call(object, property)) 
     action(property, object[property]); 
    } 
} 

// Dictionary type 
function Dictionary(startValues) { 
    this.values = startValues || {}; 
} 
Dictionary.prototype.store = function(name, value) { 
    this.values[name] = value; 
}; 
Dictionary.prototype.lookup = function(name) { 
    return this.values[name]; 
}; 
Dictionary.prototype.contains = function(name) { 
    return Object.prototype.hasOwnProperty.call(this.values, name) && 
    Object.prototype.propertyIsEnumerable.call(this.values, name); 
}; 
Dictionary.prototype.each = function(action) { 
    forEachIn(this.values, action); 
}; 

// terrarium plan 
var thePlan = [ 
    "############################", 
    "#  # #  o  ##", 
    "#       #", 
    "#   #####   #", 
    "##   # # ##  #", 
    "###   ##  #  #", 
    "#   ###  #  #", 
    "# ####     #", 
    "# ##  o    #", 
    "# o #   o  ### #", 
    "# #      #", 
    "############################" 
]; 

// Point type 
function Point(x, y) { 
    this.x = x; 
    this.y = y; 
} 
Point.prototype.add = function(other) { 
    return new Point(this.x + other.x, this.y + other.y); 
}; 

// Grid type 
function Grid(width, height) { 
    this.width = width; 
    this.height = height; 
    this.cells = new Array(width * height); 
} 
Grid.prototype.valueAt = function(point) { 
    return this.cells[point.y * this.width + point.x]; 
}; 
Grid.prototype.setValueAt = function(point, value) { 
    this.cells[point.y * this.width + point.x] = value; 
}; 
Grid.prototype.isInside = function(point) { 
    return point.x >= 0 && point.y >= 0 && 
     point.x < this.width && point.y < this.height; 
}; 
Grid.prototype.moveValue = function(from, to) { 
    this.setValueAt(to, this.valueAt(from)); 
    this.setValueAt(from, undefined); 
}; 

Grid.prototype.each = function(action) { 
    for (var y = 0; y < this.height; y++) { 
    for (var x = 0; x < this.width; x++) { 
     var point = new Point(x, y); 
     action(point, this.valueAt(point)); 
    } 
    } 
}; 

// directions object 
var directions = new Dictionary(
    {"n": new Point(0, -1), 
    "ne": new Point(1, -1), 
    "e": new Point(1, 0), 
    "se": new Point(1, 1), 
    "s": new Point(0, 1), 
    "sw": new Point(-1, 1), 
    "w": new Point(-1, 0), 
    "nw": new Point(-1, -1)}); 

// StupidBug 
function StupidBug() {} 
StupidBug.prototype.act = function(surroundings) { 
    return {type: "move", direction: "s"}; 
}; 

// Terrarium 
var wall = {}; 

function elementFromCharacter(character) { 
    if (character == " ") 
    return undefined; 
    else if (character == "#") 
    return wall; 
    else if (character == "o") 
    return new StupidBug(); 
} 

function Terrarium(plan) { 
    var grid = new Grid(plan[0].length, plan.length); 
    for (var y = 0; y < plan.length; y++) { 
    var line = plan[y]; 
    for (var x = 0; x < line.length; x++) { 
     grid.setValueAt(new Point(x, y), elementFromCharacter(line.charAt(x))); 
    } 
    } 
    this.grid = grid; 
} 

// characterFromElement 
wall.character = "#"; 
StupidBug.prototype.character = "o"; 

function characterFromElement(element) { 
    if (element === undefined) 
    return " "; 
    else 
    return element.character; 
} 

// Terrarium.prototype.toString 
Terrarium.prototype.toString = function() { 
    var characters = []; 
    var endOfLine = this.grid.width - 1; 
    this.grid.each(function(point, value) { 
    characters.push(characterFromElement(value)); 
    if (point.x == endOfLine) 
     characters.push("\n"); 
    }); 
    return characters.join(""); 
}; 

// bind and method 
function bind(func, object) { 
    return function(){ 
    return func.apply(object, arguments); 
    }; 
} 

function method(object, name) { 
    return function() { 
    object[name].apply(object, arguments); 
    }; 
} 

// Terrarium.prototype.step 
Terrarium.prototype.listActingCreatures = function() { 
    var found = []; 
    this.grid.each(function(point, value) { 
    if (value !== undefined && value.act) 
     found.push({object: value, point: point}); 
    }); 
    return found; 
}; 

Terrarium.prototype.listSurroundings = function(center) { 
    var result = {}; 
    var grid = this.grid; 
    directions.each(function(name, direction) { 
    var place = center.add(direction); 
    if (grid.isInside(place)) 
     result[name] = characterFromElement(grid.valueAt(place)); 
    else 
     result[name] = "#"; 
    }); 
    return result; 
}; 

Terrarium.prototype.processCreature = function(creature) { 
    var action = creature.object.act(this.listSurroundings(creature.point)); 

    if (action.type == "move" && directions.contains(action.direction)) { 
    var to = creature.point.add(directions.lookup(action.direction)); 
    if (this.grid.isInside(to) && this.grid.valueAt(to) === undefined) 
     this.grid.moveValue(creature.point, to); 
    } 
    else { 
    throw new Error("Unsupported action: " + action.type); 
    } 
}; 

Terrarium.prototype.step = function() { 
    forEach(this.listActingCreatures(), bind(this.processCreature, this)); 
}; 

function forEach(array,action) { 
    for(var i=0;i<array.length;i++) 
    {action(array[i]);} 
} 

// Run demo - Check in console 
var terrarium = new Terrarium(thePlan); 
console.log(terrarium.toString()); 
terrarium.step(); 
console.log(terrarium.toString()); 

Проверить демо здесь, в результате консоли: https://jsfiddle.net/huyb1991/baoe8qj6/