1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > C++复原2048小游戏(纯文字)

C++复原2048小游戏(纯文字)

时间:2022-06-26 11:49:32

相关推荐

C++复原2048小游戏(纯文字)

2048可谓是一款十分经典的小游戏,在智能手机刚刚起步时风靡全球,所要求的算法也不是很难。我花了两天时间复刻了2048,在此和大家分享一下。

首先,游戏要有一个4×4的界面。因此我选择定义了一个Game类,类的public访问权限里有int类型的4×4的二维数组,到时可以通过Game类操作这个数组。

class Game {public:int board[4][4];};

接着是几个功能需要满足。

1.判断4×4的数组是否装满。

2.判断游戏是否结束。

3.判断玩家是否获胜。

4.判断数组里面的元素可不可以移动。

5.移动数组里面的元素。

6.判断数组里面的相邻元素是否可以合并(也就是是否相等)。

7.合并相邻元素。

8.用函数把移动和合并元素封装成一次操作。

9.生成随机数。

10.输出数组里的每个元素。

11.判断是否获胜或结束。

接下来一个个实现这些功能。

1.判断4×4的数组是否装满。

运用嵌套循环访问数组里每个元素,如果有0(空元素)就返回false,都没有就返回true。

bool full(Game game) {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {return false;}}}return true;}

2.判断游戏是否结束。

运用刚才写的判断满没满的函数,如果没满的话,就没输,返回false,满了就接着进行判断:如果相邻元素没有一样的,返回true,反之返回false。

也就是说,对于board[i][j],只要board[i + 1][j],board[i - 1][j],board[i][j + 1],board[i][j - 1]中的任意一个和它相等,游戏都可以继续下去。

问题是,i的取值范围是0i3,0j3,因此 i 1和 j1可能超出数组的索引范围,也就会出现一些bug。

因此我们如果要解决这个问题,就是要找到两个函数。

其中一个是,当x = 0时,f(x) = x + 1;当x = 1或2或3时,f(x) = x - 1。

另一个是,当x = 3时,f(x) = x - 1;当x = 0或1或2时,f(x) = x + 1。

第一个好解决,瞬间想到 f(x) = | x - 1 |。

第二个稍微麻烦点,但经过我的不懈努力,我找到了它。f(x) = 3 - | x - 2 |

但是C++并没有内置的绝对值,因此要函数实现。

//int 的绝对值int abs(int a) {return a >= 0 ? a : a * -1;}

(三目运算符使代码更加简洁)

接下来的事就好办了,依次判断board[abs(i - 1)][j],board[3 - abs(i - 2)][j],board[i][abs(j - 1)],board[i][3 - abs(j - 2)]和board[i][j]是否相等,有一个相等就返回false,全不相等就移至下一个元素进行判断。

bool over(Game game) {if (!full(game)) {return false;}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[abs(i - 1)][j] == game.board[i][j]) {return false;}else if (game.board[3 - abs(i - 2)][j] == game.board[i][j]) {return false;}else if (game.board[i][abs(j - 1)] == game.board[i][j]) {return false;}else if (game.board[i][3 - abs(j - 2)] == game.board[i][j]) {return false;}}}return true;}}

3.判断玩家是否获胜。

只要有一个元素是2048,玩家就获胜;全都不是2048,游戏就继续。

运用嵌套循环访问数组里每个元素,如果有2048就返回true,都没有就返回false。

bool win(Game game) {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 2048) {return true;}}}return false;}

4.判断数组里面的元素可不可以移动。

就W(向上)而言,运用嵌套循环访问数组里每个元素,如果有是0的就从该元素开始,依次看它下面的每一个元素是否有不为0的数字。如果有,说明这些不为0的数字头顶上是空的,因此可以沿W(向上)移动,返回true;反之,如果没有,就访问下一个元素,直到找到符合条件的元素为止。

如果循环结束(全部访问完)都没有符合条件的元素,说明都移动不了,返回false。

if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k < 3; k++) {if (game.board[k + 1][j] != 0) {return true;}}}}}return false;}

事实上,元素只需要访问三排四列,因为第四排的元素即使是零,它下面(第五排)也不可能有数字可以移动,所以没有访问第四排的必要。

以此类推,A,S,D的代码也可以写出来。

