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

C实现2048

翟奇逸
2023-12-01

C的简单新手小游戏练习,知识基本是数组,用到指针的比较少,代码含有少量简单的C++,个人认为2048的核心是数字的移动与合并,其次是玩家有效操作的判断,与井字棋有点像。

代码实现了2048的基本功能,数字移动、合并、随机数产生在随机空白位置、有效操作判定、步数记录、得分情况、放弃本局游戏,以及通过修改宏定义常量值能玩更大的棋盘。如果加入文件的读写应该可以多一个排行榜功能。

目前存在情况是随着数字的位数增加界面框会歪斜,以及在游戏菜单界面输入字母直接退出。

代码如下

game.h 文件

#pragma once
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define ROW 4
#define COL 4

extern void Intialize(int (*p)[COL]);
extern void Checkerboard(int (*p)[COL]);
extern void Random(int (*p)[COL],int k);
extern void MoveAss(int(*p)[COL], int i, int j,char o);
//extern void Valid(int(*p)[COL],char o,char q,int* g);
//extern void Valid(int(*p)[COL], char o, int q);
extern int Move(int(*p)[COL], char o);
extern void Operate(int (*p)[COL],int k,int* c,int* g);
extern int Criterion(int (*p)[COL]);
extern void Progress(int (*p)[COL]);


game.cpp 文件
#include "game.h"

//界面初始化
void Intialize(int (*p)[COL])
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROW; i++)//遍历
	{
		for (j = 0; j < COL; j++)
			p[i][j] = 0;
	}
}
//打印界面
void Checkerboard(int (*p)[COL])
{
	int i = 0;
	int j = 0;
	for (i = 0; i < ROW; i++)
	{
		for (j = 0; j < COL; j++)
		{
			if (j == COL - 1)
			{
				if (p[i][j])
					cout << ' ' << p[i][j];
				else
					cout << ' ' << ' ';//掩盖 0 
			}
			else
			{
				if (p[i][j])
					cout << ' ' << p[i][j] << ' ' << '|';//打印  p[][] |  单元
				else
					cout << ' ' << ' ' << ' ' << '|';//掩盖 0 
			}
		}
		cout << endl;
		for (j = 0; j < COL; j++)
		{
			if (i != ROW-1)
				cout << "----";//打印 ---  单元
			if (j == COL - 1)
				cout << endl;
		}
	}
	cout << endl;
}
//在界面随机生成一个2/4数字
void Random(int (*p)[COL],int k)
{
	int x = 0;
	int y = 0;
	if (k != 2048)
	{
		if (k)
		{
			while (1)//生成一个随机数
			{
				x = rand() % ROW;
				y = rand() % COL;
				if (p[x][y] == 0)//寻找空位
				{
					p[x][y] =(rand() % 2 + 1) * 2;
					break;//(rand()%2+1)*2随机生成2/4数字
				}
			}
		}
		if (k != ROW * COL)
			Checkerboard(p);//在界面上显示
	}
}
//辅助移动
void MoveAss(int(*p)[COL],int i,int j,char o)
{
	switch (o)
	{
	case 'w':
	{
		if (p[i][j])
		{
			if ((i != 0)&&(i <= ROW-1))
			{
				if (p[i - 1][j] == 0)
				{
					p[i - 1][j] = p[i][j];
					p[i][j] = 0;
					MoveAss(p, i + 1, j, o);//递归调用
				}
			}
		}
		break;
	}
	case 's':
	{
		if (p[i][j])
		{
			if ((i != ROW-1)&&(i >= 0))
			{
				if (p[i + 1][j] == 0)
				{
					p[i + 1][j] = p[i][j];
					p[i][j] = 0;
					MoveAss(p, i - 1, j, o);//递归调用
				}
			}
		}
		break;
	}
	case 'a':
	{
		if (p[i][j])
		{
			if ((j != 0)&&(j <= COL - 1))
			{
				if (p[i][j - 1] == 0)
				{
					p[i][j - 1] = p[i][j];
					p[i][j] = 0;
					MoveAss(p, i, j + 1, o);//递归调用
				}
			}
		}
		break;
	}
	case 'd':
	{
		if (p[i][j])
		{
			if ((j != ROW - 1)&&(j >= 0))
			{
				if (p[i][j + 1] == 0)
				{
					p[i][j + 1] = p[i][j];
					p[i][j] = 0;
					MoveAss(p, i, j - 1, o);//递归调用
				}
			}
		}
		break;
	}
	}
}
//数字移动与合并
int Move(int (*p)[COL],char o)
{
	int i = 0;
	int j = 0;
	int g = 0;
	switch (o)
	{
	case 'w':
	{
		for (i = ROW - 1; i >= 0; i--)//移动
		{
			for (j = COL - 1; j >= 0; j--)
			{
				MoveAss(p, i, j, o);
			}
		}
		for (i = 0; i < ROW-1; i++)//合并
		{
			for (j = 0; j < COL; j++)
			{
				if (p[i][j] == p[i + 1][j])
				{
					p[i][j] = 2 * p[i][j];
					g = g + p[i][j];
					p[i + 1][j] = 0;
				}
			}
		}
		for (i = ROW - 1; i >= 0; i--)//移动
		{
			for (j = COL - 1; j >= 0; j--)
				MoveAss(p,i,j,o);
		}
		break;
	}
	case 's':
	{
		for (i = 0; i < ROW; i++)//移动
		{
			for (j = 0; j < COL; j++)
			{
				MoveAss(p, i, j, o);
			}
		}
		for (i = ROW-1; i > 0; i--)//合并
		{
			for (j = 0; j < COL; j++)
			{
				if (p[i][j] == p[i - 1][j])
				{
					p[i][j] = 2 * p[i][j];
					g = g + p[i][j];
					p[i - 1][j] = 0;
				}
			}
		}
		for (i = 0; i < ROW; i++)//移动
		{
			for (j = 0; j < COL; j++)
				MoveAss(p, i, j, o);
		}
		break;
	}
	case 'a':
	{
		for (j = COL - 1; j >= 0; j--)//移动
		{
			for (i = ROW - 1; i >= 0; i--)
			{
				MoveAss(p, i, j, o);
			}
		}
		for (j = 0; j < COL - 1; j++)//合并
		{
			for (i = 0; i < ROW; i++)
			{
				if (p[i][j] == p[i][j + 1])
				{
					p[i][j] = 2 * p[i][j];
					g = g + p[i][j];
					p[i][j + 1] = 0;
				}
			}
		}
		for (j = COL - 1; j >= 0; j--)//移动
		{
			for (i = ROW - 1; i >= 0; i--)
				MoveAss(p, i, j, o);
		}
		break;
	}
	case 'd':
	{
		for (j = 0; j < COL; j++)//移动
		{
			for (i = 0; i < ROW; i++)
			{
				MoveAss(p, i, j, o);
			}
		}
		for (j = COL-1; j > 0; j--)//合并
		{
			for (i = 0; i < ROW; i++)
			{
				if (p[i][j] == p[i][j - 1])
				{
					p[i][j] = 2 * p[i][j];
					g = g + p[i][j];
					p[i][j - 1] = 0;
				}
			}
		}
		for (j = 0; j < COL; j++)//移动
		{
			for (i = 0; i < ROW; i++)
				MoveAss(p, i, j, o);
		}
		break;
	}
	}
	return g;
}
//有效移动判定
int Valid(int (*p)[COL],char o,char q,int* g)//重载,通过参数为字符还是整形来调用同名的不同函数
{
	int arr1[ROW][COL];
	int i = 0;
	int j = 0;
	int v = 0;
	for (i = 0; i < ROW; i++)//拷贝一份
	{
		for (j = 0; j < COL; j++)
		{
			arr1[i][j] = p[i][j];
		}
	}
	*g = *g + Move(p, o);
	for (i = 0; i < ROW; i++)
	{
		for (j = 0; j < COL; j++)
		{
			if (arr1[i][j] != p[i][j])
			{
				v = 1;
				break;
			}
		}
		if (v == 1)
			break;
	}
	return v;
}
int Valid(int(*p)[COL], char o,int q)//重载,通过参数为字符还是整形来调用同名的不同函数
{
	int arr1[ROW][COL];
	int i = 0;
	int j = 0;
	int v = 0;
	for (i = 0; i < ROW; i++)//拷贝一份
	{
		for (j = 0; j < COL; j++)
		{
			arr1[i][j] = p[i][j];
		}
	}
	Move(arr1, o);
	for (i = 0; i < ROW; i++)
	{
		for (j = 0; j < COL; j++)
		{
			if (arr1[i][j] != p[i][j])
			{
				v = 1;
				break;
			}
		}
		if (v == 1)
			break;
	}
	return v;
}
//玩家操作
void Operate(int (*p)[COL],int* k,int* c,int* g)
{
	char o = '0';
	char ret[20];
	while (1)
	{
		cout << "请输入:" << endl;
		cin >> ret;
		o = ret[0];//只读取输入的第一个字符
		if (o == 'w' || o == 's' || o == 'a' || o == 'd')
		{
			if (Valid(p, o, 'q', g))
			{
				*c = *c + 1;
				break;
			}
			else
				cout << "无效移动" << endl;
		}
		else if (o == '0')
			break;
		else
			cout << "输入错误" << endl;
	}
	if (o == '0')
		*k = -1;
	else
		Checkerboard(p);
}
//游戏结束判定
int Criterion(int (*p)[COL])
{
	int i = 0;
	int j = 0;
	int k = COL * ROW;//空格剩余数
	for (i = 0; i < ROW; i++)
	{
		for (j = 0; j < COL; j++)
		{
			if (p[i][j] == 2048)//胜利
			{
				k = 2048;
				break;
			}
			if (p[i][j] != 0)
				k--;
		}
		if (k == 2048)
			break;
	}
	return k;
}
//控制游戏进程
void Progress(int (*p)[COL])
{
	int k = ROW * COL;//初始空格数
	int count = 0;
	int grade = 0;
	Random(p,k);
	while(1)
	{
		k = Criterion(p);
		Random(p,k);
		if ((k > 0) && (k != 2048))
			k = k - 1;
		if (k == 2048)
		{
			cout << "恭喜,你赢了!" << endl;
			break;
		}
		if (k == 0)
		{
			if ((Valid(p, 'w',1) || Valid(p, 's',1) || Valid(p, 'a',1) || Valid(p, 'd',1)) == 0)
			{
				cout << "很遗憾,你输了。" << endl;
				break;
			}
		}
		Operate(p, &k,&count,&grade);
		if (k == -1)
		{
			cout << "已放弃当前游戏。" << endl;
			break;
		}
		cout << "步数: " << count << "     ";
		cout << "分数: " << grade << endl << endl;
	}
}


test.cpp 文件

#include "game.h"

void nume()
{
	cout << endl;
	cout << "*****************************" << endl;
	cout << "******   2  0  4  8   *******" << endl;
	cout << "******     1:paly     *******" << endl;
	cout << "******     0:exit     *******" << endl;
	cout << "*****************************" << endl << endl;
}

void game()
{
	int ARR[ROW][COL] = {0};
	int (*p)[COL] = ARR;
	Intialize(p);
	//Checkerboard(p);
	Procgress(p);
}

void select()
{
	int input = 0;
	do
	{
		nume();
		srand((unsigned int)time(NULL));
		cout << "请选择" << endl << endl;
		cin >> input;
		cout << endl;
		switch (input)
		{
		case 1:
			cout << "开始游戏" << endl << endl;
			cout << "  w:上移  s:下移" << endl << endl;
			cout << "  a:左移  d:右移" << endl << endl;
			cout << "  0:放弃当前游戏" << endl << endl;
			game();
			break;
		case 0:
			cout << "退出" << endl;
			break;
		default:
			cout << "选择错误,请重新选择" << endl<<endl;
			break;
		}
	} while (input);
}
int main()
{
	srand((unsigned int)time(NULL));
	select();
	return 0;
}

 类似资料: