2048小游戏
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26239525/article/details/82345363
研一时写的2048小游戏C++程序,程序中还有很多值得优化的地方,等以后有时间了再慢慢优化。
编程环境:Based on Qt 5.9.1 (MSVC 2015)。
Github:https://github.com/StayAI/2048
首先要了解2048的游戏规则:
-
游戏棋盘为四行四列,很容易想到用二维数组实现,开始时棋盘内随机出现两个数字,出现的数字仅可能为2或4。
-
玩家可以选择上下左右四个方向,若棋盘内的数字出现位移或合并,视为有效移动
-
玩家选择的方向上若有相同的数字则合并,每次有效移动可以同时合并,但不可以连续合并
-
合并所得的所有新生成数字想加即为该步的有效得分
-
玩家选择的方向行或列前方有空格则出现位移
-
每有效移动一步,棋盘的空位(无数字处)随机出现一个数字(依然可能为2或4)
-
棋盘被数字填满,无法进行有效移动,判负,游戏结束
-
棋盘上出现2048,判胜,游戏结束
然后总结2048游戏的关键步骤:
-
生成二维数组,并初始化:
int array; for (int i=0; i<4; i++) for (int j=0; j<4; j++) array[i][j] = 0;
-
棋盘内随机出现两个数字,出现的数字仅可能为2或4:
ex->randomNumber(array); ex->randomNumber(array);
-
判断是否有按键按下,如果有按键按下,需要判断此步是否为有效移动,如果是有效移动,那么进行合并运算:
-
判断是否为有效移动,需要先将移动之前的数组拷贝一遍,以便于之后作比较:
ex->copy(array);
-
然后判断按下按键方向,进行一系列的运算(主要为游戏规则的3、 4、 5步):
if (e->key() == Qt::Key_W || e->key() == Qt::Key_Up) { ex->calculateArrayUp(array); } if (e->key() == Qt::Key_S || e->key() == Qt::Key_Down) { ex->calculateArrayDown(array); } if (e->key() == Qt::Key_A || e->key() == Qt::Key_Left) { ex->calculateArrayLeft(array); } if (e->key() == Qt::Key_D || e->key() == Qt::Key_Right) { ex->calculateArrayRight(array); }
-
判断是否为有效移动,如果是有效移动,则棋盘上随机生成数字(游戏规则6):
if ( ex->isChange(array) ) { ex->generateNumber(array); }
-
更新显示:
showArray(array);
-
-
判断棋盘是否填满,游戏结束。
ex->isGameOver(array);
-
判断棋盘上是否出现2048,游戏胜利。
ex->isSuccess(array);
给出具体代码的实现:
-
判断数字是否为有效移动:
void _2048::copy(int array[][4])//复制数组 { for (int i=0; i<4; i++) for (int j=0; j<4; j++) array1[i][j] = array[i][j]; } bool _2048::isChange(int array[][4])//判断数组是否改变 { bool change = false; for (int i=0; i<4; i++) for (int j=0; j<4; j++) if (array1[i][j] != array[i][j]) { array1[i][j] = array[i][j]; change = true; } return change; }
-
生成随机数字2或4(2和4出现的频率比是4:1):
void _2048::randomNumber(int array[][4]) { int t; qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); t = qrand()%16; while ( array[t/4][t%4] != 0) { t = qrand()%16; } int seed[7] = {2, 2, 2, 2, 2, 2, 4}; array[t/4][t%4] = seed[qrand()%7]; }
-
如果棋盘上未满,就生成数字:
void _2048::generateNumber(int array[][4]) { int num = 0; for (int i=0; i<4; i++) for (int j=0; j<4; j++) if (array[i][j] != 0) num++; if (num != 16) { this->randomNumber(array); } }
-
判断游戏结束:
void _2048::isGameOver(int array[][4]) { int num = 0; for (int i=0; i<4; i++) for (int j=0; j<4; j++) if (array[i][j] != 0) num++; else return; if (num == 16) { for(int i=0; i<4; i++) for(int j=0; j<3; j++) if (array[i][j] == array[i][j+1]) return; for(int i=0; i<3; i++) for(int j=0; j<4; j++) if (array[i][j] == array[i+1][j]) return; qDebug() << "GameOver"; } }
-
判断游戏胜利:
void _2048::isSuccess(int array[][4]) { for (int i=0; i<4; i++) for (int j=0; j<4; j++) if (array[i][j] == 2048) qDebug() << "Success"; }
-
执行具体的操作运算(只给出一个方向上的,其他方向类似):
注:这个函数比较复杂,主要就是进行运算,感兴趣的拿着纸笔一点一点的算吧。
void _2048::calculateArrayLeft(int array[][4]) { for (int i=0; i<4; i++) { int temp[4] = {0, 0, 0, 0}; int m = 0; for (int j=0; j<4; j++) { if (array[i][j] != 0) temp[m++] = array[i][j]; } for (int j=0; j<4; j++) { array[i][j] = temp[j]; temp[j] = 0; } for (int j=0; j<3; j++) { if ( (array[i][j] == array[i][j+1]) && array[i][j]!=0 ) { array[i][j] *= 2; this->score += array[i][j]; for (int k=j+1; k<3; k++) { array[i][k] = array[i][k+1]; } array[i][3] = 0; break; } } } }
游戏界面:
最好成绩BEST懒得写了,所以一直显示为0。
欢迎交流