C++实现2048小游戏(命令行)

C++学习笔记

试着写了一下

用一个二维数组模拟游戏棋盘,在二维数组上的空位置随机位置生成数字2或4,然后接收用户操作,向指定的方向移动并合并数字,再次生成数字,如此往复,直到游戏结束。

这里有几个问题:

  1. 游戏结束条件
  2. 如何保证随机生成的位置不会覆盖已有数字
  3. 如何移动与合并数字

游戏结束的条件为,随机生成数字后棋盘为满,且此时已经没有数字可以再合并。而为了保证随机生成的位置不会覆盖已有数字,可以将还没空的数字单独存在一个数组中,生成数字时在这个数组中生成。

移动与合并数字可以根据用户输入的操作依次扫描每排或每列的相邻两个非零数字,判断是否相同,如果有相同数字则可以移动,依次将可合并的数字合并,并排列到用户输入的方向即可

具体实现:

//游戏类
//提供棋盘与函数接口
//2048.h
#pragma once
#include <iostream>
#include<ctime>
#include<conio.h>
using namespace std;
#define GAMESIZE  4

class Game_2048
{
public:
	Game_2048();

	void ShowChessBoard();

	bool MakeNum();

	void UpDateEA();

	bool Move(char op);

	bool MoveAble();

	bool IsFull();

	char direction();

	bool GameOver(bool end);

	~Game_2048();

private:
	int number_array[GAMESIZE][GAMESIZE];

	int **empty_array;

	int counter;
};
//编写游戏规则,调用函数接口
//game.cpp
#include<iostream>
using namespace std;
#include"2048.h"

int main()
{
	Game_2048 game;

	bool is_moved = 1;//用于标记当前输入的方向是否可以移动数字
	bool is_created = 1;//标记随机数字是否生成成功

	while (1)
	{
		if(is_moved)//当棋盘内数字产生移动才生成新的数字
			is_created = game.MakeNum();

		game.ShowChessBoard();//输出当前棋盘

		if (game.GameOver(is_created))//GameOver()判断当前游戏是否结束
			return 0;


		cout << "请操作:(W/A/D/S)" << endl;
		char op;
		op = game.direction();//接收操作
		cout << op <<endl;

		is_moved = game.Move(op);
		
		system("cls");
	}


	system("pause");
	return 0;
}

具体的函数实现:

//2048.cpp
#include <iostream>
using namespace std;
#include"2048.h"

Game_2048::Game_2048()
{
	for (int i = 0; i < GAMESIZE; i++)
	{
		for (int j = 0; j < GAMESIZE; j++)
		{
			this->number_array[i][j] = 0;

		}
	}
	this->counter = 0;

	this->UpDateEA();
}

void Game_2048::ShowChessBoard()
{
	for (int i = 0; i < GAMESIZE; i++)
	{
		for (int j = 0; j < GAMESIZE; j++)
		{
			cout << this->number_array[i][j];
			cout << "\t";
		}
		cout << endl;
		cout << endl;
	}
}

bool Game_2048::MakeNum()
{
	if (this->IsFull())
		return 0;
	else
	{
		srand((int)time(0));
		int index = rand() % (GAMESIZE*GAMESIZE - counter );
		int i = rand() % 3;
		if (i % 3)
			*this->empty_array[index] = 2;
		else
			*this->empty_array[index] = 4;

		this->counter++;

		this->UpDateEA();

		return 1;
	}
	
}

void Game_2048::UpDateEA()
{
	if (this->empty_array != NULL)
	{
		delete[] this->empty_array;
		this->empty_array = NULL;
	}

	this->empty_array = new int*[GAMESIZE*GAMESIZE];
	int flag = 0;
	for (int i = 0; i < GAMESIZE*GAMESIZE ; i++)
	{
		if (this->number_array[i / GAMESIZE][i % GAMESIZE] == 0)
		{
			this->empty_array[flag] = &this->number_array[i / GAMESIZE ][i % GAMESIZE];
			flag++;
		}
	}
	
}

bool Game_2048::IsFull()
{
	if (this->counter == GAMESIZE * GAMESIZE)
		return 1;
	else
		return 0;
}

char Game_2048::direction()//读取键盘的方向键
{
	int c1 = _getch();
	if (c1 == 'w'|| c1 == 'W')return 'u';
	if (c1 == 's' || c1 == 'S')return 'd';
	if (c1 == 'a' || c1 == 'A')return 'l';
	if (c1 == 'd' || c1 == 'D')return 'r';
	return 'f';
}

bool Game_2048::MoveAble()
{
	if (counter != GAMESIZE * GAMESIZE)
		return 1;
	else
	{
		for (int i = 0; i < GAMESIZE; i++)
		{
			int line1 = 0;
			int line2 = 0;
			for (int j = 0; j < GAMESIZE; j++)
			{
				if (this->number_array[i][j] != 0)
				{
					line1 = this->number_array[i][j];
					if (line1 == line2)
						return 1;
					else
					{
						line2 = line1;
					}
				}
			}

		}

		for (int i = 0; i < GAMESIZE; i++)
		{
			int row1 = 0;
			int row2 = 0;
			for (int j = 0; j < GAMESIZE; j++)
			{
				if (this->number_array[j][i] != 0)
				{
					row1 = this->number_array[j][i];
					if (row1 == row2)
						return 1;
					else
					{
						row2 = row1;
					}
				}
			}
		}
		return 0;
	}
}

