简介
2048 是一款风靡全球的数字益智游戏,玩家通过方向键滑动 4x4 棋盘上的数字方块,相同数字碰撞时合并为两倍,目标是合成 2048。游戏厅版本完整实现了滑动合并算法、分数计算和游戏结束判定。
数据结构
棋盘表示
使用 4x4 二维数组存储每个格子的数值,0 表示空格:
1var SIZE = 4;
2var board = [];
3for (var i = 0; i < SIZE; i++) {
4 board[i] = [0, 0, 0, 0];
5}
CSS Grid 渲染
棋盘使用 CSS Grid 布局:
1.tzfe-board {
2 display: grid;
3 grid-template-columns: repeat(4, var(--tz-cell, 72px));
4 grid-template-rows: repeat(4, var(--tz-cell, 72px));
5 gap: 8px;
6 padding: 8px;
7 background: #bbada0;
8 border-radius: 8px;
9}
核心算法
单行滑动合并
滑动的核心逻辑:去掉空格 → 合并相邻相同数字 → 补零到长度 4:
1function slideRow(row) {
2 // 1. 过滤掉所有 0
3 var arr = row.filter(function(v) { return v !== 0; });
4
5 // 2. 从左到右合并相邻相同数字
6 for (var i = 0; i < arr.length - 1; i++) {
7 if (arr[i] === arr[i + 1]) {
8 arr[i] *= 2;
9 score += arr[i];
10 arr.splice(i + 1, 1); // 移除被合并的元素
11 }
12 }
13
14 // 3. 末尾补 0 到长度 4
15 while (arr.length < SIZE) arr.push(0);
16
17 return arr;
18}
四个方向实现
利用单行滑动算法,四个方向通过旋转矩阵实现:
1function move(direction) {
2 var moved = false;
3 var oldBoard = board.map(function(r) { return r.slice(); });
4
5 if (direction === 'left') {
6 for (var i = 0; i < SIZE; i++) board[i] = slideRow(board[i]);
7 }
8 else if (direction === 'right') {
9 // 反转 → 左滑 → 反转回来
10 for (var i = 0; i < SIZE; i++)
11 board[i] = slideRow(board[i].slice().reverse()).reverse();
12 }
13 else if (direction === 'up') {
14 // 提取列 → 左滑 → 写回
15 for (var j = 0; j < SIZE; j++) {
16 var col = [];
17 for (var i = 0; i < SIZE; i++) col.push(board[i][j]);
18 col = slideRow(col);
19 for (var i = 0; i < SIZE; i++) board[i][j] = col[i];
20 }
21 }
22 else if (direction === 'down') {
23 // 提取列(反向) → 左滑 → 反向写回
24 for (var j = 0; j < SIZE; j++) {
25 var col = [];
26 for (var i = SIZE - 1; i >= 0; i--) col.push(board[i][j]);
27 col = slideRow(col).reverse();
28 for (var i = 0; i < SIZE; i++) board[i][j] = col[SIZE - 1 - i];
29 }
30 }
31
32 // 检测是否发生移动
33 for (var i = 0; i < SIZE; i++)
34 for (var j = 0; j < SIZE; j++)
35 if (oldBoard[i][j] !== board[i][j]) moved = true;
36
37 return moved;
38}
随机生成
在空白位置随机生成 2(90%概率)或 4(10%概率):
1function spawnTile() {
2 var emptyCells = [];
3 for (var i = 0; i < SIZE; i++)
4 for (var j = 0; j < SIZE; j++)
5 if (board[i][j] === 0) emptyCells.push([i, j]);
6
7 if (emptyCells.length === 0) return false;
8
9 var pos = emptyCells[Math.floor(Math.random() * emptyCells.length)];
10 board[pos[0]][pos[1]] = Math.random() < 0.9 ? 2 : 4;
11 return true;
12}
游戏结束判定
当没有空格且任何相邻格子都无法合并时,游戏结束:
1function canMove() {
2 for (var i = 0; i < SIZE; i++)
3 for (var j = 0; j < SIZE; j++) {
4 if (board[i][j] === 0) return true;
5 if (j < SIZE - 1 && board[i][j] === board[i][j + 1]) return true;
6 if (i < SIZE - 1 && board[i][j] === board[i + 1][j]) return true;
7 }
8 return false;
9}
2048 达成检测
1function checkWin() {
2 for (var i = 0; i < SIZE; i++)
3 for (var j = 0; j < SIZE; j++)
4 if (board[i][j] === 2048) return true;
5 return false;
6}
方块颜色系统
不同数值的方块使用不同背景色,从浅到深:
1.tzfe-tile.t2 { background: #eee4da; color: #776e65; }
2.tzfe-tile.t4 { background: #ede0c8; color: #776e65; }
3.tzfe-tile.t8 { background: #f2b179; color: #f9f6f2; }
4.tzfe-tile.t16 { background: #f59563; color: #f9f6f2; }
5.tzfe-tile.t32 { background: #f67c5f; color: #f9f6f2; }
6.tzfe-tile.t64 { background: #f65e3b; color: #f9f6f2; }
7.tzfe-tile.t128 { background: #edcf72; color: #f9f6f2; font-size: 1.5rem; }
8.tzfe-tile.t256 { background: #edcc61; color: #f9f6f2; font-size: 1.5rem; }
9.tzfe-tile.t512 { background: #edc850; color: #f9f6f2; font-size: 1.5rem; }
10.tzfe-tile.t1024 { background: #edc53f; color: #f9f6f2; font-size: 1.2rem; }
11.tzfe-tile.t2048 { background: #edc22e; color: #f9f6f2; font-size: 1.2rem; }
2 和 4 使用深色文字,8 及以上使用白色文字。128 以上缩小字号以适配格子大小。
游戏结束覆盖层
游戏结束时显示半透明覆盖层和提示文字:
1.tzfe-overlay {
2 position: absolute;
3 inset: 0;
4 background: rgba(238, 228, 218, 0.73);
5 display: flex;
6 align-items: center;
7 justify-content: center;
8 border-radius: 8px;
9 z-index: 10;
10}
11.tzfe-overlay-msg {
12 font-size: 2rem;
13 font-weight: 800;
14 color: #776e65;
15}
分数与最高分
1// 更新最高分
2if (score > best) {
3 best = score;
4 localStorage.setItem('arcade-tzfe-best', best);
5}
6
7// 状态栏更新
8document.getElementById('atz-score').textContent = score;
9document.getElementById('atz-best').textContent = best;
总结
2048 的核心在于单行滑动合并算法的设计——通过反转和矩阵转置,四个方向都可以复用同一个 slideRow 函数。CSS Grid 渲染配合颜色分级系统提供了清晰的视觉反馈。
留言评论
期待你的想法评论加载中