迷宫游戏

数据结构课程设计

想不出来写啥,还是用EasyX图形库写了一个走迷宫,就是简单的BFS,记录了一下路径,因为时间比较紧,就随便写了写,把代码放在这吧

编译环境:

Visual Studio 2017(在编译选项里选择多字符集支持,默认是Unicode的字符集)

EasyX图形库

游戏截图

《迷宫游戏》

《迷宫游戏》

《迷宫游戏》

《迷宫游戏》

《迷宫游戏》

代码

#include <graphics.h>
#include <stdio.h>
#include <conio.h>
#include <string>
#include <random>
#include <stack>
#include <windows.h>
#include <time.h>
#include <queue>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

#define Windows_x 1100
#define Windows_y 731
#define maze_x 180
#define maze_y 130

MOUSEMSG m;//鼠标对象

struct  pos//存储每个格子左上和右下的坐标
{
	int x1, y1;
	int x2, y2;
} map[30][30];

int maze[30][30] = { 0 };//广搜中的抽象地图

struct node
{
	int x, y, s;
} s, e;
int go[4][2] = { { 1,0 },{ -1,0 },{ 0,1 },{ 0,-1 } };
int pre[1000001] = { 0 };
int vis[25][25];
void init();//初始化界面
void start();//游戏逻辑分析
int bfs(int x, int y);//进行广搜
void myprint(int n);//进行打印路径

int bfs(int x, int y)
{
	node now, to;
	now.x = x, now.y = y, now.s = 0;
	queue <node>q;
	vis[x][y] = 1;
	q.push(now);
	while (!q.empty())
	{
		now = q.front();
		q.pop();
		if (now.x == e.x&&now.y == e.y)
			return now.s;
		for (int i = 0; i<4; i++)
		{
			int xx = now.x + go[i][0];
			int yy = now.y + go[i][1];
			if (xx >= 0 && xx<20 && yy >= 0 && yy<20 && maze[xx][yy] == 0 && !vis[xx][yy])
			{
				vis[xx][yy] = 1;
				to.x = xx, to.y = yy, to.s = now.s + 1;
				pre[xx * 20 + yy] = now.x * 20 + now.y;
				q.push(to);
			}
		}
	}
	return -1;
}

queue<node>stk;//用队列来存储路径
void myprint(int n)//回溯寻找路径
{
	if (-1 == pre[n])return;
	myprint(pre[n]);
	node t;
	t.x = n / 20, t.y = n % 20;
	stk.push(t);
}