bool Game_2048::Move(char op)
{
	if (op == 'u' || op == 'd' || op == 'l' || op == 'r')
	{
		bool flag = 0;//操作正确后是否移动的标志

		int *line1 = NULL, *line2 = NULL;
		if (op == 'l' || op == 'r')//左右
		{
			for (int i = 0; i < GAMESIZE; i++)
			{
				for (int j = 0; j < GAMESIZE; j++)
				{
					if (op == 'l')//左移
					{
						line1 = &this->number_array[i][j];

						if (line2 != NULL)
						{
							if (*line1 == *line2 && *line1 != 0)//合并
							{
								*line2 += *line1;
								*line1 = 0;
								flag = 1;
								this->counter--;
								line2 += 1;
								line1 = NULL;

							}
							else if (*line2 != *line1 && *line1 != 0 && *line2 != 0)//排序
							{
								if (*(line2 + 1) == 0)
								{
									*(line2 + 1) = *line1;
									*line1 = 0;
									line2 += 1;
									flag = 1;
								}
								else
								{
									line2 = line1;
									line1 = NULL;
								}

							}
							else if (*line2 == 0 && *line1 != 0)//排序
							{
								*line2 = *line1;
								*line1 = 0;
								flag = 1;
								continue;
							}

						}
						else
						{
							line2 = &this->number_array[i][j];
							line1 = NULL;
						}

					}
					else//右移
					{
						line1 = &this->number_array[i][GAMESIZE - j - 1];

						if (line2 != NULL)
						{
							if (*line1 == *line2 && *line1 != 0)//合并
							{
								*line2 += *line1;
								*line1 = 0;
								flag = 1;
								this->counter--;
								line2 -= 1;
								line1 = NULL;

							}
							else if (*line2 != *line1 && *line1 != 0 && *line2 != 0)//排序
							{
								if (*(line2 - 1) == 0)
								{
									*(line2 - 1) = *line1;
									*line1 = 0;
									line2 -= 1;
									flag = 1;
								}
								else
								{
									line2 = line1;
									line1 = NULL;
								}

							}
							else if (*line2 == 0 && *line1 != 0)//排序
							{
								*line2 = *line1;
								*line1 = 0;
								flag = 1;
								continue;
							}

						}
						else
						{
							line2 = &this->number_array[i][GAMESIZE - j - 1];
							line1 = NULL;
						}

					}
				}
				line2 = NULL;
			}
		}
		else//上下移动
		{
		for (int i = 0; i < GAMESIZE; i++)
		{
			for (int j = 0; j < GAMESIZE; j++)
			{
				if (op == 'u')//上移
				{
					line1 = &this->number_array[j][i];

					if (line2 != NULL)
					{
						if (*line1 == *line2 && *line1 != 0)//合并
						{
							*line2 += *line1;
							*line1 = 0;
							flag = 1;
							this->counter--;
							line2 += GAMESIZE;
							line1 = NULL;

						}
						else if (*line2 != *line1 && *line1 != 0 && *line2 != 0)//排序
						{
							if (*(line2 + GAMESIZE) == 0)
							{
								*(line2 + GAMESIZE) = *line1;
								*line1 = 0;
								line2 += GAMESIZE;
								flag = 1;
							}
							else
							{
								line2 = line1;
								line1 = NULL;
							}

						}
						else if (*line2 == 0 && *line1 != 0)//排序
						{
							*line2 = *line1;
							*line1 = 0;
							flag = 1;
						}

					}
					else
					{
						line2 = &this->number_array[j][i];
						line1 = NULL;
					}
				}

				else//下移
				{
					line1 = &this->number_array[GAMESIZE - j - 1][i];

					if (line2 != NULL)
					{
						if (*line1 == *line2 && *line1 != 0)//合并
						{
							*line2 += *line1;
							*line1 = 0;
							flag = 1;
							this->counter--;
							line2 -= GAMESIZE;
							line1 = NULL;

						}
						else if (*line2 != *line1 && *line1 != 0 && *line2 != 0)//排序
						{
							if (*(line2 - GAMESIZE) == 0)
							{
								*(line2 - GAMESIZE) = *line1;
								*line1 = 0;
								line2 -= GAMESIZE;
								flag = 1;
							}
							else
							{
								line2 = line1;
								line1 = NULL;
							}

						}
						else if (*line2 == 0 && *line1 != 0)//排序
						{
							*line2 = *line1;
							*line1 = 0;
							flag = 1;
						}

					}
					else
					{
						line2 = &this->number_array[GAMESIZE - j - 1][i];
						line1 = NULL;
					}

				}
			}
			line2 = NULL;
		}
		}
		this->UpDateEA();
		return flag;
	}
	else
	{
		cout << "输入有误" << endl;
		system("pause");
		return false;
	}
	
}

bool Game_2048::GameOver(bool creat)
{
	if (creat)
	{
		if (this->MoveAble())
			return 0;
		else
			cout << "游戏结束" << endl;
			return 1;
	}
	else
		cout << "游戏结束" << endl;
		return 1;
}

Game_2048::~Game_2048()
{
	if (this->empty_array != NULL)
	{
		delete[] this->empty_array;
		this->empty_array = NULL;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值