Classic 2048 Game
A simple implementation of the 2048 game. Let's play it!
This implementation explores recreating the classic 2048 puzzle game using Svelte’s reactive.
The major chanllenge I met is in handling tile movement mechanics across four directions while not having repeated code.
Mission accomplished: panel now in natural thumb zone 📱
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
The core move logic is like this:
function moveAllCellsTo(direction: Direction) {
// Determine movement axis and processing order
const isVertical = direction === 'up' || direction === 'down';
const reverseProcessing = direction === 'down' || direction === 'right';
// Process each row/column based on movement direction
for (let outerIndex = 0; outerIndex < 4; outerIndex++) {
// Track last checked position to prevent multiple checks towards empty cell
let lastCheckedPosition = // ...next item of current;
// Process cells in movement direction order
for (let innerIndex = reverseProcessing ? 3 : 0;
reverseProcessing ? innerIndex >= 0 : innerIndex < 4;
reverseProcessing ? innerIndex-- : innerIndex++) {
// Find next movable tile in current line
// Start from the last checked position since any tile before is checked, they are empty.
for (let scanPosition = lastCheckedPosition) {
// get the current tile, we use the two index we have,
// and the direction to determine which index is col and which is row
const currentTile = ...;
const targetTile = ...;
// update the last checked position to the next item
lastCheckedPosition++;
// Skip empty tiles during scanning
if (targetTile.value === 0) continue;
// Merge matching tiles that haven't been merged, break since we already have a merged
if (currentTile.value === targetTile.value && currentTile.lastMergedStep < currentStep) {
currentTile.value *= 2;
targetTile.reset();
break;
}
// current one is empty, move the target one to current one, continue checking the next item
if (currentTile.value === 0) {
currentTile.value = targetTile.value;
targetTile.reset();
continue;
}
// Handle blocked movement, break so we start checking for the newly moved tile
if (currentTile.value !== targetTile.value) {
nextTile.value = targetTile.value;
targetTile.reset();
break;
}
}
}
}
}