当前位置: 首页 > 工具软件 > 2048.c > 使用案例 >

C++实现2048

许出野
2023-12-01

开发环境

Vs 2015 + EasyX

需求分析

上下左右移动,相同数字相加

主要的类

一个游戏类,包含一个4*4的数组和一个记录一共有多少个非零数的变量;
方法包括,画图,上下左右,判断游戏是否结束,和产生一个新数

主函数

首先应初始化这个类,然后画出初始化的结果;然后根据上下左右键的输入,执行相关的函数并判断是否需要产生新的数,然后判断游戏是否结束,重复此过程,直到游戏结束。

实现

头文件

头文件主要完成这个类的定义

#pragma once
# include <conio.h>
#include <graphics.h>
#include <time.h>

enum Ch { up = 72, down = 80, left = 75, right = 77 };

class Game
{
private:
	int map[4][4];
	int num;//非零数的个数
public:
	Game();
	void DrawMap();//画地图
	void NewNum();
	bool Up();
	bool Down();
	bool Left();
	bool Right();
	bool GameOver();
};

Game::Game()
{
	//数组中的每个元素清零
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			map[i][j] = 0;
		}
	}
	num = 0;
	NewNum();
	//int n = 0;//产生的随机数
	//n = rand() % 5 == 0 ? 4 : 2;

	//int m = 0;//随机数的位置
	//m = rand() % 16;
	//map[m / 4][m % 4] = n;
}
//画地图
void Game::DrawMap()
{
	cleardevice();
	settextstyle(80, 80, TEXT("宋体"));
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			rectangle(j * 100, i * 100, j * 100 + 100, i * 100 + 100);
			/*if (map[i][j] != 0)
				outtextxy(j * 100+10, i * 100+10, map[i][j] + 48);*/
			switch (map[i][j])
			{
			case 2:
			case 4:
			case 8:
				settextstyle(80, 80, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, map[i][j] + 48);
				break;
			case 16:
				settextstyle(80, 40, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("16"));
				break;
			case 32:
				settextstyle(80, 40, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("32"));
				break;
			case 64:
				settextstyle(80, 40, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("64"));
				break;
			case 128:
				settextstyle(80, 27, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("128"));
				break;
			case 256:
				settextstyle(80, 27, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("256"));
				break;
			case 512:
				settextstyle(80, 27, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("512"));
				break;
			case 1024:
				settextstyle(80, 20, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("1024"));
				break;
			case 2048:
				settextstyle(80, 20, TEXT("宋体"));
				outtextxy(j * 100 + 10, i * 100 + 10, TEXT("2048"));
				break;
			}
		}
	}
}
void Game::NewNum()
{
	int n = 0;//产生的随机数
	n = rand() % 5 == 0 ? 4 : 2;
	while (1)
	{
		int m = 0;//随机数的位置
		m = rand() % 16;
		if (map[m / 4][m % 4] == 0)
		{
			map[m / 4][m % 4] = n;
			break;
		}
	}
	num++;//每产生一个新书非零个数加1
}
bool Game::Up()
{
	bool rescult = false;
	for (int j = 0; j < 4; j++)
	{
		for (int i = 0; i <4; i++)
		{
			if (map[i][j] != 0)//找到第一个非0的数
			{
				for (int t = i + 1; t <4; t++)
				{
					if (map[t][j] != 0)//找到第二个非0的数
					{
						if (map[i][j] == map[t][j])//如果两个非零数相同,则相加
						{
							map[i][j] += map[t][j];
							map[t][j] = 0;
							rescult = true;
							num--;
						}
						break;
					}
				}
			}
		}
		for (int i = 0; i <4; i++)
		{
			if (map[i][j] == 0)//找到0
			{
				for (int t = i + 1; t <4; t++)
				{
					if (map[t][j] != 0)//找到下一个非0的数
					{
						map[i][j] = map[t][j];
						map[t][j] = 0;
						rescult = true;
						break;
					}
				}
			}
		}
	}
	return rescult;
}
bool Game::Down()
{
	bool rescult = false;
	for (int j = 0; j < 4; j++)
	{
		for (int i = 3; i >= 0; i--)
		{
			if (map[i][j] != 0)//找到第一个非0的数
			{
				for (int t = i - 1; t >= 0; t--)
				{
					if (map[t][j] != 0)//找到第二个非0的数
					{
						if (map[i][j] == map[t][j])//如果两个非零数相同,则相加
						{
							map[i][j] += map[t][j];
							map[t][j] = 0;
							rescult = true;
							num--;
						}
						break;
					}
				}
			}
		}
		for (int i = 3; i >= 1; i--)
		{
			if (map[i][j] == 0)//找到0
			{
				for (int t = i - 1; t >= 0; t--)
				{
					if (map[t][j] != 0)//找到下一个非0的数
					{
						map[i][j] = map[t][j];
						map[t][j] = 0;
						rescult = true;
						break;
					}
				}
			}
		}
	}
	return rescult;
}
bool Game::Left()
{
	bool rescult = false;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j <4; j++)
		{
			if (map[i][j] != 0)//找到第一个非0的数
			{
				for (int t = j + 1; t <4; t++)
				{
					if (map[i][t] != 0)//找到第二个非0的数
					{
						if (map[i][j] == map[i][t])//如果两个非零数相同,则相加
						{
							map[i][j] += map[i][t];
							map[i][t] = 0;
							rescult = true;
							num--;
						}
						break;
					}
				}
			}
		}
		for (int j = 0; j <4; j++)
		{
			if (map[i][j] == 0)//找到0
			{
				for (int t = j + 1; t <4; t++)
				{
					if (map[i][t] != 0)//找到下一个非0的数
					{
						map[i][j] = map[i][t];
						map[i][t] = 0;
						rescult = true;
						break;
					}
				}
			}
		}
	}
	return rescult;
}
bool Game::Right()
{
	bool rescult = false;
	for (int i = 0; i < 4; i++)
	{
		for (int j = 3; j >= 0; j--)
		{
			if (map[i][j] != 0)//找到第一个非0的数
			{
				for (int t = j - 1; t >= 0; t--)
				{
					if (map[i][t] != 0)//找到第二个非0的数
					{
						if (map[i][j] == map[i][t])//如果两个非零数相同,则相加
						{
							map[i][j] += map[i][t];
							map[i][t] = 0;
							rescult = true;
							num--;
						}
						break;
					}
				}
			}
		}
		for (int j = 3; j >= 1; j--)
		{
			if (map[i][j] == 0)//找到0
			{
				for (int t = j - 1; t >= 0; t--)
				{
					if (map[i][t] != 0)//找到下一个非0的数
					{
						map[i][j] = map[i][t];
						map[i][t] = 0;
						rescult = true;
						break;
					}
				}
			}
		}
	}
	return rescult;
}
bool Game::GameOver()
{
	if (num < 16)
		return false;
	//非0的个数等于16,并且无相邻的两个相同的数
	if (num == 16)
	{
		for (int i = 0; i < 4; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				if (i < 3 && j < 3)
				{
					if (map[i][j] == map[i + 1][j] || map[i][j] == map[i][j + 1])
						return false;
				}
				else if (i < 3 && j == 3)
				{
					if (map[i][j] == map[i + 1][j])
						return false;
				}
				else if (i == 3 && j < 3)
				{
					if (map[i][j] == map[i][j + 1])
						return false;
				}
				else if (i==3 && j==3)
					return true;
			}
		}
	}
}

源文件

源文件主要执行的是主函数

#include "game.h"

int main()
{
	srand((unsigned int)time(NULL));
	Game game;
	initgraph(400, 400);
	game.DrawMap();
	
	while (1)
	{
		int ch=_getch();
		bool r = false;//是否可以上下左右移动
		switch (ch)
		{
		case up:
			r = game.Up();
			break;
		case down:
			r = game.Down();
			break;
		case left:
			r = game.Left();
			break;
		case right:
			r = game.Right();
			break;
		default:
			continue;
		}
		if (true == r)
			game.NewNum();
		game.DrawMap();
		if (game.GameOver())
			break;
		Sleep(10);
	}
	system("pause");
	return 0;
}

注意点

上下左右的逻辑

 类似资料: