Skip to content

Instantly share code, notes, and snippets.

@1fabunicorn
Last active November 16, 2017 15:57
Show Gist options
  • Save 1fabunicorn/0fd7f7a99b8eb271c158753fd1afc293 to your computer and use it in GitHub Desktop.
Save 1fabunicorn/0fd7f7a99b8eb271c158753fd1afc293 to your computer and use it in GitHub Desktop.
from Eloquent Javascript!
// 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 "&nbsp;&nbsp;";
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("<br>");
});
console.log(characters);
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);
for(var i = 0; i < 6; i++){
document.write(terrarium.toString());
terrarium.step();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment