Skip to content

Instantly share code, notes, and snippets.

@apsillers
Created July 12, 2014 06:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apsillers/eacf6101cc829e36138b to your computer and use it in GitHub Desktop.
Save apsillers/eacf6101cc829e36138b to your computer and use it in GitHub Desktop.
JavaScript BftPD sample cell
/*
Sample code for a "Battle for the Petri Dish" cell
Released under the terms of the WTF Public License,
No warranty express or implied is granted, etc, etc.
I just hacked this together very quickly; improvements are welcome, so please fork the Gist if you like.
*/
// used in defining cell spec
var MAX_HP = 2;
var MAX_ENERGY = 10;
var ACIDITY = 0;
/*
The decide function takes an Arena object (see below for prototype methods), a cell object,
and an outputCallback, which accepts a command string to output
*/
function decide(arena, cell, outputCallback) {
var nearbyEmpties = arena.getAdjacentMatches(cell.point, [".", "c"]);
var nearbyEnemies = arena.getAdjacentMatches(cell.point, ["x"]);
var nearbyCorpses = arena.getAdjacentMatches(cell.point, ["c"]);
// if you have the energy and space to divide, do it
if(cell.energy >= 5 && nearbyEmpties.length > 0) {
outputCallback("DIVIDE " + arena.getDirection(cell, nearbyEmpties[(nearbyEmpties.length*Math.random())|0]));
return;
}
// if you have two or more nearby enemies, explode if possible
if(nearbyEnemies.length > 1 && cell.energy >= cell.hp && cell.hp <= 3) {
outputCallback("EXPLODE");
return;
}
// if at least one adjacent enemy, attack if possible
if(cell.energy > 0 && nearbyEnemies.length > 0) {
outputCallback("ATTACK " + arena.getDirection(cell, nearbyEnemies[(nearbyEnemies.length*Math.random())|0]) + " " + Math.min(cell.energy, 3));
return;
}
// if there's a nearby corpse, eat it if your energy is below max
if(nearbyCorpses.length > 0) {
outputCallback("EAT " + arena.getDirection(cell, nearbyCorpses[(nearbyCorpses.length*Math.random())|0]));
return;
}
for(var i=0; i<nearbyEmpties.length; ++i) {
var space = nearbyEmpties[i];
if(arena.getAdjacentMatches(space, ["x"]).length) {
outputCallback("MOVE " + arena.getDirection(cell,space));
return;
}
}
outputCallback("REST");
return;
}
var input = "";
// quiet stdin EPIPE errors
process.stdin.on("error", function(err) {
//console.log("slight error: " + err);
});
process.stdin.on("data", function(data) {
input += data;
});
process.stdin.on("end", function() {
if(input == "BEGIN") {
// output space-separated attributes
process.stdout.write([MAX_HP, MAX_ENERGY, ACIDITY].join(" "));
} else {
// read in arena and decide on an action
var arena = new Arena();
var lines = input.split("\n");
var dimensions = lines[0].split(" ").map(function(d) { return parseInt(d); });
arena.width = dimensions[0];
arena.height = dimensions[1];
for(var y=1; y<=dimensions[1]; ++y) {
for(var x=0; x<lines[y].length; ++x) {
arena.set(x, y-1, lines[y][x]);
}
}
var stats = lines[dimensions[1]+2].split(" ");
var cell = { x: stats[0], y: stats[1], hp: stats[2], energy: stats[3], point: arena.get(stats[0], stats[1]) };
// decide on an action and write the action to stdout
decide(arena, cell, function(output) { process.stdout.write(output); })
}
});
var Arena = function() {
this.dict = {};
};
Arena.prototype = {
// get Point object
get: function(x,y) {
return this.dict[x+","+y];
},
// store Point object
set: function(x,y,d) {
this.dict[x+","+y] = new Point(x,y,d);
},
// get an array of all Points adjacent to this one whose symbol is contained in matchList
// if matchList is omitted, return all Points
getAdjacentMatches: function(point, matchList) {
var result = [];
for(var i=-1; i<=1; ++i) {
for(var j=-1; j<=1; ++j) {
var inspectedPoint = this.get(point.x+i, point.y+j);
if(inspectedPoint &&
(i!=0 || j!=0) &&
(!matchList || matchList.indexOf(inspectedPoint.symbol) != -1)) {
result.push(inspectedPoint);
}
}
}
return result;
},
// return the direction from point1 to point2
getDirection: function(point1, point2) {
var dx = point2.x - point1.x;
var dy = point2.y - point1.y;
dx = Math.abs(dx) / (dx || 1);
dy = Math.abs(dy) / (dy || 1);
c2d = { "0,0":"-",
"0,-1":"N", "0,1":"S", "1,0":"E", "-1,0":"W",
"-1,-1":"NW", "1,-1":"NE", "1,1":"SE", "-1,1":"SW" };
return c2d[dx + "," + dy];
}
}
var Point = function(x,y,d) {
this.x = x;
this.y = y;
this.symbol = d;
}
Point.prototype.toString = function() {
return "(" + this.x + ", " + this.y + ")";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment