Move rule and AI engine to separate files.
"use strict";
var board = {};
board.create = function() {
var brd = [];
for (var i = 0; i < 4; i++) {
brd[i] = [];
for (var j = 0; j < 4; j++) {
brd[i][j] = 0;
}
}
return brd;
}
board.copy = function(from, to) {
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
to[i][j] = from[i][j];
}
}
}
board.freeCnt = function(brd) {
var cnt = 0;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (brd[i][j] === 0)
cnt++;
}
}
return cnt;
}
board.gameOver = function(brd) {
if (board.freeCnt(brd) > 0)
return false;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 3; j++) {
if (brd[i][j] === brd[i][j+1])
return false;
}
}
for (var j = 0; j < 4; j++) {
for (var i = 0; i < 3; i++) {
if (brd[i][j] === brd[i+1][j])
return false;
}
}
return true;
}
board.putRandom = function(brd) {
var cnt = board.freeCnt(brd);
cnt = Math.floor(Math.random() * cnt)+1;
for (var i = 0; i < 4 && cnt > 0; i++) {
for (var j = 0; j < 4 && cnt > 0; j++) {
if (brd[i][j] !== 0)
continue;
if (cnt === 1)
brd[i][j] = (Math.random() > .9) ? 2 : 1;
cnt--;
}
}
}
/* http://www.reddit.com/r/2048/comments/214njx/highest_possible_score_for_2048_warning_math */
var boardScoreTbl = [0];
for (var i = 1, exp = 2; i < 16; i++, exp *= 2) {
boardScoreTbl[i] = (i-1)*exp;
}
board.score = function(brd) {
var score = 0;
var max = 0;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var val = brd[i][j];
score += boardScoreTbl[val];
if (max < val)
max = val;
}
}
return {score: score, max: Math.pow(2, max)};
}
board.row = {};
board.row.init = function() {
return {stack: [], curr: 0};
}
board.row.push = function(state, val) {
if (val === 0)
return;
if (state.curr === 0) {
state.curr = val;
return;
}
if (state.curr === val) {
state.stack.push(state.curr+1);
state.curr = 0;
} else {
state.stack.push(state.curr);
state.curr = val;
}
}
board.row.finish = function(state) {
if (state.curr !== 0)
state.stack.push(state.curr);
}
board.move = {};
board.move.up = function(brd) {
var updated = false;
for (var j = 0; j < 4; j++) {
var state = board.row.init();
for (var i = 0; i < 4; i++) {
board.row.push(state, brd[i][j]);
}
board.row.finish(state);
for (var i = 0; i < state.stack.length; i++) {
if (brd[i][j] !== state.stack[i])
updated = true;
brd[i][j] = state.stack[i];
}
for (; i < 4; i++) {
if (brd[i][j] !== 0)
updated = true;
brd[i][j] = 0;
}
}
return updated;
};
board.move.down = function(brd) {
var updated = false;
for (var j = 0; j < 4; j++) {
var state = board.row.init();
for (var i = 3; i >= 0; i--) {
board.row.push(state, brd[i][j]);
}
board.row.finish(state);
for (var i = 0; i < state.stack.length; i++) {
if (brd[3-i][j] !== state.stack[i])
updated = true;
brd[3-i][j] = state.stack[i];
}
for (; i < 4; i++) {
if (brd[3-i][j] !== 0)
updated = true;
brd[3-i][j] = 0;
}
}
return updated;
};
board.move.left = function(brd) {
var updated = false;
for (var i = 0; i < 4; i++) {
var state = board.row.init();
for (var j = 0; j < 4; j++) {
board.row.push(state, brd[i][j]);
}
board.row.finish(state);
for (var j = 0; j < state.stack.length; j++) {
if (brd[i][j] !== state.stack[j])
updated = true;
brd[i][j] = state.stack[j];
}
for (; j < 4; j++) {
if (brd[i][j] !== 0)
updated = true;
brd[i][j] = 0;
}
}
return updated;
};
board.move.right = function(brd) {
var updated = false;
for (var i = 0; i < 4; i++) {
var state = board.row.init();
for (var j = 3; j >= 0; j--) {
board.row.push(state, brd[i][j]);
}
board.row.finish(state);
for (var j = 0; j < state.stack.length; j++) {
if (brd[i][3-j] !== state.stack[j])
updated = true;
brd[i][3-j] = state.stack[j];
}
for (; j < 4; j++) {
if (brd[i][3-j] !== 0)
updated = true;
brd[i][3-j] = 0;
}
}
return updated;
};