C语言推箱子小游戏(可以悔步)

悔步是通过链表来实现的,在人物推动箱子移动后,记录人物移动方向和箱子运动情况,记录数据时用头插法,悔步时直接读取链表中数据即可。

代码如下:

//*
#include<stdio.h>
#include<conio.h>    //system("cls")   //_getch();
#include<windows.h> //Sleep();
#include<stdlib.h>


int map[10][10] =  //游戏地图
{
	{0,0,0,0,1,1,1,0,0,0},
	{0,0,0,0,1,2,1,0,0,0},
	{0,0,0,0,1,0,1,0,0,0},
	{0,0,0,0,1,4,1,1,1,1},
	{1,1,1,1,1,0,4,0,2,1},
	{1,2,0,4,0,3,1,1,1,1},
	{1,1,1,1,4,1,0,0,0,0},
	{0,0,0,1,0,1,0,0,0,0},
	{0,0,0,1,2,1,0,0,0,0},
	{0,0,0,1,1,1,0,0,0,0}
};

//int map[10][10] =   //测试地图
//{
//	{1,1,1,1,1,1,1,1,1,1},
//	{1,0,0,0,0,2,0,0,0,1},
//	{1,0,0,0,0,0,0,0,0,1},
//	{1,2,0,0,0,4,0,0,0,1},
//	{1,0,2,2,0,0,4,0,2,1},
//	{1,2,0,4,0,3,0,0,0,1},
//	{1,0,0,0,4,0,0,0,0,1},
//	{1,0,0,0,0,0,0,2,0,1},
//	{1,0,0,0,2,0,0,0,0,1},
//	{1,1,1,1,1,1,1,1,1,1}
//};

struct HistoryStep
{
	int boxIsMove;  //记录人物移动是否推动箱子
	int direction; //记录人物移动的运动方向
	struct HistoryStep* next;
};


struct HistoryStep* hStep_List(int direction, struct HistoryStep* head,int NextIsBox); //单链表记录人物的运动方向(头插法)
struct HistoryStep* Regret_Step(struct HistoryStep* head); //悔步,利用链表中记录的数据来悔步
void NoUse();     //游戏说明
void DrawMap();   //绘制地图
void UpMove(int row, int col, int regret);     //人向上移动 ,regret是悔步信号
void DownMove(int row, int col, int regret);   //人向下移动
void LeftMove(int row, int col, int regret);   //人向左移动
void RightMove(int row, int col, int regret);  //人向右移动
int NextIsBox(char input, int row, int col);   //判断人物下一位置是否是箱子
int JudgeMove(int num, int row, int col);      //判断人物是否移动
struct HistoryStep* PlayGame(struct HistoryStep* head);      //运行游戏
int GameOver();   //判断游戏是否结束


struct HistoryStep* hStep_List(int direction, struct HistoryStep* head, int NextIsBox)// 头插法创建单链表
{
	static int i = 0;
	struct HistoryStep* q = head;
	struct HistoryStep* p = (struct HistoryStep*)malloc(sizeof(struct HistoryStep));
	if (p)
	{
		p->boxIsMove = NextIsBox;
		p->direction = direction;
		p->next = NULL;
	}

	if (i == 0)
	{
		head = p;
		i++;
	}
	else
	{
		head = p;
		if (head)
		{
			head->next = q;
		}
	}
	return head;
}

struct HistoryStep* Regret_Step(struct HistoryStep* head) //悔步
{
	int row = -1, col = -1;//初始化人的坐标
	for (int i = 0; i < 10; i++)//行
	{
		for (int j = 0; j < 10; j++)//列
		{
			if (map[i][j] == 3 || map[i][j] == 5)//找到人的位置
			{
				row = i;
				col = j;
			}
		}
	}
	switch (head->direction)
	{
	case 72:
		DownMove(row, col, head->boxIsMove);//人物向下移动,如果悔步信号为1,同时移动箱子
		break;
	case 75:
		RightMove(row, col, head->boxIsMove);
		break;
	case 80:
		UpMove(row, col, head->boxIsMove);
		break;
	case 77:
		LeftMove(row, col, head->boxIsMove);
		break;
	default:
		break;
	}
	if (head->next)
	{
		head = head->next; //head后移
	}
	else
	{
		head->direction = 0;
	}
	return head;
}

void NoUse()  //游戏说明
{
	printf("\n加载中");
	for (int t = 0; t < 11; t++)
	{
		printf(".");
		Sleep(111);
	}
	printf("\n\n游戏说明:\n\n方向键控制移动\n\n按空格键悔步\n");
	printf("\n按任意键开始游戏\n");
	char c = _getch();
	system("cls");
}

void DrawMap()  //绘制地图
{
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			switch (map[i][j])
			{
			case 0:printf("  ");//路
				break;
			case 1:printf("■");//墙
				break;
			case 2:printf("※");//终点
				break;
			case 3://case 5://人在终点  //此程序的测试地图中有这个情况
				printf("♀");//人
				break;
			case 4:printf("□");//箱子
				break;
			case 6:printf("◆");//箱子到终点
				break;
			default:
				break;
			}
			if (j == 9)
			{
				printf("\n");
			}
		}
	}
}

void UpMove(int row, int col, int regret) //人向上移动
{
	if (map[row - 1][col] == 0 || map[row - 1][col] == 2)//人上面是路或者终点
	{
		map[row - 1][col] += 3; //路变人或者终点变人   0->3 或者 2->5
		map[row][col] -= 3;     //人变路或者终点   3->0 或者 5->2
		if (regret == 1)        //悔步:这一步需要移动箱子
		{
			map[row][col] += 4;//在上面,人已经变路或者终点,这一步路或者终点变箱子  0->4 或者 2->6
			map[row + 1][col] -= 4;  //箱子变路或者终点   6->2 或者 4->0
		}
	}
	else if (map[row - 1][col] == 4 || map[row - 1][col] == 6)//人上面是箱子
	{
		if (map[row - 2][col] == 0 || map[row - 2][col] == 2)//箱子上面路或者终点
		{
			map[row - 2][col] += 4;//路变箱子或者终点变箱子   0->4 或者 2->6
			map[row - 1][col] -= 1;//箱子变人或者箱子在终点变人在终点   4->3 或者 6->5
			map[row][col] -= 3;//人变路或终点   3->0 或者 6->3
		}
	}
}

void DownMove(int row, int col, int regret)//人向下移动
{
	if (map[row + 1][col] == 0 || map[row + 1][col] == 2)
	{
		map[row + 1][col] += 3;
		map[row][col] -= 3;
		if (regret == 1)
		{
			map[row][col] += 4;
			map[row - 1][col] -= 4;
		}
	}
	else if (map[row + 1][col] == 4 || map[row + 1][col] == 6)
	{
		if (map[row + 2][col] == 0 || map[row + 2][col] == 2)
		{
			map[row + 2][col] += 4;
			map[row + 1][col] -= 1;
			map[row][col] -= 3;
		}
	}
}

void LeftMove(int row, int col, int regret)//人向左移动
{
	if (map[row][col - 1] == 0 || map[row][col - 1] == 2)
	{
		map[row][col - 1] += 3;
		map[row][col] -= 3;
		if (regret == 1)
		{
			map[row][col] += 4;
			map[row][col + 1] -= 4;
		}
	}
	else if (map[row][col - 1] == 4 || map[row][col - 1] == 6)
	{
		if (map[row][col - 2] == 0 || map[row][col - 2] == 2)
		{
			map[row][col - 2] += 4;
			map[row][col - 1] -= 1;
			map[row][col] -= 3;
		}
	}
}

void RightMove(int row, int col, int regret)//人向右移动
{
	if (map[row][col + 1] == 0|| map[row][col + 1] == 2)
	{
		map[row][col + 1] += 3;
		map[row][col] -= 3;
		if (regret == 1)
		{
			map[row][col] += 4;
			map[row][col - 1] -= 4;
		}
	}
	else if (map[row][col + 1] == 4|| map[row][col + 1] == 6)
	{
		if (map[row][col + 2] == 0|| map[row][col + 2] == 2)
		{
			map[row][col + 2] += 4;
			map[row][col + 1] -= 1;
			map[row][col] -= 3;
		}
	}
}

int NextIsBox(char input, int row, int col) //判断下一位置是否为箱子
{
	int isBox = 0;
	switch (input)
	{
	case 72:
		if (map[row - 1][col] == 4 || map[row - 1][col] == 6)
		{
			isBox = 1;
		}
		break;
	case 75:
		if (map[row][col - 1] == 4 || map[row][col - 1] == 6)
		{
			isBox = 1;
		}
		break;
	case 80:
		if (map[row + 1][col] == 4 || map[row + 1][col] == 6)
		{
			isBox = 1;
		}
		break;
	case 77:
		if (map[row][col + 1] == 4 || map[row][col + 1] == 6)
		{
			isBox = 1;
		}
		break;
	default:
		break;
	}
	return isBox;
}

int JudgeMove(int num, int row, int col)  //判断人物是否移动
{
	if (map[row][col] == num)
	{
		return 0;
	}
	return 1;
}

struct HistoryStep* PlayGame(struct HistoryStep* head) //运行游戏
{
	int num = 0;            //记录人是3还是5
	int row = -1, col = -1; //初始化人的位置
	int nextIsBox = 0;      //记录人物下一位置是否为箱子

	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (map[i][j] == 3 || map[i][j] == 5)//找到人的位置
			{
				row = i;
				col = j;
				num = map[i][j];
			}
		}
	}
	char input = _getch();//_getch()函数接收键盘输入的数据
	switch (input)
	{
	case 72:  //向上移动  //72是↑的键码值,下面同理
		nextIsBox = NextIsBox(input, row, col); //判断人物下一位置是否为箱子
		UpMove(row, col, 0);  //人向上移动,有箱子时会推动箱子
		if (JudgeMove(num, row, col)) //判断人物是否移动,移动了就记录运动方向
		{
			head = hStep_List(72, head, nextIsBox);
			//printf("%d %d", head->direction, head->boxIsMove); //实时打印人物移动方向数据和箱子移动数据
		}
		break;

	case 75://向左移动
		nextIsBox = NextIsBox(input, row, col);
		LeftMove(row, col, 0);
		if (JudgeMove(num, row, col))
		{
			head = hStep_List(75, head, nextIsBox);
			//printf("%d %d", head->direction, head->boxIsMove);
		}
		break;

	case 80://向下移动
		nextIsBox = NextIsBox(input, row, col);
		DownMove(row, col, 0);
		if (JudgeMove(num, row, col))
		{
			head = hStep_List(80, head, nextIsBox);
			//printf("%d %d", head->direction, head->boxIsMove);
		}
		break;

	case 77://向右移动
		nextIsBox = NextIsBox(input, row, col);
		RightMove(row, col, 0);
		if (JudgeMove(num, row, col))
		{
			head = hStep_List(77, head, nextIsBox);
			//printf("%d %d", head->direction, head->boxIsMove);
		}
		break;

	case 32://悔步
		//printf("%d %d", head->direction, head->boxIsMove);
		head = Regret_Step(head);
		break;
	default:
		break;
	}
	return head;
}

int GameOver()  //判断游戏是否概束
{
	int boxs = 0;
	for (int i = 0; i < 10; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (map[i][j] == 4)
			{
				boxs++;
			}
		}
	}
	return !boxs;
}


int main(void)
{
	struct HistoryStep* head = NULL;
	system("color f0");
	system("mode con cols=27 lines=11");
	NoUse();
	while (1)
	{
		DrawMap();
		head = PlayGame(head);
		if (GameOver())
		{
			DrawMap();
			Sleep(300);
			system("cls");
			break;
		}
		Sleep(50);
		system("cls");
	}

	//for (struct HistoryStep* p = head; p != NULL; p = p->next) //打印链表中记录的运动步骤
	//{
	//	switch (p->direction)
	//	{
	//	case 72:
	//		printf(" ↑ ");
	//		break;
	//	case 75:
	//		printf(" ← ");
	//		break;
	//	case 80:
	//		printf(" ↓ ");
	//		break;
	//	case 77:
	//		printf(" → ");
	//		break;
	//	default:
	//		break;
	//	}
	//}

	printf("\n	恭喜过关!\n\n");
	return 0;
}//*/

本人的运行测试环境为VS2019,写的有问题地方还请指出。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值