小老鼠走迷宫

程序用C语言编写,在Visual Studio中调试。要求在规定时间内完成游戏小鼠走迷宫,找到粮食,小鼠形象可辨认,可以在迷宫中上下左右移动,可以手动生成迷宫,编辑迷宫,并实现墙变路、路变墙、显示所有路径、显示最短路径。
输入的形式:通过输入字符“w 、s 、 a、 d”来控制小鼠的上下左右移动,“0、1、2、3”代表通路、老鼠、墙、粮。0~7共八个操作编号。
输出的形式:符号 “▉” 和 “の” 分别表示墙体和可通路径,老鼠和粮食用汉字“鼠”,“粮”表示
程序所能达到的功能:可进行规定时间内老鼠走迷宫,老鼠形态动态可辨认;可以手动生成迷宫,修改迷宫,保存迷宫,显示新建迷宫;可以显示最短路径,所有路径。
 

主要模块

游戏模块:void  game()
新建地图模块:void  create_plat() 
查看地图模块:void  show_plat() 
修改地图模块:void  alter_plat()
读取地图模块:void  read_plat() 
最短路径模块:void  path_best(int p, int q, int l)   
所有路径模块:void  path_result(int p, int q)
时间模块:time(null)
 

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include<time.h>
#define M 9
#define N 9
//0代表通路,2代表墙体,1是老鼠位置,3是粮仓位置
int maze[M][N] = {
	{ 2,2,2,2,2,2,2,2,2 },
	{ 2,0,0,0,2,0,0,0,2 },
	{ 2,0,2,0,0,0,2,2,2 },
	{ 2,0,0,2,2,0,0,0,2 },
	{ 2,0,0,0,1,2,2,0,2 },
	{ 2,0,2,0,2,0,0,0,2 },
	{ 2,0,2,0,2,0,0,2,2 },
	{ 2,0,0,0,0,0,0,3,2 },
	{ 2,2,2,2,2,2,2,2,2 }
};


struct best                  //用于记录最短路径的结构体
{
	int min;
	int b[M][N];
}Best;

int m = 4, n = 4;            //老鼠的初始位置
int p = 4, q = 4;           //老鼠位置二次定位
int x = 7, y = 7;            //粮仓初始位置
int g, answer;		    //g:统计有效路径,防止路径过多,造成循环过度;
						//answer:统计该地图的所有可能性;

