大一上C++课程设计——2048小游戏

1.需求分析
2048小游戏,需要在进行上下左右操作的时候合并相同的数字,并且向按动的方向进行移动,每次移动后,随机生成2或者4两个数字。要求合并后移动两个数字之间不可以出现0,当无法移动再一次进行移动或者合并出现数字2048的时候,游戏结束。无法移动,游戏判负,出现2048,游戏获胜。
2.基本求解思路
万事开头难。想要对一个问题进行求解,首先要理清楚完成事情的步骤。按照题目要求:
“使用面向对象的方法来设计程序,即使用类和对象来完成设计,不运行使用面向过程的一堆函数来完成。 ”
需要注明的是,此处的N我在头文件中选择 “#define N 4” 进行描述。
因此题目的大方向是使用 类 来进行操作。接下来需要在类中定义成员函数,这些函数分步完成所需要进行的操作。我需要定义哪些函数呢?思路如下:
1.首先进行的是上下左右操作,这部分为四个函数;
2.建立初始棋盘并且打印;
3.棋盘采用何种方式储存;
4.进行上下左右操作后,随机生成数字2或者4;
5.记录分数;
6.判断游戏是否结束;

按照需求,我建立了以下成员函数:
class Game {
public:

void up(); // 四步操作
void down();
void left();
void right();

int board[N][N]{ 0 }; //定义棋盘的大小
void setchessboard(); // 定义初始棋盘
void printchessboard(); //打印棋盘

int score(); // 记录分数
int ifgameover(); // 判断游戏结束
};
具体代码如下:

#include <iostream>
#include<stdlib.h>
#include <iomanip>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <string>
#include <conio.h>
#define N 4
#define _CRT_SECURE_NO_DEPRECATE 
#define _CRT_NONSTDC_NO_DEPRECATE 
using namespace std; 

class Game {
public:
	int board[N][N]{ 0 };         //定义棋盘的大小
	void setchessboard();              // 定义初始棋盘 
	void printchessboard();            //打印棋盘

	void up();                        // 四步操作
	void down();
	void left();
	void right();

	int score();                      //  记录分数
	int ifgameover();                 // 判断游戏结束
};

//  board[a][b] 中[a]控制的是行 [b]控制的是列

//以下代码中,定义c的作用相当于一个标尺(或者说参照物?)

void Game::up() {         //向上合并的话,第一行不用向上合并。采用的思路是一行一行来看 对上一行进行怎样的一步操作。  
	int h = 0;
	for (int a = 1; a < N; a++) {
		for (int b = 0; b < N; b++) {
			if (board[a][b] != 0 && board[a - 1][b] == 0) {
				h = 1;break;
			}
			if (board[a - 1][b] == board[a][b] && board[a - 1][b] != 0) {
				h = 1; break;
			}
		}
	}

	for (int c = 0; c < N - 1; c++) { // 此处 由于a = c + 1时,最后一行已经判断,故 c < N - 1
		for (int a = c + 1; a > 0; a--) {//从 c 的下一行开始往上扫过一遍
			for (int b = 0; b < N; b++) {
				if (board[a - 1][b] == 0) {// 第a行的上一行情况
					board[a - 1][b] = board[a][b];
					board[a][b] = 0;// 从上往下进行值的“交换”
				}
			}
		}
	}

	for (int a = 1; a < N; a++) {
		for (int b = 0; b < N ; b++) {
			board[a - 1][b] == board[a][b] ? board[a - 1][b] *= 2, board[a][b] = 0 : board[a][b] = board[a][b]; // 冒号后面的部分无意义
		}
	}

	for (int c = 0; c < N - 1; c++) { // 此处 由于a = c + 1时,最后一行已经判断,故 c < N - 1
		for (int a = c + 1; a > 0; a--) {//从 c 的下一行开始往上扫过一遍
			for (int b = 0; b < N; b++) {
				if (board[a - 1][b] == 0) {// 第a行的上一行情况
					board[a - 1][b] = board[a][b];
					board[a][b] = 0;// 从上往下进行值的“交换”
				}
			}
		}
	}

	if(h){
		srand((unsigned)time(NULL));
		int x, y;
		do {
			x = rand() % N;
			y = rand() % N;
		} while (board[x][y] != 0);
		int c = rand() % 4 + 1;
		switch (c) {
		case 1:
		case 2:
		case 3:  board[x][y] = 2, h = 0; break;
		default: board[x][y] = 4, h = 0; break;
		}
	}
}

