一个简单的c++小游戏——2048
2048小游戏
代码
话不多说,代码如下:
#include<iostream>
#include<vector>
#include<ctime>
#include<cstdlib>
using namespace std;
class Game_2048
{
public:
Game_2048();
~Game_2048();
void introduction();
bool judgeOver(); //判断游戏是否结束
void reSize();
void printBoard(); //打印函数
void getRand(); //随机在棋盘上生成2,4;
void slide(); //滑动
private:
int m=4, n=4;
char op; //用户操作
vector< vector<int> > board; //棋盘
vector<int> row;
bool judgeInsert(int x,int y);
bool judgeSlide(); //判断是否能滑动,(未写完)
void copyBoard(vector< vector<int> > &newBoard,vector< vector<int> > &board);
void inputOp();
char getOp(); //返回操作符
bool judgeLeftSlide(bool mark=true);
void leftSlide(); //左滑动
bool judgeRightSlide(bool mark = true);
void rightSlide();
bool judgeUpSlide(bool mark = true);
void upSlide();
bool judgeDownSlide(bool mark = true);
void downSlide();
void reStart();
void enlarge(); //将值扩大二倍
};
int main()
{
Game_2048 NB;
NB.introduction();
NB.getRand();
NB.printBoard();
while (!NB.judgeOver())
{
NB.slide();
NB.getRand();
NB.printBoard();
}
cout << "游戏结束!!!\n";
system("pause");
return 0;
}
void Game_2048::introduction()
{
cout << "这是一个2048游戏,规则如下:\n";
cout << "上划:W;\n下滑:S;\n左划:A;\n右划:D;\n退出:Q;\n重新开始:R;\n请输入下次操作,\n";
}
void Game_2048::slide()
{
inputOp();
switch (getOp())
{
case 'a':
case 'A':
if (judgeLeftSlide())
do
leftSlide();
while (judgeLeftSlide(false));
else
{
cout << "无法左滑动,请重试!!!\n";
slide();
}
break;
case 'd':
case 'D':
if (judgeRightSlide())
do
rightSlide();
while (judgeRightSlide(false));
else
{
cout << "无法右滑动,请重试!!!\n";
slide();
}
break;
case 'w':
case 'W':
if(judgeUpSlide())
do
upSlide();
while (judgeUpSlide(false));
else
{
cout << "无法上滑动,请重试!!!\n";
slide();
}
break;
case 's':
case 'S':
if(judgeDownSlide())
do
downSlide();
while (judgeDownSlide(false));
else
{
cout << "无法下滑动,请重试!!!\n";
slide();
}
break;
case 'p':
case 'P':
enlarge();
break;
case 'q':
case 'Q':
exit(0);
break;
case 'r':
case 'R':
reStart();
break;
default:
cout << "输入错误,作为惩罚,随机生成一个数!\n";
break;
}
}
void Game_2048::reStart()
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
board[i][j] = 0;
}
}
void Game_2048::enlarge()
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
board[i][j] *= 2;
}
}
char Game_2048::getOp()
{
return op;
}
void Game_2048::upSlide()
{
for (int j = 0; j < n; j++)
for (int i = m - 1; i > 0; i--) { //n-1!!
if (board[i][j] != 0 && board[i - 1][j] == 0) //移动
{
board[i - 1][j] = board[i][j];
board[i][j] = 0;
}
}
for (int j = 0; j < n; j++)
for (int i = m - 1; i > 0; i--) {
if (board[i][j] != 0 && board[i-1][j] == board[i][j]) //覆盖
{
board[i-1][j] += board[i][j];
board[i][j] = 0;
}
}
}
bool Game_2048::judgeUpSlide(bool mark)
{
if (mark)
{
for (int i = 0; i < m; i++)
for (int j = n - 1; j > 0; j--)
{
if (board[i][j] == 0)
return true;
}
}
for (int j = 0; j < n; j++)
for (int i = m - 1; i > 0; i--) { //n-1!!
if (board[i][j] != 0 && board[i - 1][j] == 0) //移动
return true;
if (board[i][j] != 0 && board[i - 1][j] == board[i][j]) //覆盖
return true;
}
return false;
}
bool Game_2048::judgeDownSlide(bool mark)
{
if (mark) {
for (int i = 0; i < m; i++)
for (int j = n - 1; j > 0; j--)
{
if (board[i][j] == 0)
return true;
}
}
for (int j = 0; j < n; j++)
for (int i = 0; i < m - 1; i++) { //n-1!!
if (board[i][j] != 0 && board[i + 1][j] == 0) //移动
return true;
if (board[i][j] != 0 && board[i + 1][j] == board[i][j]) //覆盖
return true;
}
return false;
}
void Game_2048::downSlide()
{
for (int j = 0; j < n; j++)
for (int i = 0; i < m - 1; i++) {
if (board[i][j] != 0 && board[i + 1][j] == 0) //移动
{
board[i + 1][j] = board[i][j];
board[i][j] = 0;
}
}
for (int j = 0; j < n; j++)
for (int i = 0; i < m - 1; i++) {
if (board[i][j] != 0 && board[i + 1][j] == board[i][j]) //覆盖
{
board[i + 1][j] += board[i][j];
board[i][j] = 0;
}
}
}
void Game_2048::rightSlide()
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n - 1; j++) { //n-1!!
if (board[i][j] != 0 && board[i][j + 1] == 0) //移动
{
board[i][j + 1] = board[i][j];
board[i][j] = 0;
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n - 1; j++) {
if (board[i][j] != 0 && board[i][j + 1] == board[i][j]) //覆盖
{
board[i][j + 1] += board[i][j];
board[i][j] = 0;
}
}
}
bool Game_2048::judgeRightSlide(bool mark )
{
if (mark) {
for (int i = 0; i < m; i++)
for (int j = n - 1; j > 0; j--)
{
if (board[i][j] == 0)
return true;
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n - 1; j++) { //n-1!!
if (board[i][j] != 0 && board[i][j + 1] == board[i][j]) //覆盖
return true;
if (board[i][j] != 0 && board[i][j + 1] == 0)
return true;
}
return false;
}
void Game_2048::leftSlide()
{
for (int i = 0; i < m; i++)
for (int j = 1; j < n; j++) { //n-1!!
if (board[i][j] != 0 && board[i][j - 1] == 0) //移动
{
board[i][j - 1] = board[i][j];
board[i][j] = 0;
}
}
for (int i = 0; i < m; i++)
for (int j = 1; j < n; j++) {
if (board[i][j] != 0 && board[i][j - 1] == board[i][j]) //覆盖
{
board[i][j - 1] += board[i][j];
board[i][j] = 0;
}
}
}
bool Game_2048::judgeLeftSlide(bool mark)
{
if (mark) {
for (int i = 0; i < m; i++)
for (int j = n - 1; j > 0; j--)
{
if (board[i][j] == 0)
return true;
}
}
for (int i = 0; i < m; i++)
for (int j = n - 1; j > 0; j--) { //n-1!!
if (board[i][j] != 0 && board[i][j - 1] == 0) //移动
return true;
if (board[i][j] != 0 && board[i][j - 1] == board[i][j]) //覆盖
return true;
}
return false;
}
bool Game_2048::judgeOver()
{
if (op == 'q' || op == 'Q')
return true;
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
if (board[i][j] == 2048)
{
printBoard();
cout << "有数字达到了2048,恭喜!!!\n";
return true;
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++) {
if (board[i][j] == 0)
return false;
}
if (judgeSlide())
return false;
else
{
cout << "无法再滑动\n";
return true;
}
}
bool Game_2048::judgeSlide()
{
vector< vector<int> > copyBoard; //棋盘
vector<int> copyRow;
for (int i = 0; i < n; i++) {
copyRow.push_back(0);
}
for (int i = 0; i < m; i++) {
copyBoard.push_back(copyRow);
}
copyBoard = board;
upSlide();
downSlide();
leftSlide();
rightSlide();
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
{
if (board[i][j] == 0) {
board = copyBoard;
return true;
}
}
return false;
}
void Game_2048::copyBoard(vector< vector<int> >& newBoard, vector< vector<int> >& board)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
newBoard[i][j] = board[i][j];
}
bool Game_2048::judgeInsert(int x,int y)
{
if (board[x][y] == 0)
return true;
else
return false;
}
void Game_2048::getRand()
{
srand(time(0));
int x, y,val;
do
{
x = rand() % m;
y = rand() % n;
} while (!judgeInsert(x,y));
val = (rand() % 2 + 1)*2;
board[x][y] = val;
}
void Game_2048::inputOp()
{
cin >> op;
}
void Game_2048::reSize()
{
cout << "请输入棋盘大小m*n\n";
cin >> m >> n;
Game_2048();
}
Game_2048::~Game_2048()
{
}
Game_2048::Game_2048()
{
for (int i = 0; i < n; i++){
row.push_back(0);
}
for (int i = 0; i < m; i++){
board.push_back(row);
}
}
void Game_2048::printBoard()
{
cout << "\n--------------\n";
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cout << board[i][j];
if (j < n-1)
{
cout << "—";
}
if (j == n-1 && i < m-1)
{
cout << endl;
int count = 0;
while (count++ < n-1)
{
cout << "| ";
}
cout << "|" << endl;
}
}
}
cout << "\n--------------\n" ;
}
cpp

PS: 楼主目前仍是刚接触C++的菜鸟级别,在创作这个游戏时总共编写了大约450行代码量左右。虽然觉得数量较多存在冗余之处, 但目前还在学习阶段, 后续计划进一步精简优化。
设计思路
编译器
目前博主只会c++的控制台程序,编译器是vs2019;
2048类的声明
游戏操作极为简单,在游戏中者只需要进行上下左右方向的滑动操作即可完成主要任务;此外,在该类游戏中所有的数值数据均以一个4×4的二维向量进行存储。在功能模块划分上,默认情况下该类提供基础功能如滑动操作、打印输出、判定游戏结束状态以及获取操作符等功能模块;其中私有成员主要包括各个方向滑动的具体实现以及判定结束状态的相关逻辑,并对外公开提供一个默认初始化为一个4×4的二维向量(支持通过resize函数对其尺寸进行调整)。
打印函数的实现
void Game_2048::printBoard()
{
cout << "\n--------------\n";
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
cout << board[i][j];
if (j < n-1)
{
cout << "—";
}
if (j == n-1 && i < m-1)
{
cout << endl;
int count = 0;
while (count++ < n-1)
{
cout << "| ";
}
cout << "|" << endl;
}
}
}
cout << "\n--------------\n" ;
}
cpp

