Building a Board Game with Node
Juan Lasheras @jlas_
February 12, 2013
Juan Lasheras @jlas_
February 12, 2013
Similar to Scrabble. Played with 2-6 players. Goal is to form lines (rows & columns) of blocks such that:
Scoring:
Demo
How can we represent a board-less game in software?
This way, we can represent the board with a simple 2D array!
this.boardmat = []; // matrix representation
for (var i=0; i<181; i++) {
this.boardmat[i] = new Array(181);
}
Prevent illegal moves and tell the player why.
// return: integer of points if Success, otherwise return an error string
function addGamePiece(game, gamepiece) {
var row = gamepiece.row;
var col = gamepiece.column;
var points = 0;
if (game.boardmat[row][col] !== undefined) {
return "GamePiece already exists.";
}
...
function addGamePiece(game, gamepiece) {
...
/**
* Helper function, to check whether it is valid to place a piece
* param piece: the piece object being placed
* param getAdjacent: a function that returns an adjacent GamePiece
* return: false if valid placement, otherwise return the offending
* GamePiece
*/
function _adjacentPieces(piece, getAdjacent) {
for (var i=1; i<=6; i++) {
adjacent = getAdjacent(i);
if (typeof adjacent === 'undefined') {
return false;
} else if (i === 6) {
// can't have more than 6 pieces in a valid line
return adjacent;
}
var samecolor = (adjacent.piece.color === piece.color);
var sameshape = (adjacent.piece.shape === piece.shape);
// either samecolor or sameshape, not both
if ((samecolor || sameshape) && !(samecolor && sameshape)) {
// add 1 pt for adjacent piece, if not been played this turn
if (!game.turn_pieces.some(function(x) {
return x.equals(adjacent);})) {
points += 1;
}
continue;
}
return adjacent;
}
return false;
}
// check if adjacent pieces are compatible
var checkLeft = _adjacentPieces(gamepiece.piece, function(offset) {
var _row = row-offset;
var piece = game.boardmat[_row][col];
return piece && new GamePiece(piece, _row, col);
});
var checkRight =_adjacentPieces(gamepiece.piece, function(offset) {
var _row = row+offset;
var piece = game.boardmat[_row][col];
return piece && new GamePiece(piece, _row, col);
});
var checkUp =_adjacentPieces(gamepiece.piece, function(offset) {
var _col = col-offset;
var piece = game.boardmat[row][_col];
return piece && new GamePiece(piece, row, _col);
});
var checkDown =_adjacentPieces(gamepiece.piece, function(offset) {
var _col = col+offset;
var piece = game.boardmat[row][_col];
return piece && new GamePiece(piece, row, _col);
});
var badPiece = (checkLeft || checkRight || checkUp || checkDown);
if (badPiece !== false) {
return ("GamePiece adjacent to incompatible piece: " +
badPiece.piece.color + " " + badPiece.piece.shape);
}
....
function addGamePiece(game, gamepiece) {
...
function sameRowOrCol(otherpiece) {
return (otherpiece.row === row || otherpiece.column === col);
}
if (game.turn_pieces) {
if (!game.turn_pieces.every(sameRowOrCol)) {
return ("GamePiece must be in same row or column as " +
"others placed this turn.");
}
}
...
Third Party
Quirky server implements a ReSTful* interface.
*maybe
server.on('request', function(request, response) {
var u = url.parse(request.url);
var path = u.pathname.split('/').map(function(x) {
return decodeURIComponent(x);
}).filter(function(x) {
return Boolean(x);
});
switch(path[0]) {
case 'games':
handleGames(request, response, path.slice(1));
break;
case 'chat':
handleChat(request, response, chat);
break;
default:
var f = static_files[path[0]];
if (f !== undefined) {
var type = 'text/html';
if (path[0].search('css$') >= 0) {
type = 'text/css';
} else if (path[0].search('js$') >= 0) {
type = 'text/javascript';
}
respOk(response, f, type);
} else {
respOk(response, static_files['index.html'], 'text/html');
}
break;
}
});
How do we deal with growing board area?
Shrink pieces with CSS
function getBoard() {
...
$(GRIDCLS).css("width", (100/cols)+"%");
$(GRIDCLS).css("height", (100/rows)+"%");
...
}
How do we draw the piece icons?
Static images are annoying. Use unicode! ● ✦ ◆ ■ ▲ ♣
<span style="color:#A0E7A0">&9679;</span>
<span style="color:#FFFB8C">&10022;</span>
<span style="color:#CD2626">&9670;</span>
<span style="color:#FFAF5A">&9632;</span>
<span style="color:#FF8CB6">&9650;</span>
<span style="color:#97D0F9">&9827;</span>
{
id: (int),
name: (string),
input: (string)
}
Disallow everything but ASCII?
Overkill because server code is insensitive to weird characters.
function esc(str) {
return $('<div/>').text(str).html();
}
$ heroku create $ git push heroku master
$ npm publish <folder>
npm config allows you to specify runtime configuration for your app
var port = (process.env.PORT || process.env.npm_package_config_port || 8010); server.listen(port);
Specify a special port with npm and run the app:
$ npm config set quirky:port <port> $ npm start quirky
Send pull requests!
http://www.github.com/jlas/quirky
http://www.juanl.org/talks/quirky/index.html
Sponsors