void Game::down() { // 向下合并,最后一行不需要向下进行合并, 此处的思路为一行一行判断,看是否对下一行进行操作
	int h = 0;
	for (int a = N - 2; a >= 0; a--) {
		for (int b = 0; b < N; b++) {
			if (board[a][b] != 0 && board[a + 1][b] == 0) {
				h = 1; break;
			}
			if (board[a + 1][b] == board[a][b] && board[a + 1][b] != 0) {
				h = 1; break;
			}
		}
	}

	for (int c = N - 1; c > 0; c--) {
		for (int a = c - 1; a < N; a++) {  // 从 c 的上一行开始往下扫
			for (int b = 0; b < N; b++) {
				if (board[a + 1][b] == 0) {   // 第a行的下一行的情况
					board[a + 1][b] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

	for (int a = N - 2; a >= 0; a--) {
		for (int b = 0; b < N  ; b++) {
			board[a + 1][b] == board[a][b] ? board[a + 1][b] *= 2, board[a][b] = 0 : board[a][b] = board[a][b];
		}
	}

	for (int c = N - 1; c > 0; c--) {
		for (int a = c - 1; a < N; a++) {  // 从 c 的上一行开始往下扫
			for (int b = 0; b < N; b++) {
				if (board[a + 1][b] == 0) {   // 第a行的下一行的情况						board[a + 1][b] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

	if (h) {
		srand((unsigned)time(NULL));
		int x, y;
		do {
			x = rand() % N;
			y = rand() % N;
		} while (board[x][y] != 0);
		int c = rand() % 4 + 1;
		switch (c) {
		case 1:
		case 2:
		case 3:  board[x][y] = 2, h = 0; break;
		default: board[x][y] = 4, h = 0; break;
		}
	}
}

void Game::left() { // 向左合并的话,第一列不用合并。采用的思路是一列一列看,看怎么样对上一列进行操作
	int h = 0;
	for (int b = 1; b < N; b++) {
		for (int a = 0; a < N; a++) {
			if (board[a][b] != 0 && board[a][b - 1] == 0) {
				h = 1; break;
			}
			if (board[a][b - 1] == board[a][b] && board[a][b] != 0) {
				h = 1; break;
			}
		}
	}
	for (int c = 0;c < N - 1 ;c++) {
		for (int b = c + 1;b > 0;b--) { // 从第c列的右边开始往左扫
			for (int a = 0; a < N; a++) {// 从最后一行开始判断
				if (board[a][b - 1] == 0) {// 第b列的左一列
					board[a][b - 1] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

	for (int b = 1; b < N ; b++) { 
		for (int a = 0; a < N ; a++) {
					board[a][b - 1] == board[a][b] ? board[a][b - 1] *= 2, board[a][b] = 0 : board[a][b - 1] = board[a][b - 1];
		}
	}

	for (int c = 0; c < N - 1; c++) {
		for (int b = c + 1; b > 0; b--) { // 从第c列的右边开始往左扫
			for (int a = 0; a < N; a++) {// 从最后一行开始判断
				if (board[a][b - 1] == 0) {// 第b列的左一列
					board[a][b - 1] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

	if (h) {
		srand((unsigned)time(NULL));
		int x, y;
		do {
			x = rand() % N;
			y = rand() % N;
		} while (board[x][y] != 0);
		int c = rand() % 4 + 1;
		switch (c) {
		case 1:
		case 2:
		case 3:  board[x][y] = 2, h = 0; break;
		default: board[x][y] = 4, h = 0; break;
		}
	}
}

void Game::right() { // 向右合并的话 ,最后一列不用合并,思路是一列一列看 , 看怎样对下一列进行操作
	int h = 0;
	for (int b = N - 2; b >= 0; b--) {
		for (int a = 0; a < N; a++) {
			if (board[a][b] != 0 && board[a][b + 1] == 0) {
				h = 1; break;
			}
			if (board[a][b + 1] == board[a][b] && board[a][b] != 0) {
				h = 1; break;
			}
		}
	}

	for (int c = N -1; c > 0; c--){
		for (int b = c -1; b < N - 1; b++){ //从第c列的左边开始往右扫
			for (int a = 0; a < N; a++) {
				if (board[a][b + 1] == 0) {//第b列的右一列
					board[a][b + 1] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

		for (int b = N - 2; b >= 0; b--) { //从第c列的左边开始往右扫
			for (int a = 0; a < N; a++) {
					board[a][b + 1] == board[a][b] ? board[a][b + 1] *= 2, board[a][b] = 0 : board[a][b] = board[a][b];
			}
		}

	for (int c = N - 1; c > 0; c--) {
		for (int b = c - 1; b < N - 1; b++) { //从第c列的左边开始往右扫
			for (int a = 0; a < N; a++) {
				if (board[a][b + 1] == 0) {//第b列的右一列
					board[a][b + 1] = board[a][b];
					board[a][b] = 0;
				}
			}
		}
	}

	if (h) {
		srand((unsigned)time(NULL));
		int x, y;
		do {
			x = rand() % N;
			y = rand() % N;
		} while (board[x][y] != 0);
		int c = rand() % 4 + 1;
		switch (c) {
		case 1:
		case 2:
		case 3:  board[x][y] = 2, h = 0; break;
		default: board[x][y] = 4, h = 0; break;
		}
	}
}

void Game::setchessboard() {               // 初始棋盘生成
	srand((unsigned)time(NULL));
	int x, y ,a ,b;
	int z = 0;
		x = rand() % N;
		y = rand() % N;
		board[x][y] = 2;
		do {
			a = rand() % N;
			b = rand() % N;
		} while (a == x && b == y);
		board[a][b] = 2;
}

void Game::printchessboard() {   // 棋盘的打印实现
	cout << "————————————" << endl;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			cout << "|" << setw(4) << board[i][j]  << "|";
		}
		cout << endl;
		cout << "————————————" << endl;
	}
}  


int Game::score() {
	int c = 0;
	for (int a = 0; a < N; a++)
	{
		for (int b = 0; b < N; b++)
		{
			c += board[a][b];
		}
	}
	return c;
}

int Game::ifgameover() {//判断游戏是否结束
	int c = 0;      // case 0 : 输了,算积分

	for (int a = 0; a < N; a++){
		if (c == 1) break;
		for (int b = 0; b < N; b++){
			if (board[a][b] == 2048) {//  case 1: 赢了
				c = 1; 
				break;
			}
		}
	}

	for (int a = 0; a < N; a++){//检查相邻两列
		if (c == 1) break;
		if (c != 1) {
			for (int b = 0; b < N - 1; b++){
				if (board[a][b] == 0 || board[a][b] == board[a][b + 1]){
					c = 2;  //  case 2 : 继续游戏
					break;
				}
			}
		}
	}

	for (int b = 0; b < N; b++){// 检查相邻两行
		if (c == 1) break; 
		if (c != 1) {
			for (int a = 0; a < N - 1; a++) {
				if (board[a][b] == 0 || board[a][b] == board[a + 1][b]){
					c = 2;
					break;
				}
			}
		}
	}
	return c;
}

int main()
{

	cout << "    by Fang Hanfei  " << endl;

	Game game;	
	game.setchessboard();
	game.printchessboard();

	while (char ch = _getch()) {
		int b = game.ifgameover();
		int c = game.score();
		switch (ch) {
		case 75: 
			game.left();  // 调用函数 void Game::left()
			switch (b) {
			case 0: 
				system("CLS");//清屏
				cout << "你输了 !" << endl << "你的积分是: " << c << endl;  break;
			case 1:
				system("CLS");
				cout << "小伙子你真棒,居然赢了!" << endl; break;
			case 2:
				system("CLS");
				game.printchessboard(); break;
			}
			break;
		case 72:
			game.up(); // 调用函数void Game::up()
			switch (b) {
			case 0: 
				system("CLS");
				cout << "你输了 !" << endl << "你的积分是: " << c << endl;  break;
			case 1: 
				system("CLS");
				cout << "小伙子你真棒,居然赢了!" << endl; break;
			case 2:
				system("CLS");
				game.printchessboard(); break;
			}
			break;
		case 80:
			game.down(); // 调用函数void Game::down()
			switch (b) {
			case 0: 
				system("CLS");
				cout << "你输了 !" << endl << "你的积分是: " << c << endl;  break;
			case 1: 
				system("CLS");
				cout << "小伙子你真棒,居然赢了!" << endl; break;
			case 2:
				system("CLS");
				game.printchessboard(); break;
			}
			break;
		case 77:
			game.right(); // 调用函数void Game::right()
			switch (b) {
			case 0: 
				system("CLS");
				cout << "你输了 !" << endl << "你的积分是: " << c << endl;  break;
			case 1: 
				system("CLS");
				cout << "小伙子你真棒,居然赢了!" << endl; break;
			case 2:
				system("CLS");
				game.printchessboard(); break;
			}
			break;
		}
	}
	return 0;
}

不得不承认,由于个人水平等限制,代码冗长,结构较复杂,这要通过在以后的学习中去不断练习,改进。

  • 10
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值