$.fn.init2048 = function (_options) {
options = $.extend(defaults, _options),
holder = $('<div>').addClass('holder2048');
content = $('<div>').addClass('container').appendTo(holder);
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
$('<div>').addClass('mask').css({
function createBox(value) {
for (var i = 0; i < matrix.length; i++) {
var random = Math.floor(Math.random() * emptyMatrix + 1);
for (var j = 0; chosenIndex < matrix.length; chosenIndex++) {
while (matrix[chosenIndex].taken) {
matrix[chosenIndex].taken = true;
value = value ? value : (Math.floor(Math.random() * 4 + 1) === 4 ? 4 : 2);
var newBox = $('<div>').addClass('box').attr({
marginTop: matrix[chosenIndex].top + 2,
marginLeft: matrix[chosenIndex].left + 2,
}).text(value).appendTo(content).animate({
function combineBox(source, target, value) {
var _value = parseInt(value) * 2;
boxes[target].attr('value', _value).html(_value).css({
}, options.delay / 2, function () {
}, options.delay / 2, function () {
if (boxes.length != 16) {
for (i = 0; i < 16; i++) {
for (a = 0; a < 16; a++) {
if (boxes[a].attr('position') == i)
for (b = 0; b < 16; b++) {
if (boxes[b].attr('position') == i + 1)
if (boxes[a].attr('value') == boxes[b].attr('value'))
for (b = 0; b < 16; b++) {
if (boxes[b].attr('position') == i + 4)
if (boxes[a].attr('value') == boxes[b].attr('value'))
$(window).keydown(function (event) {
} else if (event.which == 38) {
} else if (event.which == 39) {
} else if (event.which == 40) {
var touchStartClientX, touchStartClientY;
document.addEventListener("touchstart", function (event) {
if (event.touches.length > 1)
touchStartClientX = event.touches[0].clientX;
touchStartClientY = event.touches[0].clientY;
document.addEventListener("touchmove", function (event) {
document.addEventListener("touchend", function (event) {
if (event.touches.length > 0)
var dx = event.changedTouches[0].clientX - touchStartClientX;
var absDx = Math.abs(dx);
var dy = event.changedTouches[0].clientY - touchStartClientY;
var absDy = Math.abs(dy);
if (Math.max(absDx, absDy) > 10) {
var i, j, k, empty, _empty, position, value1, value2, temp;
for (i = 0; i < 16; i++) {
matrix[i].combined = false;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
if (!matrix[position].taken) {
if (matrix[position].taken && position === empty) {
if (empty - 2 >= _empty) {
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty - 2) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty - 2].combined) {
combineBox(k, temp, value1);
matrix[empty - 1].taken = false;
matrix[empty - 2].combined = true;
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
marginLeft: matrix[empty].left + 2,
marginTop: matrix[empty].top + 2
boxes[k].attr('position', empty);
matrix[empty].taken = true;
matrix[position].taken = false;
if (empty - 2 >= _empty) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty - 2) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty - 2].combined) {
combineBox(k, temp, value1);
matrix[empty - 1].taken = false;
matrix[empty - 2].combined = true;
} else if (dir == "right") {
for (i = 3; i > -1; i--) {
for (j = 3; j > -1; j--) {
if (!matrix[position].taken) {
if (matrix[position].taken && position === empty) {
if (empty + 2 <= _empty) {
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty + 2) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty + 2].combined) {
combineBox(k, temp, value1);
matrix[empty + 1].taken = false;
matrix[empty + 2].combined = true;
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
marginLeft: matrix[empty].left + 2,
marginTop: matrix[empty].top + 2
boxes[k].attr('position', empty);
matrix[empty].taken = true;
matrix[position].taken = false;
if (empty + 2 <= _empty) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty + 2) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty + 2].combined) {
combineBox(k, temp, value1);
matrix[empty + 1].taken = false;
matrix[empty + 2].combined = true;
} else if (dir == "up") {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
if (!matrix[position].taken) {
if (matrix[position].taken && position === empty) {
if (empty - 8 >= _empty) {
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty - 8) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty - 8].combined) {
combineBox(k, temp, value1);
matrix[empty - 4].taken = false;
matrix[empty - 8].combined = true;
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
marginLeft: matrix[empty].left + 2,
marginTop: matrix[empty].top + 2
boxes[k].attr('position', empty);
matrix[empty].taken = true;
matrix[position].taken = false;
if (empty - 8 >= _empty) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty - 8) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty - 8].combined) {
combineBox(k, temp, value1);
matrix[empty - 4].taken = false;
matrix[empty - 8].combined = true;
} else if (dir == "down") {
for (i = 0; i < 4; i++) {
for (j = 3; j > -1; j--) {
if (!matrix[position].taken) {
if (matrix[position].taken && position === empty) {
if (empty + 8 <= _empty) {
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty + 8) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty + 8].combined) {
combineBox(k, temp, value1);
matrix[empty + 4].taken = false;
matrix[empty + 8].combined = true;
for (k = 0; k < boxes.length; k++) {
if (boxes[k].attr("position") == position) {
marginLeft: matrix[empty].left + 2,
marginTop: matrix[empty].top + 2
boxes[k].attr('position', empty);
matrix[empty].taken = true;
matrix[position].taken = false;
if (empty + 8 <= _empty) {
value1 = boxes[k].attr('value');
for (temp = 0; temp < boxes.length; temp++) {
if (boxes[temp].attr("position") == empty + 8) {
value2 = boxes[temp].attr('value');
if (value1 == value2 && !matrix[empty + 8].combined) {
combineBox(k, temp, value1);
matrix[empty + 4].taken = false;
matrix[empty + 8].combined = true;