2048数字游戏玩法与核心算法详解:从规则到胜利策略
《2048》是最近较为流行的一款数字游戏。原版 2048 最先在 github 上予以发布,其原作者是 Gabriele Cirulli。它是以《1024》以及《小 3 传奇》(Threes!)的玩法为基础而开发出来的新型数字游戏。

游戏规则
游戏规则简单。你要控制所有方块朝同一个方向运动。两个相同数字的方块相撞后会合并为它们的和。每次操作后,空白方格处会随机生成一个 2 或者 4,且生成 2 的概率较大。最终得到一个“2048”的方块即为胜利。
核心算法
1、方块移动和合并算法
主要思想是将游戏数字面板进行抽象处理,把它看作是一个 4 行 4 列的二维数组 a[4][4]。其中,值为 0 的位置代表空方块,其他位置则表示对应的数字方块。对于每一行,都将其同等看待,只专注于研究这一行的移动和合并算法。之后,就可以通过遍历所有行的方式来实现整个游戏中所有行的移动合并算法。在一行中,用 b[4] 来表示一行的一位数组。通过使用两个下标变量来遍历列项,这里分别使用 j 和 k 。j 总是在 k 的后面,其作用是寻找 k 项后面第一个不为 0 的数字。而 k 项则用于表示当前待比较的项,它总是和 j 项之间隔着若干个数字 0 ,或者干脆紧挨着。考虑往左滑动时,一般情况下,初始情形下 j 为 1,k 为 0。接着判断 j 项数字是否大于 0。如果大于 0,就判断 j 项和 k 项数字的关系,有 3 种情况,分别是 P1:、P2:b[k]等于 0 以及 P3:b[k]不等于 0 且 b[k]不等于 b[j];如果不大于 0,j 就自加 1,然后继续寻找 k 项后面第一个不为 0 的数字。其中P1,P2和P3分别对应如下:
如果 b[k] 等于 b[j],那么 b[k] 就变为 2 乘以 b[k](意味着两数进行了合并),同时 b[j] 变为 0(合并之后要把残留的 j 项值清除为 0),接着让 k 自增 1,之后开始下一次循环。
如果 b[k] == 0,这意味着 b[j] 之前全是空格子。此时,直接把 b[j] 移动到 k 的位置,即 b[k] = b[j]。接着,将 b[j] 的值清零,也就是 b[j] = 0(移动后将残留的 j 项值清零)。然后,k 的值保持不变。之后,进行下一次循环。
如果 b[k]不等于 0 且 b[k]不等于 b[j],这就意味着这两个数不相等且都不为 0。在这种情况下,将这两个数靠在一起,也就是让 b[k + 1]等于 b[j]。接着有两种小情况,一是如果 j 不等于 k + 1,那么就将 b[j]设为 0(移动后把残留的 j 项值清除为 0);二是如果 j 等于 k + 1,那就表示这两个数原先就靠在一起,此时不需要进行特殊处理(就如同没有移动一样)。接着k自加1,然后进行下一次循环。
2、判断游戏是否结束算法
核心思想是遍历二维数组,去查看是否有横向以及纵向两个相邻的元素是相等的。如果存在这样的情况,那么游戏就不会结束;如果不存在,那么游戏就结束。
3、生成随机数算法
核心思想是依据生成的随机数,对特定的值进行取模操作,以此来生成具有一定概率的数。在本游戏里,设定出现 2 的概率是出现 4 的概率的两倍。这样就可以借助系统提供的随机数函数生成一个数,接着对 3 取余。当得到的数小于 2 时,就在游戏面板的空格处生成一个 2;当余数等于 2 时,就生成 4。选择在哪个空格出生成数时,会依据系统提供的随机函数生成一个数,接着用这个数对空格数取余,最后在余数对应的第几个空格生成数字。
4、绘制界面的算法
核心思想:借助系统所提供的控制台界面的清屏功能,以实现刷新界面的目的;通过对制表符位置进行控制,从而达成绘制游戏数字面板的效果。
绘制界面并非本游戏的本质,并且代码段比较长,因此算法描述在此处被省略,读者能够参考完整的源代码。
源码示例:
#include
#include /* 包含设定随机数种子所需要的time()函数 */
#include 在 Windows 平台上,有一个 getch()函数,它能完成输入字符且不带回显,同时也不需要回车确认。
#include 在 Windows 平台上,有一个函数能够完成设定输出光标位置的操作,并且通过这个操作可以达到清屏的功能。
void start_game(); /* 开始游戏 */
void reset_game(); /* 重置游戏 */
/* 往左右上下四个方向移动 */
void move_left();
void move_right();
void move_up();
void move_down();
刷新界面显示的操作。
生成随机数,在本程序中仅生成 2 或 4,且概率之比设为 2:1,通过函数 void add_rand_num()来实现。
void check_game_over(