void start()//开始游戏
{
	srand(unsigned(time(0)));//以时间来做随机数种子
	loadimage(NULL, "welcome_0.jpg");
	setlinestyle(PS_SOLID, 2);//设置划线样式
	setlinecolor(BLACK);
	rectangle(maze_x, maze_y, maze_x + 500, maze_y + 500);//迷宫的区域
														  //画出迷宫地图20*20
	for (int x = maze_x; x <= maze_x + 500; x += 25)
		line(x, maze_y, x, maze_y + 500);
	for (int y = maze_y; y <= maze_y + 500; y += 25)
		line(maze_x, y, maze_x + 500, y);
	//存储每个格子的坐标
	for (int i = 0; i<20; i++)
		for (int j = 0; j < 20; j++)
		{
			map[i][j].x1 = maze_x + 25 * j;
			map[i][j].y1 = maze_y + 25 * i;
			map[i][j].x2 = map[i][j].x1 + 25;
			map[i][j].y2 = map[i][j].y1 + 25;
		}
	//画按钮
	setfillcolor(RGB(131, 175, 155));
	fillrectangle(700, 130, 950, 634);
	rectangle(700, 130, 700 + 250, 130 + 84);//设置起点1
	rectangle(700, 130 + 84, 700 + 250, 130 + 84 * 2);//设置终点2
	rectangle(700, 130 + 84 * 2, 700 + 250, 130 + 84 * 3);//设置障碍3
	rectangle(700, 130 + 84 * 3, 700 + 250, 130 + 84 * 4);//随机障碍4
	rectangle(700, 130 + 84 * 4, 700 + 250, 130 + 84 * 5);//开始寻路5
	rectangle(700, 130 + 84 * 5, 700 + 250, 130 + 84 * 6);//重置地图6
	RECT r1 = { 700, 130, 700 + 250, 130 + 84 };
	RECT r2 = { 700, 130 + 84, 700 + 250, 130 + 84 * 2 };
	RECT r3 = { 700, 130 + 84 * 2, 700 + 250, 130 + 84 * 3 };
	RECT r4 = { 700, 130 + 84 * 3, 700 + 250, 130 + 84 * 4 };
	RECT r5 = { 700, 130 + 84 * 4, 700 + 250, 130 + 84 * 5 };
	RECT r6 = { 700, 130 + 84 * 5, 700 + 250, 130 + 84 * 6 };
	settextcolor(BLUE);
	LOGFONT f;
	gettextstyle(&f);                     // 获取当前字体设置
	f.lfHeight = 60;                      // 设置字体高度为 60
	_tcscpy(f.lfFaceName, "微软雅黑");
	f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿
	settextstyle(&f);                     // 设置字体样式
	drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	int MODE = 0;//当前按钮所表示的事件
				 //处理鼠标消息
	while (true)
	{
		BeginBatchDraw();
		m = GetMouseMsg();
		switch (m.uMsg)
		{
		case WM_MOUSEMOVE://监测鼠标移动
			EndBatchDraw();
			if (m.x >= 700 && m.x <= 950 && m.y >= 130 && m.y <= 634)//在按钮区域
			{
				if (m.y >= 130 && m.y < 214)//设置起点
				{
					setfillcolor(RGB(254, 67, 101));
					fillrectangle(700, 130, 950, 214);//r1
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 214, 950, 298);//r2
					fillrectangle(700, 298, 950, 382);//r3
					fillrectangle(700, 382, 950, 466);//r4
					fillrectangle(700, 466, 950, 550);//r5
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
				else if (m.y >= 214 && m.y < 298)//设置终点
				{
					setfillcolor(RGB(254, 67, 101));//r2
					fillrectangle(700, 214, 950, 298);
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 130, 950, 214);//r1
					fillrectangle(700, 298, 950, 382);//r3
					fillrectangle(700, 382, 950, 466);//r4
					fillrectangle(700, 466, 950, 550);//r5
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
				else if (m.y >= 298 && m.y < 382)//设置障碍
				{
					setfillcolor(RGB(254, 67, 101));
					fillrectangle(700, 298, 950, 382);//r3
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 130, 950, 214);//r1
					fillrectangle(700, 214, 950, 298);//r2
					fillrectangle(700, 382, 950, 466);//r4
					fillrectangle(700, 466, 950, 550);//r5
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
				else if (m.y >= 382 && m.y < 466)//随机障碍
				{
					setfillcolor(RGB(254, 67, 101));
					fillrectangle(700, 382, 950, 466);//r4
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 130, 950, 214);//r1
					fillrectangle(700, 214, 950, 298);//r2
					fillrectangle(700, 298, 950, 382);//r3
					fillrectangle(700, 466, 950, 550);//r5
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
				else if (m.y >= 466 && m.y < 550)//开始寻路
				{
					setfillcolor(RGB(254, 67, 101));
					fillrectangle(700, 466, 950, 550);//r5
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 130, 950, 214);//r1
					fillrectangle(700, 214, 950, 298);//r2
					fillrectangle(700, 298, 950, 382);//r3
					fillrectangle(700, 382, 950, 466);//r4
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
				else if (m.y >= 550 && m.y < 634)//重置游戏
				{
					setfillcolor(RGB(254, 67, 101));
					fillrectangle(700, 550, 950, 634);//r6
					drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					setfillcolor(RGB(131, 175, 155));
					fillrectangle(700, 130, 950, 214);//r1
					fillrectangle(700, 214, 950, 298);//r2
					fillrectangle(700, 298, 950, 382);//r3
					fillrectangle(700, 382, 950, 466);//r4
					fillrectangle(700, 466, 950, 550);//r5
					drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
					drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				}
			}
			else
			{
				setfillcolor(RGB(131, 175, 155));
				fillrectangle(700, 130, 950, 214);//r1
				fillrectangle(700, 214, 950, 298);//r2
				fillrectangle(700, 298, 950, 382);//r3
				fillrectangle(700, 382, 950, 466);//r4
				fillrectangle(700, 466, 950, 550);//r5
				fillrectangle(700, 550, 950, 634);//r6
				drawtext("设置起点", &r1, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				drawtext("设置终点", &r2, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				drawtext("设置障碍", &r3, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				drawtext("随机障碍", &r4, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				drawtext("开始寻路", &r5, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
				drawtext("重置游戏", &r6, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
			}
			break;
		case WM_LBUTTONDOWN://鼠标左键按下
			EndBatchDraw();
			if (m.x >= 180 && m.x <= 680 && m.y >= 130 && m.y <= 630)//在迷宫区域
			{
				int tx, ty;//存储抽象坐标
						   //找到当前点击的点在图上的哪一个坐标
				int f = 1;
				pos ans;//存储找到的格子
				for (int i = 0; i < 20 && f; i++)
				{
					for (int j = 0; j < 20 && f; j++)
					{
						if (m.x >= map[i][j].x1&&m.x <= map[i][j].x2&&m.y >= map[i][j].y1&&m.y <= map[i][j].y2)
						{
							f = 0;
							ans = map[i][j];
							tx = i, ty = j;
						}
					}
				}
				//根据坐标绘图
				if (MODE == 1)//起点为红色
				{
					setfillcolor(RED);
					fillrectangle(ans.x1, ans.y1, ans.x2, ans.y2);
					s.x = tx, s.y = ty;
					MODE = 0;
				}
				else if (MODE == 2)//终点为蓝色
				{
					setfillcolor(BLUE);
					fillrectangle(ans.x1, ans.y1, ans.x2, ans.y2);
					e.x = tx, e.y = ty;
					MODE = 0;
				}
				else if (MODE == 3)//障碍为黑色
				{
					setfillcolor(BLACK);
					fillrectangle(ans.x1, ans.y1, ans.x2, ans.y2);
					maze[tx][ty] = 1;
				}
			}
			else if (m.x >= 700 && m.x <= 950 && m.y >= 130 && m.y <= 630)//在按钮区域
			{
				if (m.y >= 130 && m.y < 214)//设置起点区域
				{
					MODE = 1;
				}
				else if (m.y >= 214 && m.y < 298)//设置终点区域
				{
					MODE = 2;
				}
				else if (m.y >= 298 && m.y < 382)//设置障碍区域
				{
					MODE = 3;
				}
				else if (m.y >= 382 && m.y < 466)//随机障碍区域
				{
					int rad[30][30];
					mem(rad, 0);
					for (int cse = 0; cse < 100; cse++)
					{
						int random_x = rand() % 20;
						int random_y = rand() % 20;
						if (maze[random_x][random_y] == 0 && rad[random_x][random_y] == 0
							&&(random_x!=s.x||random_y!=s.y)&&(random_x!=e.x&&random_y!=e.y))
						{
							maze[random_x][random_y] = 1;
							setfillcolor(BLACK);
							pos ans = map[random_x][random_y];
							fillrectangle(ans.x1, ans.y1, ans.x2, ans.y2);
						}
					}
				}
				else if (m.y >= 466 && m.y < 550)//开始寻路区域,BFS
				{
					mem(vis, 0);
					mem(pre, -1);
					int jieguo = bfs(s.x, s.y);
					if (jieguo == -1)
					{
						MessageBox(GetHWnd(), "很遗憾,寻路失败", "提示", 0);
					}
					else
					{
						char temp[30];
						sprintf(temp, "恭喜,寻路成功,一共%d步!", jieguo);
						myprint(e.x * 20 + e.y);
						setfillcolor(YELLOW);
						while (stk.size() != 1 && !stk.empty())
						{
							node fr = stk.front();
							stk.pop();
							Sleep(50);
							fillrectangle(map[fr.x][fr.y].x1, map[fr.x][fr.y].y1, map[fr.x][fr.y].x2, map[fr.x][fr.y].y2);
						}
						MessageBox(GetHWnd(), temp, "提示", 0);
					}
				}
				else if (m.y >= 550 && m.y < 634)//重置游戏区域
				{
					loadimage(NULL, "welcome_0.jpg");
					setlinestyle(PS_SOLID, 2);//设置划线样式
					setlinecolor(BLACK);
					rectangle(maze_x, maze_y, maze_x + 500, maze_y + 500);//迷宫的区域
																		  //画出迷宫地图20*20
					for (int x = maze_x; x <= maze_x + 500; x += 25)
						line(x, maze_y, x, maze_y + 500);
					for (int y = maze_y; y <= maze_y + 500; y += 25)
						line(maze_x, y, maze_x + 500, y);
					MODE = 0;
					mem(vis, 0);
					mem(maze, 0);
					mem(pre, -1);
					while (!stk.empty())
					{
						stk.pop();
					}
				}
			}
			break;
		}
	}
	_getch();              // 按任意键继续
	closegraph();          // 关闭绘图窗口
}
void init()//对开始界面进行渲染
{
	initgraph(Windows_x, Windows_y);
	loadimage(NULL, "welcome.jpg");
	setbkmode(TRANSPARENT);//透明字体
	HWND hwnd = GetHWnd();//获取当前窗口句柄
	SetWindowText(hwnd, "迷宫自动寻路   --- By:贺鹏程");//设置窗口标题
	settextcolor(RGB(77, 77, 77));
	LOGFONT f;
	gettextstyle(&f);                     // 获取当前字体设置
	f.lfHeight = 65;                      // 设置字体高度为 48
	_tcscpy(f.lfFaceName, "微软雅黑");
	f.lfQuality = ANTIALIASED_QUALITY;    // 设置输出效果为抗锯齿
	settextstyle(&f);                     // 设置字体样式
	RECT BegingameText = { Windows_x / 4 + 100, Windows_y / 2, Windows_x / 4 + 450, Windows_y / 2 + 110 };//"开始游戏"的位置
	drawtext("【开 始 游 戏】", &BegingameText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	bool flag = true;
	while (flag)
	{
		BeginBatchDraw();
		m = GetMouseMsg();//获取鼠标消息
		switch (m.uMsg)
		{
		case WM_LBUTTONDOWN://鼠标左键被按下
			EndBatchDraw();
			if (m.x >= Windows_x / 4 + 100 && m.x <= Windows_x / 4 + 450 && m.y >= Windows_y / 2 && m.y <= Windows_y / 2 + 110)//点击开始游戏
			{
				flag = false;
				start();
			}
		case WM_MOUSEMOVE://监测鼠标移动
			EndBatchDraw();
			if (m.x >= Windows_x / 4 + 100 && m.x <= Windows_x / 4 + 450 && m.y >= Windows_y / 2 && m.y <= Windows_y / 2 + 110)
			{
				settextcolor(RGB(69, 137, 148));
				drawtext("【开 始 游 戏】", &BegingameText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
			}
			else
			{
				settextcolor(RGB(77, 77, 77));
				drawtext("【开 始 游 戏】", &BegingameText, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
			}
		}
	}
}
int main()
{
	init();
	return 0;
}

 

编译好的下载地址:

云盘下载

 

提取密码:x6nb

 

代码也开源在github,地址:

https://github.com/riba2534/MazeGame

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注