Release CHANGES.
"use strict";
/** @fileOverview Board engines with optimised primitives. */
////////////////////////////////////////////////////////////////
/** Create board on linear array.
* Extract data from 'brd' if present.
* @param brd 2d array
* @constructor */
////////////////////////////////////////////////////////////////
function BoardArr(brd) {
this.brd = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
if (brd) {
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
this.brd[4*i + j] = brd[i][j];
}
}
/** Get [i][j] element. */
BoardArr.prototype.get = function(i, j) {
return this.brd[4*i + j];
}
/** Set [i][j] element. */
BoardArr.prototype.set = function(i, j, val) {
this.brd[4*i + j] = val;
}
/** Compare boards. */
BoardArr.prototype.equals = function(brd) {
var from = this.brd, to = brd.brd;
// More often corners differ, check it first.
return from[0] === to[0] && from[3] === to[3] && from[12] === to[12] && from[15] === to[15]
&& from[1] === to[1] && from[2] === to[2]
&& from[4] === to[4] && from[5] === to[5] && from[6] === to[6] && from[7] === to[7]
&& from[8] === to[8] && from[9] === to[9] && from[10] === to[10] && from[11] === to[11]
&& from[13] === to[13] && from[14] === to[14];
}
/* Return and optionally fill 2d board.
* Doesn't designed to be efficient. */
BoardArr.prototype.exportTo = function(brd) {
brd = brd || [[],[],[],[]];
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
brd[i][j] = this.brd[4*i + j];
return brd;
}
BoardArr.prototype.copy = function(brd) {
brd = brd || new BoardArr();
for (var i = 0; i < 16; i++)
brd.brd[i] = this.brd[i];
return brd;
}
/** Number of free cell. */
BoardArr.prototype.free = function() {
var cnt = 0;
for (var i = 0; i < 16; i++)
if (this.brd[i] === 0)
cnt++;
return cnt;
}
BoardArr.prototype.score = function() {
var score = 0;
for (var i = 0; i < 16; i++) {
var v = this.brd[i][j];
if (v > 1)
score += (v-1)*(1 << v);
}
return score;
}
BoardArr.prototype.max = function() {
var max = 0;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
max = Math.max(max, this.brd[i][j]);
}
}
return max;
}
////////////////////////////////////////////////////////////////
/** Create board on 2d array.
* Extract data from 'brd' if present.
* @param brd 2d array
* @constructor */
////////////////////////////////////////////////////////////////
function BoardArr2d(brd) {
this.brd = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
if (brd) {
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
this.brd[i][j] = brd[i][j];
}
}
/** Get [i][j] element. */
BoardArr2d.prototype.get = function(i, j) {
return this.brd[i][j];
}
/** Set [i][j] element. */
BoardArr2d.prototype.set = function(i, j, val) {
this.brd[i][j] = val;
}
BoardArr2d.prototype.equals_loop = function(brd) {
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
if (this.brd[i][j] !== brd.brd[i][j])
return false;
return true;
}
BoardArr2d.prototype.equals_unrolled = function(brd) {
var x0 = this.brd[0], x1 = this.brd[1], x2 = this.brd[2], x3 = this.brd[3]
var y0 = brd.brd[0], y1 = brd.brd[1], y2 = brd.brd[2], y3 = brd.brd[3];
// More often corners differ, check it first.
return x0[0] === y0[0] && x0[3] === y0[3] && x3[0] === y3[0] && x3[3] === y3[3]
&& x0[1] === y0[1] && x0[2] === y0[2]
&& x3[1] === y3[1] && x3[2] === y3[2]
&& x1[0] === y1[0] && x1[1] === y1[1] && x1[2] === y1[2] && x1[3] === y1[3]
&& x2[0] === y2[0] && x2[1] === y2[1] && x2[2] === y2[2] && x2[3] === y2[3];
}
/** Compare boards. */
BoardArr2d.prototype.equals = BoardArr2d.prototype.equals_unrolled;
BoardArr2d.prototype.compress = function() {
var brd = this.brd;
var h1 = brd[0][0];
h1 = (h1 << 4) | brd[0][1];
h1 = (h1 << 4) | brd[0][2];
h1 = (h1 << 4) | brd[0][3];
h1 = (h1 << 4) | brd[1][0];
h1 = (h1 << 4) | brd[1][1];
h1 = (h1 << 4) | brd[1][2];
h1 = (h1 << 4) | brd[1][3];
var h2 = brd[2][0];
h2 = (h2 << 4) | brd[2][1];
h2 = (h2 << 4) | brd[2][2];
h2 = (h2 << 4) | brd[2][3];
h2 = (h2 << 4) | brd[3][0];
h2 = (h2 << 4) | brd[3][1];
h2 = (h2 << 4) | brd[3][2];
h2 = (h2 << 4) | brd[3][3];
return [h1, h2];
}
/* Return and optionally fill 2d board. */
BoardArr2d.prototype.exportTo = function(brd) {
brd = brd || [[],[],[],[]];
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
brd[i][j] = this.brd[i][j];
return brd;
}
BoardArr2d.prototype.copy = function(brd) {
brd = brd || new BoardArr2d();
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
brd.brd[i][j] = this.brd[i][j];
return brd;
}
/** Number of free cell. */
BoardArr2d.prototype.free = function() {
var cnt = 0;
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
if (this.brd[i][j] === 0)
cnt++;
return cnt;
}
BoardArr2d.prototype.score = function() {
var score = 0;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var v = this.brd[i][j];
if (v > 1)
score += (v-1)*(1 << v);
}
}
return score;
}
BoardArr2d.prototype.max = function() {
var max = 0;
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
max = Math.max(max, this.brd[i][j]);
}
}
return max;
}
BoardArr2d.prototype.find = function(val) {
var xy = [];
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
if (this.brd[i][j] === val)
xy.push([i,j]);
}
}
return xy;
}
BoardArr2d.prototype.atEdge = function(val) {
var brd = this.brd;
return (brd[0][0] === val) || (brd[0][1] === val) || (brd[0][2] === val) || (brd[0][3] === val)
|| (brd[1][0] === val) || (brd[1][3] === val)
|| (brd[2][0] === val) || (brd[2][3] === val)
|| (brd[3][0] === val) || (brd[3][1] === val) || (brd[3][2] === val) || (brd[3][3] === val);
}
BoardArr2d.prototype.atCorner = function(val) {
var brd = this.brd;
return (brd[0][0] === val) || (brd[0][3] === val) || (brd[3][0] === val) || (brd[3][3] === val);
}
BoardArr2d.prototype.canRight = function() {
for (var i = 0; i < 4; i++) {
var f0 = this.brd[i][0], f1 = this.brd[i][1], f2 = this.brd[i][2], f3 = this.brd[i][3];
if (f2 > 0 && (f2 === f3 || f3 === 0))
return true;
if (f1 > 0 && (f1 === f2 || f2 === 0))
return true;
if (f0 > 0 && (f0 === f1 || f1 === 0))
return true;
}
return false;
}
BoardArr2d.prototype.canLeft = function() {
for (var i = 0; i < 4; i++) {
var f0 = this.brd[i][0], f1 = this.brd[i][1], f2 = this.brd[i][2], f3 = this.brd[i][3];
if (f1 > 0 && (f1 === f0 || f0 === 0))
return true;
if (f2 > 0 && (f2 === f1 || f1 === 0))
return true;
if (f3 > 0 && (f3 === f2 || f2 === 0))
return true;
}
return false;
}
BoardArr2d.prototype.canUp = function() {
for (var j = 0; j < 4; j++) {
var f0 = this.brd[0][j], f1 = this.brd[1][j], f2 = this.brd[2][j], f3 = this.brd[3][j];
if (f1 > 0 && (f1 === f0 || f0 === 0))
return true;
if (f2 > 0 && (f2 === f1 || f1 === 0))
return true;
if (f3 > 0 && (f3 === f2 || f2 === 0))
return true;
}
return false;
}
BoardArr2d.prototype.canDown = function() {
for (var j = 0; j < 4; j++) {
var f0 = this.brd[0][j], f1 = this.brd[1][j], f2 = this.brd[2][j], f3 = this.brd[3][j];
if (f2 > 0 && (f2 === f3 || f3 === 0))
return true;
if (f1 > 0 && (f1 === f2 || f2 === 0))
return true;
if (f0 > 0 && (f0 === f1 || f1 === 0))
return true;
}
return false;
}
BoardArr2d.prototype.shiftLeft_unrolled = function(brd) {
var from = this.brd, to = brd.brd;
for (var i = 3; i >= 0; i--) {
var f0 = from[i][0], f1 = from[i][1], f2 = from[i][2], f3 = from[i][3];
if (f3 === 0) {
to[i][0] = 0;
if (f2 === 0) {
to[i][1] = 0;
if (f1 === 0) { // a 0 0 0
to[i][2] = 0;
to[i][3] = f0;
} else {
if (f0 === f1) { // a a 0 0
to[i][2] = 0;
to[i][3] = f0 + 1;
} else { // a b 0 0
to[i][2] = f0;
to[i][3] = f1;
}
}
} else { // f2 !== 0
if (f1 === 0) {
to[i][1] = 0;
if (f0 === f2) { // a 0 a 0
to[i][3] = f2 + 1;
to[i][2] = 0;
} else { // a 0 b 0
to[i][3] = f2;
to[i][2] = f0;
}
} else { // f1 !== 0
if (f1 === f2) { // a b b 0
to[i][3] = f2 + 1;
to[i][2] = f0;
to[i][1] = 0;
} else { // f1 !== f2
to[i][3] = f2;
if (f0 === f1) { // a a b 0
to[i][2] = f1 + 1;
to[i][1] = 0;
} else { // a b c 0
to[i][2] = f1;
to[i][1] = f0;
}
}
}
}
} else { // f3 !== 0
if (f2 === f3) {
to[i][3] = f2 + 1;
to[i][0] = 0;
if (f1 === 0) { // a 0 b b
to[i][2] = f0;
to[i][1] = 0;
} else {
if (f0 === f1) { // a a b b
to[i][2] = f1 + 1;
to[i][1] = 0;
} else { // a b c c
to[i][2] = f1;
to[i][1] = f0;
}
}
} else { // f2 !== f3
to[i][3] = f3;
if (f2 === 0) {
to[i][0] = 0;
if (f1 === 0) { // a 0 0 b
to[i][1] = 0;
to[i][2] = f0;
} else {
if (f0 === f1) { // a a 0 b
to[i][1] = 0;
to[i][2] = f1 + 1;
} else { // a b 0 c
to[i][1] = f0;
to[i][2] = f1;
}
}
} else { // f2 !== 0 && f2 !== f3
if (f1 === 0) { // a 0 b c
to[i][0] = 0;
to[i][1] = f0;
to[i][2] = f2;
} else {
if (f0 === f1) { // a a b c
to[i][0] = 0;
to[i][1] = f1 + 1;
to[i][2] = f2;
} else { // a b c d
to[i][0] = f0;
to[i][1] = f1;
to[i][2] = f2;
}
}
}
}
}
}
}
BoardArr2d.prototype.shiftRight_mostly_unrolled = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
for (var i = 0; i < 4; i++) {
var moved = true;
var f0 = from[i][0], f1 = from[i][1], f2 = from[i][2], f3 = from[i][3];
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to[i][0] = 0;
to[i][1] = 0;
to[i][2] = 0;
to[i][3] = f3;
continue;
}
if (f1 === 0) {
to[i][0] = 0;
to[i][1] = 0;
if (f2 === f3) {
updated = true;
to[i][2] = 0;
to[i][3] = f3 + 1;
} else {
to[i][2] = f2;
to[i][3] = f3;
}
continue;
}
if (f2 === f3) {
updated = true;
to[i][0] = 0;
to[i][3] = f3 + 1;
if (f0 === f1) {
to[i][1] = 0;
to[i][2] = f1 + 1;
} else {
to[i][1] = f0;
to[i][2] = f1;
}
} else {
to[i][3] = f3;
if (f1 === f2) {
updated = true;
to[i][0] = 0;
to[i][1] = f0;
to[i][2] = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to[i][0] = 0;
to[i][1] = f1+1;
to[i][2] = f2;
} else {
to[i][0] = f0;
to[i][1] = f1;
to[i][2] = f2;
}
}
}
}
return updated;
}
BoardArr2d.prototype.shiftDown_mostly_unrolled = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
for (var j = 0; j < 4; j++) {
var moved = true;
var f0 = from[0][j], f1 = from[1][j], f2 = from[2][j], f3 = from[3][j];
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to[0][j] = 0;
to[1][j] = 0;
to[2][j] = 0;
to[3][j] = f3;
continue;
}
if (f1 === 0) {
to[0][j] = 0;
to[1][j] = 0;
if (f2 === f3) {
to[2][j] = 0;
to[3][j] = f3 + 1;
updated = true;
} else {
to[2][j] = f2;
to[3][j] = f3;
}
continue;
}
if (f2 === f3) {
updated = true;
to[0][j] = 0;
to[3][j] = f3 + 1;
if (f0 === f1) {
to[1][j] = 0;
to[2][j] = f1 + 1;
} else {
to[1][j] = f0;
to[2][j] = f1;
}
} else {
to[3][j] = f3;
if (f1 === f2) {
updated = true;
to[0][j] = 0;
to[1][j] = f0;
to[2][j] = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to[0][j] = 0;
to[1][j] = f1+1;
to[2][j] = f2;
} else {
to[0][j] = f0;
to[1][j] = f1;
to[2][j] = f2;
}
}
}
}
return updated;
}
BoardArr2d.prototype.shiftLeft_mostly_unrolled = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
for (var i = 0; i < 4; i++) {
var moved = true;
var f0 = from[i][0], f1 = from[i][1], f2 = from[i][2], f3 = from[i][3];
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to[i][3] = 0;
to[i][2] = 0;
to[i][1] = 0;
to[i][0] = f0;
continue;
}
if (f2 === 0) {
to[i][3] = 0;
to[i][2] = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to[i][1] = 0;
to[i][0] = f0 + 1;
} else { // a b 0 0
to[i][1] = f1;
to[i][0] = f0;
}
continue;
}
if (f1 === f0) {
updated = true;
to[i][3] = 0;
to[i][0] = f0 + 1;
if (f3 === f2) { // a a b b
to[i][2] = 0;
to[i][1] = f2 + 1;
} else { // a a b c
to[i][2] = f3;
to[i][1] = f2;
}
} else {
to[i][0] = f0;
if (f2 === f1) { // a b b c
updated = true;
to[i][3] = 0;
to[i][2] = f3;
to[i][1] = f1 + 1;
} else {
to[i][1] = f1;
if (f2 === f3) { // a b c c
updated = true;
to[i][3] = 0;
to[i][2] = f2+1;
} else { // a b c d
to[i][3] = f3;
to[i][2] = f2;
}
}
}
}
return updated;
}
BoardArr2d.prototype.shiftUp_mostly_unrolled = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
for (var j = 0; j < 4; j++) {
var moved = true;
var f0 = from[0][j], f1 = from[1][j], f2 = from[2][j], f3 = from[3][j];
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to[3][j] = 0;
to[2][j] = 0;
to[1][j] = 0;
to[0][j] = f0;
continue;
}
if (f2 === 0) {
to[3][j] = 0;
to[2][j] = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to[1][j] = 0;
to[0][j] = f0 + 1;
} else { // a b 0 0
to[1][j] = f1;
to[0][j] = f0;
}
continue;
}
if (f1 === f0) {
to[3][j] = 0;
to[0][j] = f0 + 1;
if (f3 === f2) { // a a b b
updated = true;
to[2][j] = 0;
to[1][j] = f2 + 1;
} else { // a a b c
to[2][j] = f3;
to[1][j] = f2;
}
} else {
to[0][j] = f0;
if (f2 === f1) { // a b b c
updated = true;
to[3][j] = 0;
to[2][j] = f3;
to[1][j] = f1 + 1;
} else {
to[1][j] = f1;
if (f2 === f3) { // a b c c
updated = true;
to[3][j] = 0;
to[2][j] = f2+1;
} else { // a b c d
to[3][j] = f3;
to[2][j] = f2;
}
}
}
}
return updated;
}
BoardArr2d.prototype.left = BoardArr2d.prototype.shiftLeft_mostly_unrolled;
BoardArr2d.prototype.right = BoardArr2d.prototype.shiftRight_mostly_unrolled;
BoardArr2d.prototype.up = BoardArr2d.prototype.shiftUp_mostly_unrolled;
BoardArr2d.prototype.down = BoardArr2d.prototype.shiftDown_mostly_unrolled;
////////////////////////////////////////////////////////////////
/** Create board as properties of object.
* Extract data from 'brd' if present.
* @param brd 2d array
* @constructor */
////////////////////////////////////////////////////////////////
function BoardObj(brd) {
if (brd)
this.brd = { aa: brd[0][0], ab: brd[0][1], ac: brd[0][2], ad: brd[0][3],
ba: brd[1][0], bb: brd[1][1], bc: brd[1][2], bd: brd[1][3],
ca: brd[2][0], cb: brd[2][1], cc: brd[2][2], cd: brd[2][3],
da: brd[3][0], db: brd[3][1], dc: brd[3][2], dd: brd[3][3] };
else
this.brd = { aa: 0, ab: 0, ac: 0, ad: 0,
ba: 0, bb: 0, bc: 0, bd: 0,
ca: 0, cb: 0, cc: 0, cd: 0,
da: 0, db: 0, dc: 0, dd: 0 };
}
BoardObj.arrMap = [["aa", "ab", "ac", "ad"], ["ba", "bb", "bc", "bd"], ["ca", "cb", "cc", "cd"], ["da", "db", "dc", "dd"]];
/** Get [i][j] element. */
BoardObj.prototype.get = function(i, j) {
return this.brd[BoardObj.arrMap[i][j]];
}
/** Set [i][j] element. */
BoardObj.prototype.set = function(i, j, val) {
this.brd[BoardObj.arrMap[i][j]] = val;
}
/* Return and optionally fill 2d board.
* Doesn't designed to be efficient. */
BoardObj.prototype.exportTo = function(brd) {
brd = brd || [[],[],[],[]];
for (var i = 0; i < 4; i++)
for (var j = 0; j < 4; j++)
brd[i][j] = this.brd[4*i + j];
return brd;
}
/** Compare boards. */
BoardObj.prototype.equals = function(brd) {
var self = this.brd;
return self.aa == brd.aa && self.ad == brd.ad && self.da == brd.da && self.dd == brd.dd
&& self.ab == brd.ab && self.ac == brd.ac
&& self.ba == brd.ba && self.ca == brd.ca
&& self.bd == brd.bd && self.cd == brd.cd
&& self.db == brd.db && self.dc == brd.dc
&& self.bb == brd.bb && self.bc == brd.bc && self.cb == brd.cb && self.cc == brd.cc;
};
BoardObj.prototype.compress = function() {
var brd = this.brd;
var h1 = brd.aa;
h1 = (h1 << 4) | brd.ab;
h1 = (h1 << 4) | brd.ac;
h1 = (h1 << 4) | brd.ad;
h1 = (h1 << 4) | brd.ba;
h1 = (h1 << 4) | brd.bb;
h1 = (h1 << 4) | brd.bc;
h1 = (h1 << 4) | brd.bd;
var h2 = brd.ca;
h2 = (h2 << 4) | brd.cb;
h2 = (h2 << 4) | brd.cc;
h2 = (h2 << 4) | brd.cd;
h2 = (h2 << 4) | brd.da;
h2 = (h2 << 4) | brd.db;
h2 = (h2 << 4) | brd.dc;
h2 = (h2 << 4) | brd.dd;
return [h1, h2];
}
BoardObj.prototype.copy = function(brd) {
var self = this.brd;
if ( ! brd) {
var newBrd = new Object(BoardObj.prototype);
newBrd.brd = { aa: self.aa, ab: self.ab, ac: self.ac, ad: self.ad,
ba: self.ba, bb: self.bb, bc: self.bc, bd: self.bd,
ca: self.ca, cb: self.cb, cc: self.cc, cd: self.cd,
da: self.da, db: self.db, dc: self.dc, dd: self.dd };
return newBrd;
}
brd.aa = self.aa; brd.ab = self.ab; brd.ac = self.ac; brd.ad = self.ad;
brd.ba = self.ba; brd.bb = self.bb; brd.bc = self.bc; brd.bd = self.bd;
brd.ca = self.ca; brd.cb = self.cb; brd.cc = self.cc; brd.cd = self.cd;
brd.da = self.da; brd.db = self.db; brd.dc = self.dc; brd.dd = self.dd;
return brd;
}
/** Number of free cell. */
BoardObj.prototype.free = function() {
var cnt = 0;
var brd = this.brd;
if (brd.aa === 0) cnt++; if (brd.ab === 0) cnt++; if (brd.ac === 0) cnt++; if (brd.ad === 0) cnt++;
if (brd.ba === 0) cnt++; if (brd.bb === 0) cnt++; if (brd.bc === 0) cnt++; if (brd.bd === 0) cnt++;
if (brd.ca === 0) cnt++; if (brd.cb === 0) cnt++; if (brd.cc === 0) cnt++; if (brd.cd === 0) cnt++;
if (brd.da === 0) cnt++; if (brd.db === 0) cnt++; if (brd.dc === 0) cnt++; if (brd.dd === 0) cnt++;
return cnt;
}
BoardObj.scoreLookup = [0]; // [ 0, 4, 16, 48, 128, 320, 768, 1792, 4096, 9216, 20480, 45056, 98304];
(function() {
for (var i = 1; i < 16; i++)
BoardObj.scoreLookup[i] = (i-1)*(1 << i);
})();
BoardObj.prototype.score = function() {
var brd = this.brd;
var lookup = BoardObj.scoreLookup;
var score = lookup[brd.aa];
score += lookup[brd.ab];
score += lookup[brd.ac];
score += lookup[brd.ad];
score += lookup[brd.ba];
score += lookup[brd.bb];
score += lookup[brd.bc];
score += lookup[brd.bd];
score += lookup[brd.ca];
score += lookup[brd.cb];
score += lookup[brd.cc];
score += lookup[brd.cd];
score += lookup[brd.da];
score += lookup[brd.db];
score += lookup[brd.dc];
score += lookup[brd.dd];
return score;
}
BoardObj.prototype.max = function() {
var brd = this.brd;
var max = brd.aa;
max = Math.max(max, brd.ab);
max = Math.max(max, brd.ac);
max = Math.max(max, brd.ad);
max = Math.max(max, brd.ba);
max = Math.max(max, brd.bb);
max = Math.max(max, brd.bc);
max = Math.max(max, brd.bd);
max = Math.max(max, brd.ca);
max = Math.max(max, brd.cb);
max = Math.max(max, brd.cc);
max = Math.max(max, brd.cd);
max = Math.max(max, brd.da);
max = Math.max(max, brd.db);
max = Math.max(max, brd.dc);
max = Math.max(max, brd.dd);
return max;
}
BoardObj.prototype.find = function(val) {
var xy = [];
var brd = this.brd;
if (brd.aa === val) xy.push([0,0]); if (brd.ab === val) xy.push([0,1]); if (brd.ac === val) xy.push([0,2]); if (brd.ad === val) xy.push([0,3]);
if (brd.ba === val) xy.push([1,0]); if (brd.bb === val) xy.push([1,1]); if (brd.bc === val) xy.push([1,2]); if (brd.bd === val) xy.push([1,3]);
if (brd.ca === val) xy.push([2,0]); if (brd.cb === val) xy.push([2,1]); if (brd.cc === val) xy.push([2,2]); if (brd.cd === val) xy.push([2,3]);
if (brd.da === val) xy.push([3,0]); if (brd.db === val) xy.push([3,1]); if (brd.dc === val) xy.push([3,2]); if (brd.dd === val) xy.push([3,3]);
return xy;
}
BoardObj.prototype.atEdge = function(val) {
var brd = this.brd;
return (brd.aa === val) || (brd.ab === val) || (brd.ac === val) || (brd.ad === val)
|| (brd.ba === val) || (brd.bd === val)
|| (brd.ca === val) || (brd.cd === val)
|| (brd.da === val) || (brd.db === val) || (brd.dc === val) || (brd.dd === val);
}
BoardObj.prototype.atCorner = function(val) {
var brd = this.brd;
return (brd.aa === val) || (brd.ad === val) || (brd.da === val) || (brd.dd === val);
}
BoardObj.prototype.canRight = function() {
var brd = this.brd;
var f0 = brd.aa, f1 = brd.ab, f2 = brd.ac, f3 = brd.ad;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.ba, f1 = brd.bb, f2 = brd.bc, f3 = brd.bd;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.ca, f1 = brd.cb, f2 = brd.cc, f3 = brd.cd;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.da, f1 = brd.db, f2 = brd.dc, f3 = brd.dd;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
return false;
}
BoardObj.prototype.canLeft = function() {
var brd = this.brd;
var f0 = brd.aa, f1 = brd.ab, f2 = brd.ac, f3 = brd.ad;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.ba, f1 = brd.bb, f2 = brd.bc, f3 = brd.bd;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.ca, f1 = brd.cb, f2 = brd.cc, f3 = brd.cd;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.da, f1 = brd.db, f2 = brd.dc, f3 = brd.dd;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
return false;
}
BoardObj.prototype.canUp = function() {
var brd = this.brd;
var f0 = brd.aa, f1 = brd.ba, f2 = brd.ca, f3 = brd.da;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.ab, f1 = brd.bb, f2 = brd.cb, f3 = brd.db;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.ac, f1 = brd.bc, f2 = brd.cc, f3 = brd.dc;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
var f0 = brd.ad, f1 = brd.bd, f2 = brd.cd, f3 = brd.dd;
if (f1 > 0 && (f1 === f0 || f0 === 0)) return true;
if (f2 > 0 && (f2 === f1 || f1 === 0)) return true;
if (f3 > 0 && (f3 === f2 || f2 === 0)) return true;
return false;
}
BoardObj.prototype.canDown = function() {
var brd = this.brd;
var f0 = brd.aa, f1 = brd.ba, f2 = brd.ca, f3 = brd.da;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.ab, f1 = brd.bb, f2 = brd.cb, f3 = brd.db;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.ac, f1 = brd.bc, f2 = brd.cc, f3 = brd.dc;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
var f0 = brd.ad, f1 = brd.bd, f2 = brd.cd, f3 = brd.dd;
if (f2 > 0 && (f2 === f3 || f3 === 0)) return true;
if (f1 > 0 && (f1 === f2 || f2 === 0)) return true;
if (f0 > 0 && (f0 === f1 || f1 === 0)) return true;
return false;
}
BoardObj.prototype.right = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
var moved = true;
var f0 = from.aa, f1 = from.ab, f2 = from.ac, f3 = from.ad;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.aa = 0;
to.ab = 0;
to.ac = 0;
to.ad = f3;
} else if (f1 === 0) {
to.aa = 0;
to.ab = 0;
if (f2 === f3) {
updated = true;
to.ac = 0;
to.ad = f3 + 1;
} else {
to.ac = f2;
to.ad = f3;
}
} else if (f2 === f3) {
updated = true;
to.aa = 0;
to.ad = f3 + 1;
if (f0 === f1) {
to.ab = 0;
to.ac = f1 + 1;
} else {
to.ab = f0;
to.ac = f1;
}
} else {
to.ad = f3;
if (f1 === f2) {
updated = true;
to.aa = 0;
to.ab = f0;
to.ac = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.aa = 0;
to.ab = f1+1;
to.ac = f2;
} else {
to.aa = f0;
to.ab = f1;
to.ac = f2;
}
}
}
var moved = true;
var f0 = from.ba, f1 = from.bb, f2 = from.bc, f3 = from.bd;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.ba = 0;
to.bb = 0;
to.bc = 0;
to.bd = f3;
} else if (f1 === 0) {
to.ba = 0;
to.bb = 0;
if (f2 === f3) {
updated = true;
to.bc = 0;
to.bd = f3 + 1;
} else {
to.bc = f2;
to.bd = f3;
}
} else if (f2 === f3) {
updated = true;
to.ba = 0;
to.bd = f3 + 1;
if (f0 === f1) {
to.bb = 0;
to.bc = f1 + 1;
} else {
to.bb = f0;
to.bc = f1;
}
} else {
to.bd = f3;
if (f1 === f2) {
updated = true;
to.ba = 0;
to.bb = f0;
to.bc = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.ba = 0;
to.bb = f1+1;
to.bc = f2;
} else {
to.ba = f0;
to.bb = f1;
to.bc = f2;
}
}
}
var moved = true;
var f0 = from.ca, f1 = from.cb, f2 = from.cc, f3 = from.cd;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.ca = 0;
to.cb = 0;
to.cc = 0;
to.cd = f3;
} else if (f1 === 0) {
to.ca = 0;
to.cb = 0;
if (f2 === f3) {
updated = true;
to.cc = 0;
to.cd = f3 + 1;
} else {
to.cc = f2;
to.cd = f3;
}
} else if (f2 === f3) {
updated = true;
to.ca = 0;
to.cd = f3 + 1;
if (f0 === f1) {
to.cb = 0;
to.cc = f1 + 1;
} else {
to.cb = f0;
to.cc = f1;
}
} else {
to.cd = f3;
if (f1 === f2) {
updated = true;
to.ca = 0;
to.cb = f0;
to.cc = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.ca = 0;
to.cb = f1+1;
to.cc = f2;
} else {
to.ca = f0;
to.cb = f1;
to.cc = f2;
}
}
}
var moved = true;
var f0 = from.da, f1 = from.db, f2 = from.dc, f3 = from.dd;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.da = 0;
to.db = 0;
to.dc = 0;
to.dd = f3;
} else if (f1 === 0) {
to.da = 0;
to.db = 0;
if (f2 === f3) {
updated = true;
to.dc = 0;
to.dd = f3 + 1;
} else {
to.dc = f2;
to.dd = f3;
}
} else if (f2 === f3) {
updated = true;
to.da = 0;
to.dd = f3 + 1;
if (f0 === f1) {
to.db = 0;
to.dc = f1 + 1;
} else {
to.db = f0;
to.dc = f1;
}
} else {
to.dd = f3;
if (f1 === f2) {
updated = true;
to.da = 0;
to.db = f0;
to.dc = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.da = 0;
to.db = f1+1;
to.dc = f2;
} else {
to.da = f0;
to.db = f1;
to.dc = f2;
}
}
}
return updated;
}
BoardObj.prototype.down = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
var moved = true;
var f0 = from.aa, f1 = from.ba, f2 = from.ca, f3 = from.da;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.aa = 0;
to.ba = 0;
to.ca = 0;
to.da = f3;
} else if (f1 === 0) {
to.aa = 0;
to.ba = 0;
if (f2 === f3) {
to.ca = 0;
to.da = f3 + 1;
updated = true;
} else {
to.ca = f2;
to.da = f3;
}
} else if (f2 === f3) {
updated = true;
to.aa = 0;
to.da = f3 + 1;
if (f0 === f1) {
to.ba = 0;
to.ca = f1 + 1;
} else {
to.ba = f0;
to.ca = f1;
}
} else {
to.da = f3;
if (f1 === f2) {
updated = true;
to.aa = 0;
to.ba = f0;
to.ca = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.aa = 0;
to.ba = f1+1;
to.ca = f2;
} else {
to.aa = f0;
to.ba = f1;
to.ca = f2;
}
}
}
var moved = true;
var f0 = from.ab, f1 = from.bb, f2 = from.cb, f3 = from.db;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.ab = 0;
to.bb = 0;
to.cb = 0;
to.db = f3;
} else if (f1 === 0) {
to.ab = 0;
to.bb = 0;
if (f2 === f3) {
to.cb = 0;
to.db = f3 + 1;
updated = true;
} else {
to.cb = f2;
to.db = f3;
}
} else if (f2 === f3) {
updated = true;
to.ab = 0;
to.db = f3 + 1;
if (f0 === f1) {
to.bb = 0;
to.cb = f1 + 1;
} else {
to.bb = f0;
to.cb = f1;
}
} else {
to.db = f3;
if (f1 === f2) {
updated = true;
to.ab = 0;
to.bb = f0;
to.cb = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.ab = 0;
to.bb = f1+1;
to.cb = f2;
} else {
to.ab = f0;
to.bb = f1;
to.cb = f2;
}
}
}
var moved = true;
var f0 = from.ac, f1 = from.bc, f2 = from.cc, f3 = from.dc;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.ac = 0;
to.bc = 0;
to.cc = 0;
to.dc = f3;
} else if (f1 === 0) {
to.ac = 0;
to.bc = 0;
if (f2 === f3) {
to.cc = 0;
to.dc = f3 + 1;
updated = true;
} else {
to.cc = f2;
to.dc = f3;
}
} else if (f2 === f3) {
updated = true;
to.ac = 0;
to.dc = f3 + 1;
if (f0 === f1) {
to.bc = 0;
to.cc = f1 + 1;
} else {
to.bc = f0;
to.cc = f1;
}
} else {
to.dc = f3;
if (f1 === f2) {
updated = true;
to.ac = 0;
to.bc = f0;
to.cc = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.ac = 0;
to.bc = f1+1;
to.cc = f2;
} else {
to.ac = f0;
to.bc = f1;
to.cc = f2;
}
}
}
var moved = true;
var f0 = from.ad, f1 = from.bd, f2 = from.cd, f3 = from.dd;
if (f3 === 0) {
if (f2 === 0) {
if (f1 === 0) { // a 0 0 0
if (f0 === 0)
moved = false;
f3 = f0;
f2 = 0;
} else { // a b 0 0
f3 = f1;
f2 = f0;
}
f1 = 0;
} else { // f2 !== 0 && f3 === 0
if (f1 === 0) { // a 0 b 0
f3 = f2;
f2 = f0;
} else { // a b c 0
f3 = f2;
f2 = f1;
f1 = f0;
}
}
f0 = 0;
} else { // f3 !== 0
if (f2 === 0) {
if (f1 === 0) { // a 0 0 b
if (f0 === 0)
moved = false;
f2 = f0;
} else { // a b 0 c
f2 = f1;
f1 = f0;
}
f0 = 0;
} else { // f2 !== 0 && f3 !== 0
if (f1 === 0) { // a 0 b c
if (f0 === 0)
moved = false;
f1 = f0;
f0 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f2 === 0) {
to.ad = 0;
to.bd = 0;
to.cd = 0;
to.dd = f3;
} else if (f1 === 0) {
to.ad = 0;
to.bd = 0;
if (f2 === f3) {
to.cd = 0;
to.dd = f3 + 1;
updated = true;
} else {
to.cd = f2;
to.dd = f3;
}
} else if (f2 === f3) {
updated = true;
to.ad = 0;
to.dd = f3 + 1;
if (f0 === f1) {
to.bd = 0;
to.cd = f1 + 1;
} else {
to.bd = f0;
to.cd = f1;
}
} else {
to.dd = f3;
if (f1 === f2) {
updated = true;
to.ad = 0;
to.bd = f0;
to.cd = f2 + 1;
} else {
if (f0 === f1) {
updated = true;
to.ad = 0;
to.bd = f1+1;
to.cd = f2;
} else {
to.ad = f0;
to.bd = f1;
to.cd = f2;
}
}
}
return updated;
}
BoardObj.prototype.left = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
var moved = true;
var f0 = from.aa, f1 = from.ab, f2 = from.ac, f3 = from.ad;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.ad = 0;
to.ac = 0;
to.ab = 0;
to.aa = f0;
} else if (f2 === 0) {
to.ad = 0;
to.ac = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.ab = 0;
to.aa = f0 + 1;
} else { // a b 0 0
to.ab = f1;
to.aa = f0;
}
} else if (f1 === f0) {
updated = true;
to.ad = 0;
to.aa = f0 + 1;
if (f3 === f2) { // a a b b
to.ac = 0;
to.ab = f2 + 1;
} else { // a a b c
to.ac = f3;
to.ab = f2;
}
} else {
to.aa = f0;
if (f2 === f1) { // a b b c
updated = true;
to.ad = 0;
to.ac = f3;
to.ab = f1 + 1;
} else {
to.ab = f1;
if (f2 === f3) { // a b c c
updated = true;
to.ad = 0;
to.ac = f2+1;
} else { // a b c d
to.ad = f3;
to.ac = f2;
}
}
}
var moved = true;
var f0 = from.ba, f1 = from.bb, f2 = from.bc, f3 = from.bd;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.bd = 0;
to.bc = 0;
to.bb = 0;
to.ba = f0;
} else if (f2 === 0) {
to.bd = 0;
to.bc = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.bb = 0;
to.ba = f0 + 1;
} else { // a b 0 0
to.bb = f1;
to.ba = f0;
}
} else if (f1 === f0) {
updated = true;
to.bd = 0;
to.ba = f0 + 1;
if (f3 === f2) { // a a b b
to.bc = 0;
to.bb = f2 + 1;
} else { // a a b c
to.bc = f3;
to.bb = f2;
}
} else {
to.ba = f0;
if (f2 === f1) { // a b b c
updated = true;
to.bd = 0;
to.bc = f3;
to.bb = f1 + 1;
} else {
to.bb = f1;
if (f2 === f3) { // a b c c
updated = true;
to.bd = 0;
to.bc = f2+1;
} else { // a b c d
to.bd = f3;
to.bc = f2;
}
}
}
var moved = true;
var f0 = from.ca, f1 = from.cb, f2 = from.cc, f3 = from.cd;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.cd = 0;
to.cc = 0;
to.cb = 0;
to.ca = f0;
} else if (f2 === 0) {
to.cd = 0;
to.cc = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.cb = 0;
to.ca = f0 + 1;
} else { // a b 0 0
to.cb = f1;
to.ca = f0;
}
} else if (f1 === f0) {
updated = true;
to.cd = 0;
to.ca = f0 + 1;
if (f3 === f2) { // a a b b
to.cc = 0;
to.cb = f2 + 1;
} else { // a a b c
to.cc = f3;
to.cb = f2;
}
} else {
to.ca = f0;
if (f2 === f1) { // a b b c
updated = true;
to.cd = 0;
to.cc = f3;
to.cb = f1 + 1;
} else {
to.cb = f1;
if (f2 === f3) { // a b c c
updated = true;
to.cd = 0;
to.cc = f2+1;
} else { // a b c d
to.cd = f3;
to.cc = f2;
}
}
}
var moved = true;
var f0 = from.da, f1 = from.db, f2 = from.dc, f3 = from.dd;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.dd = 0;
to.dc = 0;
to.db = 0;
to.da = f0;
} else if (f2 === 0) {
to.dd = 0;
to.dc = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.db = 0;
to.da = f0 + 1;
} else { // a b 0 0
to.db = f1;
to.da = f0;
}
} else if (f1 === f0) {
updated = true;
to.dd = 0;
to.da = f0 + 1;
if (f3 === f2) { // a a b b
to.dc = 0;
to.db = f2 + 1;
} else { // a a b c
to.dc = f3;
to.db = f2;
}
} else {
to.da = f0;
if (f2 === f1) { // a b b c
updated = true;
to.dd = 0;
to.dc = f3;
to.db = f1 + 1;
} else {
to.db = f1;
if (f2 === f3) { // a b c c
updated = true;
to.dd = 0;
to.dc = f2+1;
} else { // a b c d
to.dd = f3;
to.dc = f2;
}
}
}
return updated;
}
BoardObj.prototype.up = function(brd) {
var updated = false;
var from = this.brd, to = brd.brd;
var moved = true;
var f0 = from.aa, f1 = from.ba, f2 = from.ca, f3 = from.da;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.da = 0;
to.ca = 0;
to.ba = 0;
to.aa = f0;
} else if (f2 === 0) {
to.da = 0;
to.ca = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.ba = 0;
to.aa = f0 + 1;
} else { // a b 0 0
to.ba = f1;
to.aa = f0;
}
} else if (f1 === f0) {
to.da = 0;
to.aa = f0 + 1;
if (f3 === f2) { // a a b b
updated = true;
to.ca = 0;
to.ba = f2 + 1;
} else { // a a b c
to.ca = f3;
to.ba = f2;
}
} else {
to.aa = f0;
if (f2 === f1) { // a b b c
updated = true;
to.da = 0;
to.ca = f3;
to.ba = f1 + 1;
} else {
to.ba = f1;
if (f2 === f3) { // a b c c
updated = true;
to.da = 0;
to.ca = f2+1;
} else { // a b c d
to.da = f3;
to.ca = f2;
}
}
}
var moved = true;
var f0 = from.ab, f1 = from.bb, f2 = from.cb, f3 = from.db;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.db = 0;
to.cb = 0;
to.bb = 0;
to.ab = f0;
} else if (f2 === 0) {
to.db = 0;
to.cb = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.bb = 0;
to.ab = f0 + 1;
} else { // a b 0 0
to.bb = f1;
to.ab = f0;
}
} else if (f1 === f0) {
to.db = 0;
to.ab = f0 + 1;
if (f3 === f2) { // a a b b
updated = true;
to.cb = 0;
to.bb = f2 + 1;
} else { // a a b c
to.cb = f3;
to.bb = f2;
}
} else {
to.ab = f0;
if (f2 === f1) { // a b b c
updated = true;
to.db = 0;
to.cb = f3;
to.bb = f1 + 1;
} else {
to.bb = f1;
if (f2 === f3) { // a b c c
updated = true;
to.db = 0;
to.cb = f2+1;
} else { // a b c d
to.db = f3;
to.cb = f2;
}
}
}
var moved = true;
var f0 = from.ac, f1 = from.bc, f2 = from.cc, f3 = from.dc;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.dc = 0;
to.cc = 0;
to.bc = 0;
to.ac = f0;
} else if (f2 === 0) {
to.dc = 0;
to.cc = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.bc = 0;
to.ac = f0 + 1;
} else { // a b 0 0
to.bc = f1;
to.ac = f0;
}
} else if (f1 === f0) {
to.dc = 0;
to.ac = f0 + 1;
if (f3 === f2) { // a a b b
updated = true;
to.cc = 0;
to.bc = f2 + 1;
} else { // a a b c
to.cc = f3;
to.bc = f2;
}
} else {
to.ac = f0;
if (f2 === f1) { // a b b c
updated = true;
to.dc = 0;
to.cc = f3;
to.bc = f1 + 1;
} else {
to.bc = f1;
if (f2 === f3) { // a b c c
updated = true;
to.dc = 0;
to.cc = f2+1;
} else { // a b c d
to.dc = f3;
to.cc = f2;
}
}
}
var moved = true;
var f0 = from.ad, f1 = from.bd, f2 = from.cd, f3 = from.dd;
if (f0 === 0) {
if (f1 === 0) {
if (f2 === 0) { // 0 0 0 a
if (f3 === 0)
moved = false;
f0 = f3;
f1 = 0;
} else { // 0 0 a b
f0 = f2;
f1 = f3;
}
f2 = 0;
} else { // f1 !== 0 && f0 === 0
if (f2 === 0) { // 0 a 0 b
f0 = f1;
f1 = f3;
} else { // 0 a b c
f0 = f1;
f1 = f2;
f2 = f3;
}
}
f3 = 0;
} else { // f0 !== 0
if (f1 === 0) {
if (f2 === 0) { // a 0 0 b
if (f3 === 0)
moved = false;
f1 = f3;
} else { // a 0 b c
f1 = f2;
f2 = f3;
}
f3 = 0;
} else { // f1 !== 0 && f0 !== 0
if (f2 === 0) { // a b 0 c
if (f3 === 0)
moved = false;
f2 = f3;
f3 = 0;
} else { // else: a b c d
moved = false;
}
}
}
updated = updated || moved;
if (f1 === 0) { // a 0 0 0
to.dd = 0;
to.cd = 0;
to.bd = 0;
to.ad = f0;
} else if (f2 === 0) {
to.dd = 0;
to.cd = 0;
if (f1 === f0) { // a a 0 0
updated = true;
to.bd = 0;
to.ad = f0 + 1;
} else { // a b 0 0
to.bd = f1;
to.ad = f0;
}
} else if (f1 === f0) {
to.dd = 0;
to.ad = f0 + 1;
if (f3 === f2) { // a a b b
updated = true;
to.cd = 0;
to.bd = f2 + 1;
} else { // a a b c
to.cd = f3;
to.bd = f2;
}
} else {
to.ad = f0;
if (f2 === f1) { // a b b c
updated = true;
to.dd = 0;
to.cd = f3;
to.bd = f1 + 1;
} else {
to.bd = f1;
if (f2 === f3) { // a b c c
updated = true;
to.dd = 0;
to.cd = f2+1;
} else { // a b c d
to.dd = f3;
to.cd = f2;
}
}
}
return updated;
}