195 lines
4.5 KiB
JavaScript
195 lines
4.5 KiB
JavaScript
/* ------------------------
|
|
5. GAME LOGIC
|
|
------------------------ */
|
|
function addNewTile() {
|
|
const empty = [];
|
|
for (let r = 0; r < 4; r++) {
|
|
for (let c = 0; c < 4; c++) {
|
|
if (board[r][c] === 0) empty.push({ r, c });
|
|
}
|
|
}
|
|
|
|
if (empty.length === 0) return false;
|
|
|
|
const spot = empty[Math.floor(Math.random() * empty.length)];
|
|
board[spot.r][spot.c] = 2;
|
|
|
|
const tile = document.getElementById(`${spot.r}-${spot.c}`);
|
|
if (tile) {
|
|
tile.classList.add("new");
|
|
playSound(audio.pop);
|
|
setTimeout(() => tile.classList.remove("new"), 300);
|
|
}
|
|
updateTile(spot.r, spot.c, 2);
|
|
return true;
|
|
}
|
|
|
|
function filterZero(row) {
|
|
return row.filter(n => n !== 0);
|
|
}
|
|
|
|
function slide(row) {
|
|
row = filterZero(row);
|
|
let mergedThisMove = false;
|
|
let mergedPositions = [];
|
|
let mergeCount = 0;
|
|
|
|
for (let i = 0; i < row.length - 1; i++) {
|
|
if (row[i] === row[i + 1]) {
|
|
row[i] = row[i] * 2;
|
|
|
|
playSound(audio.merge);
|
|
|
|
if (navigator.vibrate) {
|
|
navigator.vibrate([80, 20, 80]);
|
|
}
|
|
|
|
currentScore += row[i];
|
|
row[i + 1] = 0;
|
|
mergedThisMove = true;
|
|
mergedPositions.push(i);
|
|
mergeCount++;
|
|
}
|
|
}
|
|
|
|
row = filterZero(row);
|
|
while (row.length < 4) row.push(0);
|
|
return { row, merged: mergedThisMove, mergedPositions, mergeCount };
|
|
}
|
|
|
|
function arraysEqual(a, b) {
|
|
return a.length === b.length && a.every((v, i) => v === b[i]);
|
|
}
|
|
|
|
/* Move functions */
|
|
function moveLeft() {
|
|
let moved = false;
|
|
let mergedCells = [];
|
|
mergesInCurrentMove = 0;
|
|
|
|
for (let r = 0; r < 4; r++) {
|
|
const { row: newRow, mergedPositions, mergeCount } = slide(board[r]);
|
|
if (!arraysEqual(newRow, board[r])) moved = true;
|
|
board[r] = newRow;
|
|
|
|
mergesInCurrentMove += mergeCount;
|
|
|
|
if (mergedPositions && mergedPositions.length > 0) {
|
|
mergedPositions.forEach(c => {
|
|
mergedCells.push({ r, c });
|
|
});
|
|
}
|
|
}
|
|
|
|
if (moved) {
|
|
refreshBoard();
|
|
triggerComboEffect(mergedCells, mergesInCurrentMove);
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
function moveRight() {
|
|
let moved = false;
|
|
let mergedCells = [];
|
|
mergesInCurrentMove = 0;
|
|
|
|
for (let r = 0; r < 4; r++) {
|
|
let reversed = [...board[r]].reverse();
|
|
const { row: slid, mergedPositions, mergeCount } = slide(reversed);
|
|
let newRow = slid.reverse();
|
|
if (!arraysEqual(newRow, board[r])) moved = true;
|
|
board[r] = newRow;
|
|
|
|
mergesInCurrentMove += mergeCount;
|
|
|
|
if (mergedPositions && mergedPositions.length > 0) {
|
|
mergedPositions.forEach(pos => {
|
|
const c = 3 - pos;
|
|
mergedCells.push({ r, c });
|
|
});
|
|
}
|
|
}
|
|
|
|
if (moved) {
|
|
refreshBoard();
|
|
triggerComboEffect(mergedCells, mergesInCurrentMove);
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
function moveUp() {
|
|
let moved = false;
|
|
let mergedCells = [];
|
|
mergesInCurrentMove = 0;
|
|
|
|
for (let c = 0; c < 4; c++) {
|
|
const col = [board[0][c], board[1][c], board[2][c], board[3][c]];
|
|
const { row: newCol, mergedPositions, mergeCount } = slide(col);
|
|
for (let r = 0; r < 4; r++) {
|
|
if (board[r][c] !== newCol[r]) moved = true;
|
|
board[r][c] = newCol[r];
|
|
}
|
|
|
|
mergesInCurrentMove += mergeCount;
|
|
|
|
if (mergedPositions && mergedPositions.length > 0) {
|
|
mergedPositions.forEach(r => {
|
|
mergedCells.push({ r, c });
|
|
});
|
|
}
|
|
}
|
|
|
|
if (moved) {
|
|
refreshBoard();
|
|
triggerComboEffect(mergedCells, mergesInCurrentMove);
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
function moveDown() {
|
|
let moved = false;
|
|
let mergedCells = [];
|
|
mergesInCurrentMove = 0;
|
|
|
|
for (let c = 0; c < 4; c++) {
|
|
const col = [board[3][c], board[2][c], board[1][c], board[0][c]];
|
|
const { row: slid, mergedPositions, mergeCount } = slide(col);
|
|
const newCol = slid.reverse();
|
|
for (let r = 0; r < 4; r++) {
|
|
if (board[r][c] !== newCol[r]) moved = true;
|
|
board[r][c] = newCol[r];
|
|
}
|
|
|
|
mergesInCurrentMove += mergeCount;
|
|
|
|
if (mergedPositions && mergedPositions.length > 0) {
|
|
mergedPositions.forEach(pos => {
|
|
const r = 3 - pos;
|
|
mergedCells.push({ r, c });
|
|
});
|
|
}
|
|
}
|
|
|
|
if (moved) {
|
|
refreshBoard();
|
|
triggerComboEffect(mergedCells, mergesInCurrentMove);
|
|
}
|
|
return moved;
|
|
}
|
|
|
|
function canMove() {
|
|
for (let r = 0; r < 4; r++) {
|
|
for (let c = 0; c < 4; c++) {
|
|
if (board[r][c] === 0) return true;
|
|
}
|
|
}
|
|
|
|
for (let r = 0; r < 4; r++) {
|
|
for (let c = 0; c < 4; c++) {
|
|
const current = board[r][c];
|
|
if (c < 3 && board[r][c + 1] === current) return true;
|
|
if (r < 3 && board[r + 1][c] === current) return true;
|
|
}
|
|
}
|
|
return false;
|
|
} |