Skip to content

Instantly share code, notes, and snippets.

@loonkwil
Created February 3, 2014 08:41
Show Gist options
  • Save loonkwil/8780610 to your computer and use it in GitHub Desktop.
Save loonkwil/8780610 to your computer and use it in GitHub Desktop.
"use strict";
var Stream = require("stream"),
util = require("util");
function ConnectFour() {
Stream.Transform.apply(this, arguments);
};
util.inherits(ConnectFour, Stream.Transform);
ConnectFour.prototype._transform = function _transform(chunk, encoding, callback) {
var that = this;
// Helpers
/**
* @param {string} str
* @return {string}
*/
var addLeadingZeros = function(str) {
return (Math.pow(2, 48) + parseInt(str, 2)).toString(2).slice(1);
};
/**
* @param {string} str
* @return {boolean}
*/
var isEmpty = function(str) {
return !Boolean(+str);
};
/**
* @param {string} str
* @param {function} fn
* @return {string}
*/
var doWithEveryChar = function(str, fn) {
return str.split('').map(fn).join('');
};
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var bitwiseAnd = function(a, b) {
return doWithEveryChar(a, function(value, index) {
return value & b[index];
});
};
/**
* @param {string} a
* @param {string} b
* @return {string}
*/
var bitwiseOr = function(a, b) {
return doWithEveryChar(a, function(value, index) {
return value | b[index];
});
};
/**
* @param {string} str
* @param {number} num
* @return {string}
*/
var rightShift = function(str, num) {
return addLeadingZeros(str.slice(0, -1 * num));
};
/**
* @param {string} board
* @return {boolean}
*/
var hasWon = function(board) {
var d1, d2, h, v;
d1 = bitwiseAnd(board, rightShift(board, 6)); // diagonal \
d2 = bitwiseAnd(board, rightShift(board, 8)); // diagonal /
h = bitwiseAnd(board, rightShift(board, 7)); // horizontal -
v = bitwiseAnd(board, rightShift(board, 1)); // vertical |
return (
!isEmpty(bitwiseAnd(d1, rightShift(d1, 2 * 6))) ||
!isEmpty(bitwiseAnd(d2, rightShift(d2, 2 * 8))) ||
!isEmpty(bitwiseAnd(h, rightShift(h, 2 * 7))) ||
!isEmpty(bitwiseAnd(v, rightShift(v, 2)))
);
};
// Remove the unnecessarily characters
chunk = chunk.toString().replace(/\D/g, '');
// Validate the move
if( !chunk ) { return callback(new Error()); }
// Concatenate the current chunk with the previous ones
that.prevData = that.prevData || '';
that.prevData += chunk;
// More about the bitboards: http://en.wikipedia.org/wiki/Bitboard
var emptyBoard = addLeadingZeros(0);
var bitboards = [ emptyBoard, emptyBoard ];
doWithEveryChar(that.prevData, function(oneStep, index) {
var boardIndex = index % 2;
var firstCellInTheRow = (oneStep - 1) * 7;
// Find out the index of the first empty cell
var allMoves = bitwiseOr(bitboards[0], bitboards[1]);
var firstEmptyCell = allMoves.indexOf('0', firstCellInTheRow);
// Mark the cell
var myBoard = bitboards[boardIndex];
myBoard = myBoard.slice(0, firstEmptyCell) +
1 + myBoard.slice(firstEmptyCell + 1);
// Has won?
if( hasWon(myBoard) ) {
that.push(boardIndex ? 'b' : 'a');
bitboards = [ emptyBoard, emptyBoard ];
}
bitboards[boardIndex] = myBoard;
});
callback();
};
module.exports = ConnectFour;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment