迷宫游戏

数据结构课程设计

想不出来写啥,还是用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

 

点赞
  1. L说道:

    很好

发表评论

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