这部分其实很简单啦!基本上就是在做一个二维向量的循环遍历(使用两个for循环)。稍微复杂一点的部分是输出那些竖线和横线符号(|和-),多想想就能解决了。
公共部分滑动函数slide的实现
程序不会弹出代码窗口,并且其本质上就是一种简单的switch语句来处理不同情况下的功能切换。每个滑块(case)都采用do-while循环机制来执行特定的操作。由于这四个private的滑块函数对于棋盘上的数值只能执行一次移动操作(限制因素),因此在某些情况下必须反复调用右侧移动操作以达到目标状态。比如4, 0, 0, 0这样的初始状态向右移动后会变为[4→1]的状态吗?或者会变成什么样子呢?
judgeOver函数的实现
改写说明
私有滑动函数的实现
void Game_2048::rightSlide()
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n - 1; j++) { //n-1!!
if (board[i][j] != 0 && board[i][j + 1] == 0) //移动
{
board[i][j + 1] = board[i][j];
board[i][j] = 0;
}
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n - 1; j++) {
if (board[i][j] != 0 && board[i][j + 1] == board[i][j]) //覆盖
{
board[i][j + 1] += board[i][j];
board[i][j] = 0;
}
}
}
cpp

还是很简单,就是两个遍历,一个移动,一个合并。
总结
作为一位编程新手,在某天夜里突然有了编写一个2048小游戏的想法,并决定通过这个项目来检验自己的技术能力。经过一个失眠夜的设计思考后,在第二天上午的第一节课开始动手编写起这个项目。尽管进展顺利,但在调试过程中却耗费了不少时间(主要集中在do-while循环这一部分)。由于自身经验不足导致开发效率不高,在为期约一周的时间内完成了全部编码工作(共450行代码),但缺乏创新性且未引入新的算法或技术方案。