else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j] == 0) {for (int k = j; k < 3; k++) {if (game.board[i][k + 1] != 0) {return true;}}}}}return false;}else if (input == 'S' || input == 's') {for (int i = 3; i > 0; i--) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k > 0; k--) {if (game.board[k - 1][j] != 0) {return true;}}}}}return false;}else {for (int i = 0; i < 4; i++) {for (int j = 3; j > 0; j--) {if (game.board[i][j] == 0) {for (int k = j; k > 0; k--) {if (game.board[i][k - 1] != 0) {return true;}}}}}return false;}

所以判断函数代码如下:

bool moveAble(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k < 3; k++) {if (game.board[k + 1][j] != 0) {return true;}}}}}return false;}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j] == 0) {for (int k = j; k < 3; k++) {if (game.board[i][k + 1] != 0) {return true;}}}}}return false;}else if (input == 'S' || input == 's') {for (int i = 3; i > 0; i--) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k > 0; k--) {if (game.board[k - 1][j] != 0) {return true;}}}}}return false;}else {for (int i = 0; i < 4; i++) {for (int j = 3; j > 0; j--) {if (game.board[i][j] == 0) {for (int k = j; k > 0; k--) {if (game.board[i][k - 1] != 0) {return true;}}}}}return false;}}

5.移动数组里面的元素。

照之前的思路,只要找到符合条件的元素(本身为0,移动方向的反方向有不为0的数字),就要进行移动。

这里为了简便,函数调用时,从符合条件的元素开始到数组边缘,整体只需要移动一格,到调用时多调几次就可以一移到底。

if (game.board[i][j] == 0 && game.board[i + 1][j] != 0) {for (int k = i; k < 3; k++) {int temp = game.board[k][j];game.board[k][j] = game.board[k + 1][j];game.board[k + 1][j] = temp;}}

函数如下:

Game move(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0 && game.board[i + 1][j] != 0) {for (int k = i; k < 3; k++) {int temp = game.board[k][j];game.board[k][j] = game.board[k + 1][j];game.board[k + 1][j] = temp;}}}}}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j] == 0 && game.board[i][j + 1] != 0) {for (int k = j; k < 3; k++) {int temp = game.board[i][k];game.board[i][k] = game.board[i][k + 1];game.board[i][k + 1] = temp;}}}}}else if (input == 'S' || input == 's') {for (int i = 3; i > 0; i--) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0 && game.board[i - 1][j] != 0) {for (int k = i; k > 0; k--) {int temp = game.board[k][j];game.board[k][j] = game.board[k - 1][j];game.board[k - 1][j] = temp;}}}}}else {for (int i = 0; i < 4; i++) {for (int j = 3; j > 0; j--) {if (game.board[i][j] == 0 && game.board[i][j - 1] != 0) {for (int k = j; k > 0; k--) {int temp = game.board[i][k];game.board[i][k] = game.board[i][k - 1];game.board[i][k - 1] = temp;}}}}}return game;}

6.判断数组里面的相邻元素是否可以合并(也就是是否相等)。

如果输入是W或S的话,就上下判断;如果输入是A或D的话,就左右判断。

依然使用嵌套循环访问每一个元素。

代码如下:

bool combineAble(Game game, char input) {if (input == 'W' || input == 'w' || input == 'S' || input == 's') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {return true;}}}return false;}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {return true;}}}return false;}}

7.合并相邻元素。

为了简便,函数还是设计只合并一次的,到时多调几次。

拿W举例,对于board[i][j],如果board[i][j] =board[i + 1][j],两个元素上下方向相等,就可以进行合并。

这里有个坑,我就掉进去过:一定要注意,game.board[i + 1][j] !=0也是个条件,因为刚开始时,全盘都是0,程序就会觉得:“天哪,这么多相等的0,我该合并到猴年马月!”就会一直合并下去。我花了很大劲儿才发现错出在哪里。

Game combine(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j] += game.board[i + 1][j];game.board[i + 1][j] = 0;}}}}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j] += game.board[i][j + 1];game.board[i][j + 1] = 0;}}}}else if (input == 'S' || input == 's') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {game.board[i + 1][j] += game.board[i][j];game.board[i][j] = 0;}}}}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j + 1] += game.board[i][j];game.board[i][j] = 0;}}}}return game;}

8.用函数把移动和合并元素封装成一次操作。

首先判断是不是既不能合并也不能移动。如果是的话,不处理直接返回;如果不是,先合并一次,避免出现意外情况。

接着在死循环里面套两个循环,第一个循环的条件是可不可以合并,循环体是合并(也就是能合并就一直合并);第一个循环的条件是可不可以移动,循环体是移动(也就是能移动就一直移动)。跳出死循环的条件是既不能合并也不能移动。

最后返回处理过的数据。

Game sort(Game game, char input) {if (!combineAble(game, input) && !moveAble(game, input)) {return game;}game = combine(game, input);while (true) {while (combineAble(game, input)) {game = combine(game, input);}while (moveAble(game, input)) {game = move(game, input);}if (!combineAble(game, input) && !moveAble(game, input)) {break;}}return game;}

9.生成随机数。

首先判断4×4的数组是不是装满了数字。

如果是,就不用生成,直接原路返回;如果不是,随机找个位置放2或4,找的位置必须还是空的。

因此设计一个循环,如果找的位置不是空,就再随机找一个位置,直到找的位置为空为止。

2或4的随机生成方法:rand() % 2生成0或1,加一后rand() % 2 + 1生成1或2,乘二后2 * (rand() % 2 + 1)生成2或4。

Game random(Game game) {srand((unsigned int)time(NULL));if (!full(game)) {//如果没满//rand() % 4 :0 到 3 之间的随机数int i = rand() % 4;int j = rand() % 4;while (game.board[i][j] != 0) {i = rand() % 4;j = rand() % 4;}game.board[i][j] = 2 * (rand() % 2 + 1); //2*(0+1)~2*(1+1)return game;}else {//如果满了return game;}}

10.输出数组里的每个元素。

我们肯定不能直接输出,那样太丑了。适当的美化是必要的。

每个元素高三排(不包含上下两根线)。

因此可以再来个嵌套循环,一排执行四次,一共执行四排。

第一排是"|-------|-------|-------|-------|",在循环外输出。

每个大循环下,第一排是五根竖着的线,第二排是五根竖着的线加不为0的元素,第三排又是五根竖着的线,第四排是"|-------|-------|-------|-------|"。

代码如下:

void printBoard(Game game) {cout << "|-------|-------|-------|-------|" << endl;for (int i = 0; i < 4; i++) {for (int i = 0; i < 4; i++) {cout << "|" << "\t";}cout << "|" << endl;for (int j = 0; j < 4; j++) {cout << "|";if (game.board[i][j] != 0) {cout << game.board[i][j];}cout << "\t";}cout << "|";cout << endl;for (int i = 0; i < 4; i++) {cout << "|" << "\t";}cout << "|" << endl;cout << "|-------|-------|-------|-------|";cout << endl;}cout << endl << endl;}

11.判断是否获胜或结束。

该函数应该在main函数里。

同样的,设计一个死循环,跳出的条件是赢或输。

如果没有达成条件的话,循环重复执行 提示输入→输入→合并和移动→生成随机数→清屏→打印→判断。

代码如下:

while (1) {cout << "请输入你想要采取的操作:";cin >> input;game = sort(game, input);if (!full(game)) {game = random(game);}system("cls");printBoard(game);if (over(game) == true) {cout << "Game over!" << endl;break;}else if (win(game) == true) {cout << "You win!" << endl;break;}}

至此,所有功能都已实现。所以……

源代码如下:

#include<iostream>#include<ctime>using namespace std;class Game {public:int board[4][4];};//int 的绝对值int abs(int a) {return a >= 0 ? a : a * -1;}//满了bool full(Game game) {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {return false;}}}return true;}//游戏结束bool over(Game game) {if (!full(game)) {return false;}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[abs(i - 1)][j] == game.board[i][j]) {return false;}else if (game.board[3 - abs(i - 2)][j] == game.board[i][j]) {return false;}else if (game.board[i][abs(j - 1)] == game.board[i][j]) {return false;}else if (game.board[i][3 - abs(j - 2)] == game.board[i][j]) {return false;}}}return true;}}//玩家获胜bool win(Game game) {for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 2048) {return true;}}}return false;}//可不可以移动bool moveAble(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k < 3; k++) {if (game.board[k + 1][j] != 0) {return true;}}}}}return false;}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j] == 0) {for (int k = j; k < 3; k++) {if (game.board[i][k + 1] != 0) {return true;}}}}}return false;}else if (input == 'S' || input == 's') {for (int i = 3; i > 0; i--) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0) {for (int k = i; k > 0; k--) {if (game.board[k - 1][j] != 0) {return true;}}}}}return false;}else {for (int i = 0; i < 4; i++) {for (int j = 3; j > 0; j--) {if (game.board[i][j] == 0) {for (int k = j; k > 0; k--) {if (game.board[i][k - 1] != 0) {return true;}}}}}return false;}}//移动一次Game move(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0 && game.board[i + 1][j] != 0) {for (int k = i; k < 3; k++) {int temp = game.board[k][j];game.board[k][j] = game.board[k + 1][j];game.board[k + 1][j] = temp;}}}}}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j] == 0 && game.board[i][j + 1] != 0) {for (int k = j; k < 3; k++) {int temp = game.board[i][k];game.board[i][k] = game.board[i][k + 1];game.board[i][k + 1] = temp;}}}}}else if (input == 'S' || input == 's') {for (int i = 3; i > 0; i--) {for (int j = 0; j < 4; j++) {if (game.board[i][j] == 0 && game.board[i - 1][j] != 0) {for (int k = i; k > 0; k--) {int temp = game.board[k][j];game.board[k][j] = game.board[k - 1][j];game.board[k - 1][j] = temp;}}}}}else {for (int i = 0; i < 4; i++) {for (int j = 3; j > 0; j--) {if (game.board[i][j] == 0 && game.board[i][j - 1] != 0) {for (int k = j; k > 0; k--) {int temp = game.board[i][k];game.board[i][k] = game.board[i][k - 1];game.board[i][k - 1] = temp;}}}}}return game;}//可不可以合并(合并后是否是同一状态)bool combineAble(Game game, char input) {if (input == 'W' || input == 'w' || input == 'S' || input == 's') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {return true;}}}return false;}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {return true;}}}return false;}}//合并一次Game combine(Game game, char input) {if (input == 'W' || input == 'w') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j] += game.board[i + 1][j];game.board[i + 1][j] = 0;}}}}else if (input == 'A' || input == 'a') {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j] += game.board[i][j + 1];game.board[i][j + 1] = 0;}}}}else if (input == 'S' || input == 's') {for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {if (game.board[i + 1][j] == game.board[i][j] && game.board[i][j] != 0) {game.board[i + 1][j] += game.board[i][j];game.board[i][j] = 0;}}}}else {for (int i = 0; i < 4; i++) {for (int j = 0; j < 3; j++) {if (game.board[i][j + 1] == game.board[i][j] && game.board[i][j] != 0) {game.board[i][j + 1] += game.board[i][j];game.board[i][j] = 0;}}}}return game;}//生成随机数Game random(Game game) {srand((unsigned int)time(NULL));if (!full(game)) {//如果没满//rand() % 4 :0 到 3 之间的随机数int i = rand() % 4;int j = rand() % 4;while (game.board[i][j] != 0) {i = rand() % 4;j = rand() % 4;}game.board[i][j] = 2 * (rand() % 2 + 1); //2*(0+1)~2*(1+1)return game;}else {//如果满了return game;}}//操作一次Game sort(Game game, char input) {if (!combineAble(game, input) && !moveAble(game, input)) {return game;}game = combine(game, input);while (true) {while (combineAble(game, input)) {game = combine(game, input);}while (moveAble(game, input)) {game = move(game, input);}if (!combineAble(game, input) && !moveAble(game, input)) {break;}}return game;}//打印void printBoard(Game game) {cout << "|-------|-------|-------|-------|" << endl;for (int i = 0; i < 4; i++) {for (int i = 0; i < 4; i++) {cout << "|" << "\t";}cout << "|" << endl;for (int j = 0; j < 4; j++) {cout << "|";if (game.board[i][j] != 0) {cout << game.board[i][j];}cout << "\t";}cout << "|";cout << endl;for (int i = 0; i < 4; i++) {cout << "|" << "\t";}cout << "|" << endl;cout << "|-------|-------|-------|-------|";cout << endl;}cout << endl << endl;}int main() {Game game;for (int i = 0; i < 4; i++) {for (int j = 0; j < 4; j++) {game.board[i][j] = 0;}}char input;//生成随机数game = random(game);printBoard(game);while (1) {cout << "请输入你想要采取的操作:";cin >> input;game = sort(game, input);if (!full(game)) {game = random(game);}system("cls");printBoard(game);if (over(game) == true) {cout << "Game over!" << endl;break;}else if (win(game) == true) {cout << "You win!" << endl;break;}}system("pause");return 0;}

如有错误,请在评论区斧正。谢谢大家!

资源地址:/s/1M8AHq835B9tPEwxQLpLmIQ

提取码:0861

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。