2048 游戏结束判定:棋盘满了,还要看相邻格
做 2048 时,一个很容易写错的条件是“16 个格子都不为空,就显示游戏结束”。满格只说明没有空位;只要相邻的两个数字相同,玩家仍能通过合并继续玩。我检查了自己的单文件游戏《2048·数字漫游》,并在本地页面构造棋盘,核对了判断函数、页面提示和无效移动的行为。
这个版本把棋盘按行放进长度为 16 的数组。canMove 的规则只有三条:存在空格、同一行的右侧邻格相等,或同一列的下方邻格相等。只要其中一条成立,就还能继续。
function canMove(source) {
return source.some(v => v === 0) || source.some((v, i) =>
(i % 4 < 3 && v === source[i + 1]) ||
(i < 12 && v === source[i + 4])
);
}
这里的边界值得单独检查。i % 4 < 3 阻止把一行末尾和下一行开头误认成水平邻居;i < 12 阻止最后一行继续向下取值。两处比较只看右方和下方,是因为左方、上方的相邻关系会在遍历其他格子时覆盖。
我在 Edge 打开本地 HTML,把棋盘临时设成四种状态,再调用页面原有的 render()。结果如下:
| 棋盘状态 | canMove |
页面结束提示 |
|---|---|---|
| 2、4 交错排列的满盘,无相邻相同数字 | false |
显示“本局结束” |
| 满盘,第一行有一组水平相邻的 2 | true |
不显示结束 |
| 满盘,第一列有一组垂直相邻的 2 | true |
不显示结束 |
| 留一个空格 | true |
不显示结束 |
交错满盘还有一个容易漏掉的细节:第一行末尾与第二行开头恰好都是 4,但它们隔着行边界,并不是相邻格。实际测试中该棋盘的四个方向都没有变化,canMove 正确返回 false。如果去掉取模的边界条件,这类棋盘就可能被错判为仍可合并。
我又在这个结束状态下尝试向左移动。页面保持 16 个格子和 128 分不变,结束提示仍在,“撤销一步”保持禁用。原因是 move() 先检查 nextBoard() 的 changed;没有变化便直接返回,不会生成新数字,也不会覆盖撤销快照。这样游戏结束后的方向键不会偷偷改变状态。
这组检查只覆盖了我手工构造的棋盘和本地浏览器页面,没有穷举所有可能局面,也没有修改已发布作品。它给我的实际启发是:对这类棋盘游戏,测试“满但能合并”“满且不能合并”和“有空位”三类状态,比只测试正常开局更容易发现边界错误。
- 点赞
- 收藏
- 关注作者
评论(0)