zeroclickinfo-goodies/share/goodie/game2048/game2048.js

250 lines
7.9 KiB
JavaScript

DDH.game2048 = DDH.game2048 || {};
DDH.game2048.build = function(ops) {
// Global Variables Declaration
var $tempArea, $container, $spanPoints, WINNUM, SIZE, TILE_COUNT;
var lost_or_won = false,
started,
area,
cells,
score = 0;
function rc_to_index(row, col) {
return row * SIZE + col;
}
//This function moves and sums numbers
function mov(dir) {
var points = 0,
moved = false;
if (dir === 'a' || dir === 'd') {
transpose_area();
}
if (dir === 's' || dir === 'd') {
swap_rows_area();
}
for (var col = 0; col < SIZE; ++col) {
var moves = 0;
for (var row = 0; row < SIZE; ++row) {
var i = rc_to_index(row, col);
var exit = false;
if (area[i].val === 0) {
++moves;
} else {
// if a move can be made
if(moves > 0) {
area[rc_to_index(row - moves, col)].val = area[i].val;
area[i].val = 0;
moved = true;
}
for(var j = row + 1; j < SIZE && exit === false; ++j) {
// if numbers can be summed
if(area[rc_to_index(row - moves, col)].val === area[rc_to_index(j, col)].val) {
// sum numbers
area[rc_to_index(row - moves, col)].val *= 2;
// delete the old number
area[rc_to_index(j, col)].val = 0;
// add points
points = area[rc_to_index(row - moves, col)].val;
moved = true; exit = true;
// else quit the while loop
} else if(area[rc_to_index(j, col)].val !== 0) {
exit = true;
}
}
}
}
}
if (dir === 's' || dir === 'd') {
swap_rows_area();
}
if (dir === 'a' || dir === 'd') {
transpose_area();
}
increase_points(points);
//This check is mandatory in order to avoid the appearance of a new
//value in the area if no moves has been made
return moved;
}
// Updates the 'points' div
function increase_points(points) {
score += points;
$spanPoints.text(score);
}
//After every little table's change, the area is updated.
//This function changes the cell class too
function print_area() {
cells.each(function(index) {
var val = area[index].val;
if(val === 0) {
$(this).html("").attr("class", "boxtile val-");
} else {
$(this).html(val).attr("class", "boxtile val-" + val);
}
});
}
// 'area' initialization
function init_area() {
area = [];
cells.each(function(index) {
area[index] = {
row: Math.floor(index / SIZE),
col: index % SIZE,
val: 0
};
});
}
// left and right moves activate this function
function transpose_area() {
for(var i = 0; i < TILE_COUNT; ++i) {
if(area[i].col >= area[i].row) continue;
var index_to_swap = area[i].col * SIZE + area[i].row;
var tmp_val = area[i].val;
area[i].val = area[index_to_swap].val;
area[index_to_swap].val = tmp_val;
}
}
// down and right moves activate this function
function swap_rows_area() {
for(var i = 0; i < TILE_COUNT / 2; ++i) {
var row = area[i].row,
col = area[i].col;
var index_to_swap = rc_to_index(SIZE - 1 - row, col);
var tmp_val = area[i].val;
area[i].val = area[index_to_swap].val;
area[index_to_swap].val = tmp_val;
}
}
//This function set a random number ( 2 or 4 ) in a random
//position around the area. 4 has a 10% chance of being chosen.
function add_random_tile() {
var free = [];
for(var i = 0; i < TILE_COUNT; ++i) {
if(area[i].val === 0) {
free.push(i);
}
}
var rand_tile = free[Math.floor(Math.random() * free.length)];
var rand_val = Math.floor(Math.random() * 11);
rand_val = rand_val < 2 ? 4 : 2;
area[rand_tile].val = rand_val;
}
//If there is the winning number inside the table, returns true and
//prints a congratulation message
function has_won() {
for(var i = 0; i < TILE_COUNT; ++i) {
if (area[i].val == WINNUM) {
alert("You won");
return true;
}
}
return false;
}
// If no moves or sums are possible, return true
function has_lost() {
var full_tiles_count = 0,
move_possible = false;
for(var i = 0; i < TILE_COUNT; ++i) {
if (area[i].val > 0) {
++full_tiles_count;
}
var row = area[i].row;
var col = area[i].col;
// check all available movements
if ((row !== 0 && area[i].val === area[rc_to_index(row - 1, col)].val) ||
(row !== SIZE - 1 && area[i].val === area[rc_to_index(row + 1, col)].val) ||
(col !== 0 && area[i].val === area[rc_to_index(row, col - 1)].val) ||
(col !== SIZE - 1 && area[i].val === area[rc_to_index(row, col + 1)].val)) {
move_possible = true;
}
}
if (full_tiles_count === TILE_COUNT && move_possible === false) {
alert("You lost");
return true;
}
return false;
}
// This function creates and prints on page the gaming table
function start() {
init_area();
add_random_tile();
print_area();
}
return {
onShow: function() {
//'started' is a boolean variable used in order to avoid the
//duplication of the gaming area. Moving around the DDG tabs the
//'onShow' function is executed over and over. This simple solution
//prevents the problem
if (!started) {
started = true;
$container = $('#game2048__container');
$spanPoints = $('.game2048__points');
$tempArea = $('#game2048__area');
WINNUM = ops.data[0].inputNum;
SIZE = ops.data[0].dimension;
TILE_COUNT = SIZE * SIZE;
cells = $('td.boxtile.val-');
start();
$tempArea.keydown(function(e) {
e.preventDefault();
var moved = false;
if (!lost_or_won) {
if (e.keyCode === 87 || e.keyCode === 38) { // w or up arrow
moved = mov('w');
} else if (e.keyCode === 65 || e.keyCode === 37) { // a or left arrow
moved = mov('a');
} else if (e.keyCode === 83 || e.keyCode === 40) { // s or dowm arrow
moved = mov('s');
} else if (e.keyCode === 68 || e.keyCode === 39) { // d or right arrow
moved = mov('d');
}
if (moved) {
add_random_tile();
print_area();
if (has_won() || has_lost()) {
lost_or_won = true;
}
}
print_area();
}
return false;
});
}
}
};
};