void game()  //走迷宫游戏,包含时间统计,以及对老鼠的移动控制,游戏模块
{
	int i, j, v = 0, t = 0;          //t为初始时间
									 //v代表移动成功后,v加1,否则加0
	char str;                      //存放字符w,s,a,d
	time_t start, end;
	start = time(NULL);

	maze[x][y] = 3;        //放粮仓的位置

	m = p;
	n = q;
	maze[m][n] = 1;    //重新定位老鼠位置

	printf("显示迷宫:\n");     //地图初始化
	for (i = 0; i < M; i++)
	{
		for (j = 0; j < N; j++)
		{
			if (maze[i][j] == 2) {
				printf("▉");
			}

			else if (maze[i][j] == 1)
			{
				printf("鼠");
			}
			else if (maze[i][j] == 3)
			{
				printf("粮");
			}
			else
			{
				printf("  ");
			}
		}
		printf("\n");
	}
	printf("(按w↑s↓a← d→移动)\n请在60秒内通关\n"); //初始化地图

	while (1)
	{
		printf("时间:%d\r", t);
		if (kbhit())	 //输入控制
						 //如果有输入就返回非零值,否则返回0.
		{
			str = getch();    //接受用户从键盘输入的字符,并存入str中
			if (str == 'w') //上
			{
				if (maze[m - 1][n] == 0)
				{
					maze[m - 1][n] = 1;
					maze[m][n] = 0;
					m = m - 1;
				}
				else if (maze[m - 1][n] == 3)
				{
					maze[m][n] = 0;
					v = 1;
				}
			}
			else if (str == 's')   //下
			{
				if (maze[m + 1][n] == 0)
				{
					maze[m + 1][n] = 1;
					maze[m][n] = 0;
					m = m + 1;
				}
				else if (maze[m + 1][n] == 3)
				{
					maze[m][n] = 0;
					v = 1;
				}
			}
			else if (str == 'a')   //左
			{
				if (maze[m][n - 1] == 0)
				{
					maze[m][n - 1] = 1;
					maze[m][n] = 0;
					n = n - 1;
				}
				else if (maze[m][n - 1] == 3)
				{
					maze[m][n] = 0;
					v = 1;
				}
			}
			else if (str == 'd')  //右
			{
				if (maze[m][n + 1] == 0)
				{
					maze[m][n + 1] = 1;
					maze[m][n] = 0;
					n = n + 1;
				}
				else if (maze[m][n + 1] == 3)
				{
					maze[m][n] = 0;
					v = 1;
				}
			}
			else;

			system("cls");   //cls是为了清屏
			printf("显示迷宫:\n");  //显示游戏地图
			for (i = 0; i < M; i++)
			{
				for (j = 0; j < N; j++)
				{
					if (maze[i][j] == 2)
					{
						printf("▉");
					}

					else if (maze[i][j] == 1)
					{
						printf("鼠");
					}
					else if (maze[i][j] == 3)
					{
						printf("粮");
					}
					else
					{
						printf("  ");
					}
				}
				printf("\n");
			}
			printf("(按w↑s↓a← d→移动)\n请在60秒内通关\n");
		}
		else;

		if (v == 1)  //判断是否通关
		{
			printf("\n恭喜通关!\n");
			system("pause");
			break;
		}

		if (t>60)   //规定时间到后结束游戏
		{
			printf("\n未在规定时间内通关,游戏失败。\n");
			maze[m][n] = 0;   //清除最后所在位置
			system("pause");
			break;
		}

		end = time(NULL);
		t = difftime(end, start);
	}

}

void create_plat()   //新建地图,并存入文件的模块
{
	int i, j, s;
cc:	printf("请输入0和2,0代表通路,2代表墙体(数字用空格隔开),输入规格是%dx%d,有边缘墙体无需再次输入\n", M - 2, M - 2);
	for (i = 1; i <= M - 2; i++)
	{
		printf("第%d行:", i);
		for (j = 1; j <= N - 2; j++)
		{
			scanf("%d", &s);
			if (s == 0 || s == 2)
				maze[i][j] = s;
			else
			{
				system("cls");         //清屏
				printf("输入错误请重新输入!\n");
				goto cc;           //跳转到cc去做执行
			}
		}
	}

aa: printf("请设置老鼠的初始位置x,y即行列(1~%d,1~%d):\n", M - 2, N - 2);

	for (i = 0; i<30; i++)
		fflush(stdin);     //清除来自键盘的30多个缓存字符,防止死循环bug

	scanf("%d,%d", &p, &q);
	if (p <= (M - 2) && q <= (M - 2) && p>0 && q>0)
		maze[p][q] = 1;
	else
	{
		system("cls");    //清屏
		printf("输入错误,请重新输入,在%dx%d的范围内。\n", M - 2, N - 2);
		goto aa;
	}

bb: printf("请设置粮仓的位置x,y:\n");

	//清除来自键盘的30多个缓存字符,防止死循环bug
	for (i = 0; i<30; i++)
		fflush(stdin);

	scanf("%d,%d", &x, &y);
	if (x <= (M - 2) && y <= (N - 2) && x>0 && y>0 && (x != p || y != q))
		maze[x][y] = 3;
	else
	{
		system("cls");
		printf("输入错误,请重新输入,在%dx%d的范围内。\n", M - 2, N - 2);
		goto bb;
	}

	//文件保存地图
	FILE *fp;
	fp = fopen("plat.txt", "w");
	for (i = 0; i<M; i++)
	{
		for (j = 0; j<N; j++)
			fprintf(fp, "%d\t", maze[i][j]);
		fprintf(fp, "%c", '\n');
	}
	fprintf(fp, "%d\t", p);
	fprintf(fp, "%d\t", q);
	fprintf(fp, "%d\t", x);
	fprintf(fp, "%d\t", y);
	fclose(fp);

	printf("地图新建完成,并保存成功!\n");
	system("pause");
}

void show_plat()   //地图展示模块
{
	int i, j;
	system("cls");

	maze[x][y] = 3;    //粮仓位置

	m = p;
	n = q;
	maze[m][n] = 1;      //老鼠位置

	printf("显示迷宫:\n");  //显示游戏地图
	for (i = 0; i < M; i++)
	{
		for (j = 0; j < N; j++)
		{
			if (maze[i][j] == 2)
			{
				printf("▉");
			}

			else if (maze[i][j] == 1)
			{
				printf("鼠");
			}
			else if (maze[i][j] == 3)
			{
				printf("粮");
			}
			else
			{
				printf("  ");
			}
		}
		printf("\n");
	}
	printf("已显示地图\n");
	system("pause");
}

void alter_plat()    //修改地图模块
{
	int i, j, select, a, b;
	FILE *fp;
	while (1)
	{
		system("cls");

		m = p;
		n = q;
		maze[m][n] = 1;

		printf("显示迷宫:\n");  //显示游戏地图
		for (i = 0; i < M; i++)
		{
			for (j = 0; j < N; j++)
			{
				if (maze[i][j] == 2)
				{
					printf("▉");
				}

				else if (maze[i][j] == 1)
				{
					printf("鼠");
				}
				else if (maze[i][j] == 3)
				{
					printf("粮");
				}
				else
				{
					printf("  ");
				}
			}
			printf("\n");
		}
		printf("  =============----修改地图------===================\n");
		printf(" |请选择:                                          |\n");
		printf(" |              1.修改为墙体;                      |\n");
		printf(" |              2.修改为通路;                      |\n");
		printf(" |              3.保存修改地图;                    |\n");
		printf(" |              0.退出修改功能;                    |\n");
		printf("  ===========(请输入相应数字执行其功能)===========\n");
		fflush(stdin);  //清除键入的缓存
		scanf("%d", &select);

		if (select<4 && select >= 0)
		{
			switch (select)
			{
			case 1:	printf("围墙内为修改范围,范围是%dx%d\n", M - 2, N - 2);
				printf("请输入坐标x,y(行,列)修改地图:\n");

				//清除来自键盘的30多个缓存字符,防止死循环bug
				for (i = 0; i<30; i++)
					fflush(stdin);

				scanf("%d,%d", &a, &b);
				if (a <= (M - 2) && b <= (N - 2) && a>0 && b>0 && maze[a][b] != 1 && maze[a][b] != 3)
					maze[a][b] = 2;
				else
				{
					printf("输入错误请重新输入,不能在围墙、粮仓和老鼠的位置修改!\n");
					system("pause");
				}
				break;
			case 2:	printf("围墙内为修改范围,范围是%dx%d\n", M - 2, N - 2);
				printf("请输入坐标x,y(行,列)修改地图:\n");
				//清除来自键盘的30多个缓存字符,防止死循环bug
				for (i = 0; i<30; i++)
					fflush(stdin);

				scanf("%d,%d", &a, &b);
				if (a <= (M - 2) && b <= (N - 2) && a>0 && b>0 && maze[a][b] != 1 && maze[a][b] != 3)
					maze[a][b] = 0;
				else
				{
					printf("输入错误请重新输入,不能在围墙、粮仓和老鼠的位置修改!\n");
					system("pause");
				}
				break;
			case 3:
			{			//文件形式保存修改后地图
				fp = fopen("plat.txt", "w");
				for (i = 0; i<M; i++)
				{
					for (j = 0; j<N; j++)
						fprintf(fp, "%d\t", maze[i][j]);
					fprintf(fp, "%c", '\n');
				}
				fprintf(fp, "%d\t", p);
				fprintf(fp, "%d\t", q);
				fprintf(fp, "%d\t", x);
				fprintf(fp, "%d\t", y);
				fclose(fp);

				printf("地图修改完成,并保存成功!\n");
				system("pause");
			}
			break;
			case 0: break;
			}
		}
		else
		{
			printf("请按规定输入!\n");
			system("pause");
		}

		if (select == 0)
			break;
	}
}

void read_plat()  //读取文件里的地图模块
{
	int i, j;
	FILE *fp;
	fp = fopen("plat.txt", "r");
	if (!fp)
	{
		printf("文件不存在,请重新打开!\n");
		system("pause");
	}
	else
	{
		for (i = 0; i<M; i++)
		{
			for (j = 0; j<N; j++)
				fscanf(fp, "%d\t", &maze[i][j]);
			fscanf(fp, "\n");
		}
		fscanf(fp, "%d\t", &p);
		fscanf(fp, "%d\t", &q);    //读取老鼠的位置
		fscanf(fp, "%d\t", &x);
		fscanf(fp, "%d\t", &y);   //读取粮仓的位置
		printf("读取成功,请查看新地图!\n");
		system("pause");
	}
	fclose(fp);
}

void path_result(int p, int q)  
       //统计地图的所有可能出现的路径结果,并把次数赋给全局变量answer
      //并在path_result函数中引用变量,作为递归终止和显示最优解的条件
{
	int i, j;
	maze[p][q] = 1;

	if (maze[p][q + 1] == 3 || maze[p][q - 1] == 3 || maze[p + 1][q] == 3 || maze[p - 1][q] == 3)  
		//判断当前位置上下左右是否有粮仓
	{
		++answer;    //统计一个地图的所有可能性的次数
		printf("已计算%d次,若超过1 h,请重启\r", answer);
	}
	// 递归部分,即寻找路径的部分
	if (maze[p][q + 1] == 0) path_result(p, q + 1);  //右
	if (maze[p + 1][q] == 0) path_result(p + 1, q);  //下
	if (maze[p][q - 1] == 0) path_result(p, q - 1);  //左
	if (maze[p - 1][q] == 0) path_result(p - 1, q);  //上
	maze[p][q] = 0;

}


void path_best(int p, int q, int l)     //显示最优路径的模块
{
	int i, j, c, k;

	maze[p][q] = 1;

	if (maze[p][q + 1] == 3 || maze[p][q - 1] == 3 || maze[p + 1][q] == 3 || maze[p - 1][q] == 3)   //判断当前位置上下左右是否有粮仓
	{
		if (Best.min>l)
		{
			Best.min = l;
			for (i = 0; i < M; i++)
				for (j = 0; j< N; j++)
					Best.b[i][j] = maze[i][j];
		}
		g++;
		k = ((double)g / answer) / 2 * 100 + 50;  //计算后面一半完成的百分比情况

		printf("已完成%d%%,请继续等待\r", k);

		c = g;

		if (c == answer)               //防止过度循环,比较answer条路径。
		{
			printf("已列举最优解!%d个方案中的最优解\n", answer);
			for (i = 0; i < M; i++)
			{
				for (j = 0; j< N; j++)
					if (Best.b[i][j] == 2)
					{
						printf("█");
					}
					else if (Best.b[i][j] == 1)
						printf("の");
					else if (Best.b[i][j] == 3)
						printf("粮");
					else
						printf("  ");
				printf("\n");
			}
			printf("已显示最优解,方案如上!\n");
			maze[p][q] = 0;
			return;
			exit(0);
		}

	}

	++l;

	if (g != answer)
	{
		if (maze[p][q + 1] == 0) path_best(p, q + 1, l);  //右
		if (maze[p + 1][q] == 0) path_best(p + 1, q, l);  //下
		if (maze[p][q - 1] == 0) path_best(p, q - 1, l);  //左
		if (maze[p - 1][q] == 0) path_best(p - 1, q, l);  //上
	}
	maze[p][q] = 0;
}

void path_find(int p, int q)  //寻找通关路径的模块
{
	int i, j, c;
	maze[p][q] = 1;

	c = g;
	if (c == 15)               //防止过度循环,暂时只能显示15条路径,可调节。
	{
		printf("已列举10种可行方案!!方案太多可能列举不完,所以最多列举15个\r");
		maze[p][q] = 0;
		return;
		//	exit(0);
	}

	if (maze[p][q + 1] == 3 || maze[p][q - 1] == 3 || maze[p + 1][q] == 3 || maze[p - 1][q] == 3)
		//判断当前位置上下左右是否有粮仓
	{
		printf("显示路径: \n");
		for (i = 0; i < M; i++)
		{
			for (j = 0; j< N; j++)
			{
				if (maze[i][j] == 2)
				{
					printf("█");
				}
				else if (maze[i][j] == 1)
					printf("の");
				else if (maze[i][j] == 3)
					printf("粮");
				else
					printf("  ");
			}
			printf("\n");
		}
		printf("已显示方案,如上!\n");
		g++;
	}

	if (g != 15)
	{
		if (maze[p][q + 1] == 0) path_find(p, q + 1);  //右
		if (maze[p + 1][q] == 0) path_find(p + 1, q);  //下
		if (maze[p][q - 1] == 0) path_find(p, q - 1);  //左
		if (maze[p - 1][q] == 0) path_find(p - 1, q);  //上
	}
	maze[p][q] = 0;
}

void main()   //主函数,菜单控制界面
{            //全局变量:m,n老鼠位置,p,q老鼠初始位置x,y粮仓的初始位置
			 //g统计所有有效路径的次数,最多十次,防止因为路径过多而死循环;
	int select, k;
	time_t start, end;
	int hour, minute, second, t;   //时间变量

	while (1)
	{
		system("cls");
		printf("  =============老鼠走迷宫游戏 n.0===================\n");
		printf(" |请选择:                                          |\n");
		printf(" |              1.开始游戏;                        |\n");
		printf(" |              2.新建地图;                        |\n");
		printf(" |              3.查看地图;                        |\n");
		printf(" |              4.修改地图;                        |\n");
		printf(" |              5.读取地图;                        |\n");
		printf(" |              6.显示最短路径;                    |\n");
		printf(" |              7.显示通关所有路径;                |\n");
		printf(" |              0.退出系统;                        |\n");
		printf("  ===========(请输入相应数字执行其功能)===========\n");
		printf(" 注意事项:\n 地图不要全空,否则不要执行6,7选项,会运算十亿次花费很长时间,尽量把通关所有路径设置在一亿种以内!\n");
		for (k = 0; k<30; k++)
			fflush(stdin);  //清除键盘输入的scanf缓存,防止死循环

		scanf("%d", &select);
		if (select >= 0 && select<8)    //键盘输入检错
		{
			switch (select)
			{
			case 0:  exit(0);
			case 1:	 system("cls");  //清除菜单 
				game();        //开始游戏
				break;
			case 2:  create_plat();  //新建地图
				break;
			case 3:  show_plat();   //显示地图
				break;
			case 4:  alter_plat();  //修改地图
				break;
			case 5:  read_plat();   //在文件里读取地图
				break;
			case 6:  g = 0; Best.min = 999; answer = 0;
				start = time(NULL);
				path_result(p, q);    //统计地图所有解的个数
				path_best(p, q, 1);   //寻找最短的路径
				end = time(NULL);
				t = difftime(end, start);
				second = t % 60;     //求出秒
				minute = t / 60;        //总分数
				hour = minute / 60;      //求出小时
				minute = minute % 60;   //求出分
				printf("花费时间:%dh %dm %ds", hour, minute, second);
				//显示寻找最短路径所花费的时间
				system("pause");
				break;
			case 7:  g = 0;
				path_find(p, q);   //寻找所有通关路径
				printf("已显示所有路径! \n");
				system("pause");
				break;
			default:
				break;
			}
		}
		else
		{
			printf("请按规定输入!\n");
			system("pause");
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_43765564/article/details/85779974