C语言--2048小游戏

需要用到EasyX图形库

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include<assert.h>
#include <conio.h>
#include <windows.h>
#include<graphics.h>
#include<string.h>
#define ROW 4 /* 行数 */
#define COL ROW /* 列数 */
#define KEY_UP 72 /* 方向键'上'的扫描码码值 */
#define KEY_DOWN 80 /* 方向键'下'的扫描码码值 */
#define KEY_LEFT 75 /* 方向键'左'的扫描码码值 */
#define KEY_RIGHT 77 /* 方向键'右'的扫描码码值 */
#define BLANK 0 /* 空白区域的数字 */
int g_seed = 0; /* 修改随机数种子 */
//产生新的数字
bool GetNum(int(*arr)[COL])
{
	srand((unsigned int)time(NULL) + g_seed);
	g_seed++;
	int row = rand() % ROW;
	int col = rand() % COL;
	int ran = 2;//ran用来确认随机数为2或4
	if (rand() % 5 == 0)
	{
		ran = 4;
	}
	while (arr[row][col] != 0)//当前格子不等于0
	{
		col++;
		if (col == COL)
		{
			row = (row + 1) % ROW;
			col = 0;
		}
	}
	if (arr[row][col] == 0)
	{
		arr[row][col] = ran;
		return true;
	}
	else
		return false;
}
//显示界面
void Show(int(*arr)[COL])
{
	system("CLS");//清除屏幕数据
	 绘图窗口初始化
	//initgraph(640, 640);

	 读取图片至绘图窗口
	//loadimage(NULL, _T("C:\\Users\\86166\\Desktop\\微信图片_20230524161021.jpg"), 640, 640);
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			printf("%d\t", arr[i][j]);
		}
		printf("\n\n");
	}
	/*_getch();
	closegraph();*/
}
//向左合并和移动函数
//有合并或移动数据返回true,否则返回false
bool MergeLeft(int(*arr)[COL])
{
	for (int i = 0; i < 4; i++)
	{
		//如果出现连续三个相同,先合并靠里面的,也就是说先合并最左边的,所以从左向右循环
		//如果后两个合并后与前一个相同,不会继续和前一个合并
		for (int j = 0; j < 3; j++)
		{//合并
			if (((*(arr + i))[j] == (*(arr + i))[j + 1]) && (*(arr + i))[j + 1] != 0)
			{
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j + 1] = 0;
			}
			else if (j < 2 && (*(arr + i))[j] == (*(arr + i))[j + 2] && (*(arr + i))[j + 1] == 0)
			{//解决出现2 0 2 0->4 0 0 0的问题和0 2 0 2->0 4 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j + 2] = 0;
			}
			else if (j == 0 && (*(arr + i))[j] == (*(arr + i))[j + 3] && (*(arr + i))[j + 1] == 0 && (*(arr + i))[j + 2] == 0)
			{//解决出现2 0 0 2->4 0 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j + 3] = 0;
			}
			/*else
			{
				break;
			}*/
		}
		for (int j = 2; j >= 0; j--)
		{//平移
			if ((*(arr + i))[j] == 0 && (*(arr + i))[j + 1] != 0)
			{
				for (int k = j; k < 3; k++)
				{
					(*(arr + i))[k] = (*(arr + i))[k + 1];
				}
				(*(arr + i))[3] = 0;
			}
		}
	}
	return true;
}

//向上合并函数
bool MergeUp(int(*arr)[COL])
{
	for (int j = 0; j < 4; j++)
	{
		//如果出现连续三个相同,先合并靠里面的,也会是说先合并最左边的,所以从左向右循环
		//如果后两个合并后与前一个相同,不会继续和前一个合并
		for (int i = 0; i < 3; i++)
		{//合并
			if ((*(arr + i))[j] == (*(arr + i + 1))[j] && (*(arr + i + 1))[j] != 0)
			{
				(*(arr + i))[j] *= 2;
				(*(arr + i + 1))[j] = 0;
			}
			else if (i < 2 && (*(arr + i))[j] == (*(arr + i + 2))[j] && (*(arr + i + 1))[j] == 0)
			{//解决出现2 0 2 0->4 0 0 0的问题和0 2 0 2->0 4 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i + 2))[j] = 0;
			}
			else if (i == 0 && (*(arr + i))[j] == (*(arr + i + 3))[j] && (*(arr + i + 1))[j] == 0 && (*(arr + i + 2))[j] == 0)
			{//解决出现2 0 0 2->4 0 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i + 3))[j] = 0;
			}
		}
		for (int i = 2; i >= 0; i--)
		{//平移
			if ((*(arr + i))[j] == 0 && (*(arr + i + 1))[j] != 0)
			{
				for (int k = i; k < 3; k++)
				{
					(*(arr + k))[j] = (*(arr + k + 1))[j];
				}
				(*arr + 3)[j] = 0;
			}
		}
	}
	return true;
}

bool MergeRight(int(*arr)[COL])
{
	for (int i = 0; i < 4; i++)
	{
		//如果出现连续三个相同,先合并靠里面的,也会是说先合并最左边的,所以从左向右循环
		//如果后两个合并后与前一个相同,不会继续和前一个合并
		for (int j = 3; j > 0; j--)
		{//合并
			if (((*(arr + i))[j] == (*(arr + i))[j - 1]) && (*(arr + i))[j - 1] != 0)
			{
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j - 1] = 0;
			}
			else if (j > 1 && (*(arr + i))[j] == (*(arr + i))[j - 2] && (*(arr + i))[j - 1] == 0)
			{//解决出现2 0 2 0->4 0 0 0的问题和0 2 0 2->0 4 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j - 2] = 0;
			}
			else if (j == 3 && (*(arr + i))[j] == (*(arr + i))[j - 3] && (*(arr + i))[j - 1] == 0 && (*(arr + i))[j - 2] == 0)
			{//解决出现2 0 0 2->4 0 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i))[j - 3] = 0;
			}
			/*else
			{
				break;
			}*/
		}
		for (int j = 1; j <= 3; j++)
		{//平移
			if ((*(arr + i))[j] == 0 && (*(arr + i))[j - 1] != 0)
			{
				for (int k = j; k > 0; k--)
				{
					(*(arr + i))[k] = (*(arr + i))[k - 1];
				}
				(*(arr + i))[0] = 0;
			}
		}
	}
	return true;
}

//向下合并函数
bool MergeDown(int(*arr)[COL])
{
	for (int j = 0; j < 4; j++)
	{
		//如果出现连续三个相同,先合并靠里面的,也会是说先合并最左边的,所以从左向右循环
		//如果后两个合并后与前一个相同,不会继续和前一个合并
		for (int i = 3; i > 0; i--)
		{//合并
			if ((*(arr + i))[j] == (*(arr + i - 1))[j] && (*(arr + i - 1))[j] != 0)
			{
				(*(arr + i))[j] *= 2;
				(*(arr + i - 1))[j] = 0;
			}
			else if (i > 1 && (*(arr + i))[j] == (*(arr + i - 2))[j] && (*(arr + i - 1))[j] == 0)
			{//解决出现2 0 2 0->4 0 0 0的问题和0 2 0 2->0 4 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i - 2))[j] = 0;
			}
			else if (i == 3 && (*(arr + i))[j] == (*(arr + i - 3))[j] && (*(arr + i - 1))[j] == 0 && (*(arr + i - 2))[j] == 0)
			{//解决出现2 0 0 2->4 0 0 0的问题
				(*(arr + i))[j] *= 2;
				(*(arr + i - 3))[j] = 0;
			}
		}
		for (int i = 1; i < 4; i++)
		{//平移
			if ((*(arr + i))[j] == 0 && (*(arr + i - 1))[j] != 0)
			{
				for (int k = i; k > 0; k--)
				{
					(*(arr + k))[j] = (*(arr + k - 1))[j];
				}
				(*arr)[j] = 0;
			}
		}
	}
	return true;
}

//根据方向键合并相应的数字
//arr:保存数据的数组,dirce :方向值
bool MergeNum(int(*arr)[COL], int dirce)
{
	bool flg = false;
	switch (dirce)
	{
	case 1:
		flg = MergeLeft(arr);//向左合并
		break;
	case 2:
		flg = MergeUp(arr);//向上合并
		break;
	case 3:
		flg = MergeRight(arr);//向右合并
		break;
	case 4:
		flg = MergeDown(arr);//向下合并
		break;
	default:
		break;
	}
	return flg;
}

// 获得方向键键值函数
int GetButton()
{
	int ch;//保存从键盘读取的值

	while (1)

	{
		if (_kbhit())//有击键发生

		{
			ch = _getch();//获取键盘值,不需要回车
			if (ch == 0xE0)//确定是方向键
			{
				ch = _getch();
				if (ch == KEY_LEFT)
					return 1;
				else if (ch == KEY_UP)
					return 2;
				else if (ch == KEY_RIGHT)
					return 3;
				else if (ch == KEY_DOWN)
					return 4;
				else
					return 0;
			}
		}
	}
	ExMessage m;
	while (peekmessage(&m, EX_KEY))
	{
		if (m.message == WM_KEYDOWN)
		{
			switch (m.vkcode)
			{
			case VK_LEFT:
				return 1;
			case VK_UP:
				return 2;
			case VK_RIGHT:
				return 3;
			case VK_DOWN:
				return 4;
			}
		}
	}
	return 0;
}

//判断游戏是否结束函数
bool IsGameover(int(*arr)[COL])
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if ((*arr + i)[j] == 0)
			{
				return false;
			}
			else if (((*(arr + i))[j] == (*(arr + i))[j + 1] && j < 3) || ((*(arr + i))[j] == (*(arr + i + 1))[j] && i < 3))
			{
				return false;
			}
		}
	}
	return true;
}

//运行游戏
void Run(int(*arr)[COL])
{
	int direc; /* 保存方向值 */
	while (1)
	{
		direc = GetButton();//获得方向键键值
		//printf("%d\n", direc);//用于测试
		if (!MergeNum(arr, direc)) //合并和移动数据
		{
			continue;
		}
		if (!GetNum(arr)) /* 游戏结束 */
		{
			return;
		}
		Show(arr);
		if (IsGameover(arr)) //游戏是否结束
		{
			return;
		}
	}
}
//开始游戏
void Start(int(*arr)[COL])
{
	for (int i = 0; i < 2; i++) /* 开始界面必须有两个数字 */
	{

		GetNum(arr);
	}
	Show(arr);
}
int main()
{
	int arr[ROW][COL] = { 0 };
	Start(arr);
	Run(arr);
	printf("Game over!\n");
	return 0;
}
相关推荐
Ajiang282473530438 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空43 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024066 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神7 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式