一.废话不多说,直接上代码。
(不懂游戏规则,可以自行查阅^_^)
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <conio.h> #define N 4 //定义阶数 #define up 72 //键盘上键 #define down 80 //键盘下键 #define left 75 //键盘左键 #define right 77 //键盘右键 #define esc 27 //键盘esc键 //产生n个随机数 void Random(int *data, int n) { for(int i = 0; i<n; i++) { data[i] = rand()%N; } } //初始化游戏,随机生成两个数字方块 void initGame(int data[N][N], int num) { int a[4]; while(1) { Random(a, 4); //产生两个坐标 //如果坐标不重合,就退出 if(a[0] != a[2] && a[1] != a[3]) { data[a[0]][a[1]] = num; data[a[2]][a[3]] = num; break; } } } //判断是否还有空位 int checkSpace(int data[N][N]) { int i, j, n; n = 0; for(i = 0; i<N; i++) { for(j = 0; j<N; j++) { if(!data[i][j]) //还有空位 { n++; } } } return n; } //选择一个空坐标,生成数字 void produceXY(int data[N][N], int num) { int i, j, flag, a[2]; flag = checkSpace(data); if(!flag) //如果没有空位就不用产生数字 { return; } while(1) //一定可以找到空位并产生数字 { flag = 0; Random(a, 2); //随机产生一个坐标 for(i = 0; i<N; i++) { for(j = 0; j<N; j++) //尝试找出一个空坐标 { if(data[i][j] == 0 && a[0] == i && a[1] == j) { data[a[0]][a[1]] = num; //成功找到空坐标 return; } } } } } //有空位就向左移动 void pushLeft(int data[N]) { int i, j = 0; for (i = 0; i < N; i++) { if (data[i] != 0) { data[j] = data[i]; //每个位都要判断一次 j++; } } //将左移后的产生的新空位标识出来 for(;j<N;j++) { data[j] = 0; } } //复制二维数组,方便旋转 void copyData(int data[N][N], int tmp[N][N]) { int i, j; for(i = 0; i<N; i++) { for(j = 0; j<N; j++) { tmp[i][j] = data[i][j]; } } } //将游戏界面顺时针旋转90°*count, count表示旋转次数 void rotateMatrix(int data[N][N], int count) { int i, j, tmp[N][N]; while(count) { copyData(data, tmp); for(i = 0; i<N; i++) { for(j = 0; j<N; j++) { data[i][j] = tmp[N-j-1][i]; } } count--; } } //向左合并 int mergeLeft(int data[N][N]) { int i, j, flag; flag = 0; //假设不能向左合并 for(i = 0; i<N; i++) { pushLeft(data[i]); for(j = 0; j<N-1; j++) { if(data[i][j] == data[i][j+1]) //找到相等的就左右合并 { flag = 1; //有合并过就可以继续游戏 data[i][j] += data[i][j]; data[i][j+1] = 0; //标记空位 pushLeft(data[i]); //重新有空位就左移 } } } return flag; //返回标记值 } //向右合并 int mergeRight(int data[N][N]) { int flag = 0; rotateMatrix(data, 2); //将游戏界面先顺时针旋转180° flag = mergeLeft(data); //向左合并 rotateMatrix(data, 2); //还原游戏界面,顺时针旋转180° return flag; } //向上合并 int mergeUp(int data[N][N]) { int flag = 0; rotateMatrix(data, 3); //将游戏界面先顺时针旋转270° flag = mergeLeft(data); //向左合并 rotateMatrix(data, 1); //还原游戏界面,顺时针旋转90° return flag; } //向下合并 int mergeDown(int data[N][N]) { int flag = 0; rotateMatrix(data, 1); //将游戏界面先顺时针旋转90° flag = mergeLeft(data); //向左合并 rotateMatrix(data, 3); //还原游戏界面,顺时针旋转270° return flag; } //检查是否能继续游戏 int check(int data[N][N]) { int i, j, n; for(i = 0; i<N; i++) { for(j = 0; j<N; j++) { if(data[i][j] == 2048) //如果等于2048, 游戏胜利 { return 2; } } } n = checkSpace(data); if(n) //如果还有空位就可以继续游戏 { return 1; } n = 0; //如果没有空位, 但是还可以合并, 也可以继续游戏 for(i = 0; i<N; i++) { for(j = 0; j<N-1; j++) { if(data[i][j]==data[i][j+1] || data[j][i] == data[j+1][i]) { n++; //存在左右数字相等或者上下数字相等情况,可以继续游戏 } } } if(n) { return 1; } return 0; } //显示游戏界面 void show(int data[N][N]) { printf("\n\t2048小游戏"); for (int i = 0; i < N; i++) { printf("\n|______|______|______|______|\n|"); for (int j = 0; j < N; j++) { if (data[i][j] == 0) { printf("%5c |", ' '); } else { printf("%5d |", data[i][j]); } } } printf("\n|______|______|______|______|\n"); } int main(void) { char ch; int win; srand(time(0)); int data[N][N] = {0}; //游戏界面初始数据 initGame(data, 2); while(1) { show(data); win = check(data); //检查能否继续游戏 if(win == 0) { printf("游戏结束\n"); return 0; } if(win == 2) { printf("恭喜你,胜利了\n"); return 0; } ch = getch(); //获取一个字符,不回显 switch(ch) { case up: //上移 mergeUp(data); produceXY(data, 2); break; case down: //下移 mergeDown(data); produceXY(data, 2); break; case left: //左移 mergeLeft(data); produceXY(data, 2); break; case right: //右移 mergeRight(data); produceXY(data, 2); break; case esc: printf("2048小游戏不是这么简单的哦\n"); return 0; } system("cls"); //每次按键后,清屏,然后显示新的游戏界面 } return 0; }
游戏截图
二.代码分析
相信认真看完我的代码注释的小伙伴,一定感慨,老夫活这么久,查阅代码无数,从未见有如此注释简单,清晰的代码(说笑^_^),之所以写这么详细,是因为查代码的小伙伴很大程度上不会写,或者自己写的时候出bug,不知道哪里错了,想看看人家的,但是网上一找,发现,全部在讲原理,或者代码根本没有什么关键的注释,看完以后,一头雾水。所有博主特意写下这篇博客,来赠予友猿人。
这里重点介绍一下,合并的方法。可以看到,我的代码非常简洁,把右移,上移和下移操作等全部转化为左移操作了,节省了不少(这里采用了数学的转化与化归思想和空间想象力)。右移,相当于先把游戏界面顺时针旋转180°,然后左移,然后再把游戏界面顺时针旋转180°,还原。上移和下移是同样的逻辑,当然也可以逆时针旋转,这里不展开。
所以关键步骤变化为,如何左移。首先左移可以分解为两个步骤。第一步,每一行整体左移,遇到空位(这里用数字0表示),直接跳过,直到碰到非零数字,最终结果是,每一行的所有数字都紧紧挨一起,留下几个空位或者这行全空(都是数字0)。第二步,合并左右相同的数字,当合并了一个数字后,要重新整体左移,因为刚才合并时,右边的数字已经没有意义了,需要被下一个数字覆盖,所有要整体左移。循环这步,直到不能合并结束(找不到左右相同的数字)。
其他的部分,应该都挺好理解的,代码也有注释,这里就不一一讲解了。对了,这里用到了一些特殊函数,system("cls"),用来清屏的,类似Linux下在终端输入clear。还有一个getch(),是用来获取一个字符,并且不回显的(头文件conio.h),当然你回显也没有问题,因为每次移动后都清屏,然后重新显示游戏界面。
三.总结
本次游戏,在算法方面每怎么优化,小伙伴可以自行尝试一下。好了,本期的小游戏分享就到这里了,以后会不定期更新,更多好玩的,可以在左边的专栏里慢慢玩,毕竟可以白嫖(^_^)。
文章来源地址https://www.toymoban.com/news/detail-485294.html文章来源:https://www.toymoban.com/news/detail-485294.html
到了这里,关于C语言版---2048小游戏,简单易懂,看过就会的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!