恭喜你打开了我们的第5篇文章
下午四点,我已经在南草坪坐下了。点了杯饮料,打开微信,发现上个星期一同学问我的编程问题到现在都还没回复。于是我打开电脑,决定帮他改改程序。下午五点钟,改完程序的我在咖啡厅伸了个懒腰。寻思着距离吃饭还有一段时间,我打开百度,搜起了“有什么简单好玩的小游戏?”于是,四个数字——2048映入眼帘……
一、前言
(1)什么是2048?
2048是一个数字游戏,在4*4的方格上有初始的随机数字1或2,每次玩家可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢,相同数字的方块在靠拢、相撞时会相加,系统也会在空白的地方乱数出现一个随机数字1或2。不断的叠加最终屏幕上若存在一个方格拼凑出2048这个数字就算成功。[1]
例如:
上图是一张初始情况的图片,当执行向右滑动时,表格变为:
所有的1都移到了表格最右边,然后随机在0的部分产生新的数字0或1。此时如果执行上滑动,则表格变为:
可以看到,右上角出现了4和2,这分别是2+2和1+1的结果。以此类推,当屏幕上出现数字2048时,游戏即算成功。
在本文所展示的游戏中,并没有引入“成功”这一个概念,本文所指的2048游戏分数多多益善,上不封顶,直到屏幕上执行上下左右操作都不能改变表格的数字时,即玩家失败。
(2)阅读这篇文章你需要什么知识水平?
本文和上一篇文章不一样,需要一定的C语言或C++语言基础,但是如果你没有语言基础也没有关系,你仍然可以看下去。本文在文末部分附上了源代码的获取方法,读者可以自行获取。
二、核心处理
最重要的处理莫过于:当我们执行上下左右其中一个操作的时候,我们的表格该怎么改变。观察到上下左右处理具有高度一致性,我们不妨举向右滑动的操作作为例子,其他操作是相似的,读者不难自行实现,本文就不再赘述。
(1)最初的思考
观察到对整个表格的处理可以分解为对每一行的处理,而对每一行的处理是相似的。此处我们假设正在处理第i行,那么其他行依照下面的方式可以同样处理。
在第i行中,我们需要:
· 把所有的数字移到最右边
· 将相同的数字相加,并把结果保存在右边的格子,然后把左边的格子数字变为0.
我们很容易想到我们可以从左向右相加,如果碰到第j个数和第j+1个数相等,那么就把他们相加,并把结果储存到第j+1个数;如果第j个数不是0,可是第j+1个数是0,那就把这两个数交换。
但是这是一种优秀的解决方案吗?显然并不是。我们看下面的例子:
可以看到,依照我们上面的方法,在处理三个连续的数字时并不可行,导致的问题有两个:
· 所有数字并没有紧凑地排列到表格右边
· 2在1的左边,可是我们期望2在表格的最右边。
对于第一个问题,是容易解决的。只要再次执行上述步骤即可。而第二个问题解决方法就要用到下文所述的方案了。
(2)一种可行的解决方案
我们大可改变思路,既然执行向右操作的时候不能从左往右执行,那么能不能从右往左执行呢?事实证明,从右往左执行的方法是完全正确的。我们依照从右往左的方向,依旧是依照(1)中所述的方法操作,即:
· 把所有的数字移到最右边
· 将相同的数字相加,并把结果保存在右边的格子,然后把左边的格子数字变为0.
我们可以举一个例子,请看下图:
这样,我们就解决了(1)中的第二个问题,那么(1)中第一个问题的解决方案也很简单,只要再次执行上述步骤就可以了。
到现在为止,我们已经知道了当用户执行上下左右其中之一的操作时如何处理了,以右为例,当用户执行右操作时,程序需要:
· 从右往左两两判断,如果相邻的两个数相同,那么就把他们相加并把结果返回右边的格子;
· 如果右边的格子没有填写而左边的格子填写了,就把他们交换。
· 重复上述步骤,直到执行上述步骤时对表格没有任何操作为止。
三、细节处理
(1)如何在键盘上接收上下左右?
从键盘上接受上下左右,需要载入
上:72
下:80
左:75
右:77
输入时用函数getch()来获取输入内容。getch()的主要优势是可以不需要用户按下回车键即得到用户当前输入的字符。例如,我们可以利用下面的代码来解释这一过程:
void control()
{
char ch;
again:
if (_getch()==224)
{
ch=_getch();
if (ch==left)
cout"left";
else if (ch==right)
cout"right";
else if (ch==up)
cout"up";
else if (ch==down)
cout"down";
}
else
goto again;
}
在这段代码里面,用户输入其他字符是没有反应的,而当用户按下上下左右按钮时,屏幕就会显示用户按下的是哪一个按钮。[2]
(2)如何刷新输出内容?
与其说刷新输出内容,不如我们说清空屏幕内容重新输出,可以调用
system("cls");
(3)如何设置随机数?
C/C++语言中没有随机数函数random,但是我们仍然可以产生随机数。以下代码是产生随机数的一个方法,它的作用是产生一个1~100的随机数。
using namespace std;
int main()
{
int i;
srand((int)(time(0)));
i=random(100); //Produce an integer from 1 to 100;
coutendl;
return 0;
}
如果要改变产生随机数的范围,只要把第11行括号中的内容改为你需要的数就可以了。
(4)如何设置计时器?
我们可以调用
“在头文件time.h中,clock()函数返回从“开启这个程序进程”到“程序中调用clock()函数”时之间的CPU时钟计时单元(clock tick)数,在MSDN中称之为挂钟时间(wal-clock),常量CLOCKS_PER_SEC,它用来表示一秒钟会有多少个时钟计时单元,精确到毫秒,其使用方法如下:”
int main()
{
double dur;
clock_t start,end;
start = clock();
foo();//dosomething
end = clock();
dur = (double)(end - start);
printf("Use Time:%f ",(dur/CLOCKS_PER_SEC));
}
[3]
四、代码实现
我们需要分别写出上下左右操作的具体步骤,除此之外,我们还需要:
· 输出数据
· 检查表格是否已经填满
· 产生随机数,填到空格上
· 检查是否上下左右操作表格都没有任何变化
那么,主函数要做的事情就非常明晰了:
如果还没失败,那就:
· 在空格上填入随机数
· 输出
· 用户输入上下左右,并且更新表格
具体的代码由于篇幅有限,读者可以关注我们,后台回复“2048”获取源代码。
五、后记
于是,我就兴奋地玩起了游戏,直到发现情况越来越不对劲:
参考文献
[1]https://baike.百度.com/item/2048/13383511
[2] http://www.myexception.cn/c/336441.html
[3] https://www.cnblogs.com/chmm/p/7461684.html