拯救007(基于c++,easyx)

1 引言

在电影《生死关头》中,James Bond作为世界上最著名的特工,遭遇了一场惊心动魄的逃脱戏码。在这个被湖中心的小岛和湖中的鳄鱼包围的困境中,他需要快速做出决策,以成功逃脱险恶的环境。

在这个场景中,湖的大小为100米乘以100米,湖的中心坐标为(0,0),而东北角的坐标则是(50,50)。湖中的小岛位于湖中心,其圆心为(0,0),岛的直径为15米。此外,湖中还分布着一些凶猛的鳄鱼,它们的分布位置和James Bond可以跳跃的最大距离已知。

在这样险恶的环境下,James Bond需要依靠我们的路径规划系统来寻找最短的逃脱路径。这个路径规划系统是专门为他提供帮助的,帮助他在小岛和湖中的鳄鱼包围中找到最短的路径,以尽可能快地脱离险境。

这个路径规划系统是通过广度优先搜索算法实现的。广度优先搜索算法是一种经典的图搜索算法,它能够按照距离的远近逐一搜索每个可能的路径,并从中选择最短的一条。这种算法可以确保所推荐的路径是最短的、可行的,能够提供最短的逃脱路径给James Bond。

2 需求分析

根据用户需求分析,设计一个名为“拯救007游戏系统”的应用,以满足以下功能要求:

1. 输入数据读取:从文件中读取输入数据,包括鳄鱼数量、最大跳跃距离以及各个鳄鱼的位置坐标。

2. 路径规划:采用广度优先搜索算法,计算从中心小岛到湖岸的最短路径,并将结果输出至文件。若无法找到007逃离的路径,则在文件中写入“007不存在可逃离的路径”。

3. 路径坐标按跳跃顺序输出:按照007跳跃的顺序排列,输出路径上鳄鱼的坐标,每行输出一个坐标。

4. 数据处理:支持对输入数据的处理,数据之间相互独立,可分别计算路径的长度。

5. 输出排序:按照长度排序,输出所有可行的路径。

6. 图形化展示:提供图形化界面,以图的方式展示游戏的最短路径。

7. 用户界面友好:提供简单易用的操作界面,便于用户进行输入和输出操作。

3 系统设计

3.1系统功能设计

本系统的功能模块图如图1所示。

图1 系统功能模块图

3.2 开发与运行环境

硬件:Windows11

软件:Visual Studio 2022

4.测试

4.1文件功能测试

(1)输入数据界面

图2 输入数据界面

图3 输入数据界面(无路径输出)

图4 输入数据界面(一步到位)

(2)运行结果界面

图5 运行结果界面

图6 运行结果界面(无路径输出)

图7 运行结果界面(一步到位)

4.2显示功能测试

(1)结果路径图界面:

图8 路径图界面

图9 路径图界面(无路径输出)

图10 路径图界面(一步到位)

5.另外提醒

      input.txt和output.txt的位置:

图11 文件存放结构图

6.源代码

#include <iostream>  
#include <fstream>  
#include <vector>  
#include <queue>
#include <cstring>  
#include <graphics.h>  
#include <algorithm>

using namespace std;

typedef struct Node
{
    double x, y;

} Node;

int N, M; // N是鳄鱼数量,M是最大步长  
Node node[1000];
int vis[1000];//记录结点是否被访问过
vector<vector<int>> results; // 存储所有可能的路径  
vector<int> path; // 当前路径,存储从起点到当前节点经过的所有鳄鱼  
Node circle_boundary; // 圆心坐标
Node box_boundary; // 方框边界的终点坐标


// 从岛跳到第 i 号鳄鱼是否可行  
int first(int i, int M)
{
    double p1 = pow(node[i].x, 2);
    double p2 = pow(node[i].y, 2);
    double m = p1 + p2;
    double q = sqrt(m);
    if (q - 7.5 <= M && m >= 56.25)  //起始点  
        return 1;
    return 0;
}

// 求第 i 号和第 j 号鳄鱼之间的距离,并判断  
int jump(int i, int j)
{
    double p1 = (node[i].x - node[j].x) * (node[i].x - node[j].x);
    double p2 = (node[i].y - node[j].y) * (node[i].y - node[j].y);

    // 圆的公式
    if (p1 + p2 <= pow(M, 2))
        return 1;
    return 0;
}


// 求当前位置能否直接跳到鳄鱼池边缘
int key(int k)
{
    if (abs(node[k].x) + M >= 50 || abs(node[k].y) + M >= 50) {
        return 1;
    }
    return 0;
}

void draw_alligators()
{
    // 绘制鳄鱼  
    setfillcolor(YELLOW);
    for (int i = 0; i < N; i++)
    {
        solidcircle(node[i].x, node[i].y, 1);
    }
}

// 绘制路径
void draw_path(const vector<int>& path)
{
    // 保存圆点坐标
    circle_boundary.x = 0;
    circle_boundary.y = 0;

    // 保存方框边界的终点坐标
    box_boundary.x = 0;
    box_boundary.y = 0;
    if (path.size() < 1) return;
 
    setlinecolor(BLACK);

    //画圆心到第一个点的图
    moveto(node[path[0]].x, node[path[0]].y);
    lineto(circle_boundary.x, circle_boundary.y);

    //更新box
    box_boundary.x = node[path[0]].x;
    box_boundary.y = node[path[0]].y;

    for (int i = 1; i < path.size(); i++)
    {
        moveto(node[path[i - 1]].x, node[path[i - 1]].y);
        lineto(node[path[i]].x, node[path[i]].y);
        //更新box
        box_boundary.x = node[path[i]].x;
        box_boundary.y = node[path[i]].y;
    }

    //判断box的位置
    if (abs(box_boundary.x) >= abs(box_boundary.y))
    {
        if (box_boundary.x <= 0)
        {
            moveto(box_boundary.x, box_boundary.y);
            lineto(-50, box_boundary.y);
        }
        else
        {
            moveto(box_boundary.x, box_boundary.y);
            lineto(50, box_boundary.y);
        }

    }
    else {
        if (box_boundary.y <= 0)
        {
            moveto(box_boundary.x, box_boundary.y);
            lineto(box_boundary.x, -50);
        }
        else
        {
            moveto(box_boundary.x, box_boundary.y);
            lineto(box_boundary.x, 50);
        }
    }

}


// 计算路径长度  
double get_path_length(const vector<int>& path)
{
    double length = 0.0;
    double p = 0.0;//存放最后一个点到边的距离
    double t = 0.0;//存放圆边缘到第一个点的距离

    //判断t,p
    //假如只有一个点
    if (path.size() == 1)
    {
        t = sqrt((pow(node[path[0]].x, 2) + pow(node[path[0]].y, 2))) - 7.5;
        box_boundary.x = node[path[0]].x;
        box_boundary.y = node[path[0]].y;
    }
    else {
        for (int i = 1; i < path.size(); i++)
        {
            int j = path[i - 1];
            int k = path[i];
            if (i == 1)//圆的边缘到第一个点的距离
            {
                t = sqrt((pow(node[path[i-1]].x, 2) + pow(node[path[i-1]].y, 2))) - 7.5;
                box_boundary.x = node[j].x;
                box_boundary.y = node[j].y;
                length += sqrt(pow(node[k].x - node[j].x, 2) + pow(node[k].y - node[j].y, 2));
            }
            else {

                length += sqrt(pow(node[k].x - node[j].x, 2) + pow(node[k].y - node[j].y, 2));
                box_boundary.x = node[k].x;
                box_boundary.y = node[k].y;
            }
        }
    }
    //判断box的位置
    if (abs(box_boundary.x) >= abs(box_boundary.y))
    {
        p = abs(50 - abs(box_boundary.x));
    }
    else {
        p = abs(50 - abs(box_boundary.y));
    }

    return length + p + t;
}


// 求所有路径中的最短路径  
vector<int> get_shortest_path(const vector<vector<int>>& results)
{
    double shortest_length = 100000.0;  // 设一个较大的值作为初始值  
    vector<int> shortest_path;
    for (const auto& path : results)
    {
        double length = get_path_length(path);
        if (length <= shortest_length)
        {
            shortest_length = length;
            shortest_path = path;
        }
    }
    return shortest_path;
}

void bfs(int s)
{
    queue<int> q;
    vector<int> path(N, -1); // 用于记录路径
    q.push(s);
    vis[s] = 1;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        if (sqrt(pow(node[u].x, 2) + pow(node[u].y, 2)) <= 7.5)
        {
            continue; // 当前节点在圆心岛的范围内,直接跳过
        }
        if (key(u))
        {
            vector<int> tmp;
            int p = u;
            while (p != s)
            {
                tmp.push_back(p);
                p = path[p];
            }
            tmp.push_back(s); // 加入起点
            reverse(tmp.begin(), tmp.end()); // 反转路径
            results.push_back(tmp); // 将当前路径加入结果集合
            continue; // 找到一条路径后,继续搜索
        }
        for (int i = 0; i < N; i++)
        {
            if (!vis[i] && jump(u, i))
            {
                q.push(i);
                vis[i] = 1;
                path[i] = u;
            }
        }
    }
}


int main()
{
    initgraph(1000, 1000, EW_SHOWCONSOLE);// 设置窗口坐标系的原点和比例系数  
    setorigin(500, 500);
    setaspectratio(5, 5); // 200个像素对应1米  

    // 绘制鳄鱼池和池心岛  
    setfillcolor(RGB(142, 150, 255));
    fillrectangle(-50, -50, 50, 50); // 鳄鱼池边长为100米  
    setfillcolor(GREEN);
    solidcircle(0, 0, 7.5); // 池心岛直径为15米  

    // 保存圆点坐标
    circle_boundary.x = 0;
    circle_boundary.y = 0;

    ifstream input_file("input.txt");
    ofstream output_file("output.txt");

    // 检查输入文件是否打开成功  
    if (!input_file.is_open())
    {
        cout << "文件打开失败!" << endl;
        return 1;
    }
    // 检查输出文件是否打开成功  
    if (!output_file.is_open())
    {
        cout << "文件打开失败!" << endl;
        return 1;
    }

    // 读取鳄鱼数量和最大步长  
    input_file >> N >> M;

    // 读取每只鳄鱼的位置坐标  
    for (int i = 0; i < N; i++)
    {
        input_file >> node[i].x >> node[i].y;
    }

    draw_alligators();  //画鳄鱼

    //若可以一步跳出边界这里单独判断
    if (M < 42.5) {  
        // 枚举起点  
        for (int i = 0; i < N; i++)
        {
            if (first(i, M))
            {
                memset(vis, 0, sizeof(vis));
                bfs(i);
            }
        }

        // 输出所有的路径(保存在文件中)
        output_file << "所有可能的路径:" << endl;
        for (int i = 0; i < results.size(); i++)
        {

            output_file << "第" << i + 1 << "组:" << endl;
            output_file << "需要" << results[i].size() + 1 << "步:" << endl;
            for (int j = 0; j < results[i].size(); j++)
            {
                output_file << "(" << node[results[i][j]].x << "," << node[results[i][j]].y << ") " << endl; // 输出路径的坐标
            }
            output_file << "路径长度:" << get_path_length(results[i]) << endl;
            output_file << endl;
        }
        output_file << endl;
        //若没有路径
        if (results.size() == 0)
            output_file << "007不存在可以逃出去的路径" << endl;

        // 输出最短路径(图的形式)
        if (!results.empty())
        {
            vector<int> shortest_path = get_shortest_path(results);
            output_file << "最短路径: " << endl;
            output_file << "需要" << shortest_path.size() + 1 << "步:" << endl;
            for (int i = 0; i < shortest_path.size(); i++)
            {
                output_file << "(" << node[shortest_path[i]].x << "," << node[shortest_path[i]].y << ")" << endl; // 输出最短路径的坐标
            }
            double shortest_length = 1000000; //设置一个大点的值
            shortest_length = get_path_length(shortest_path);
            output_file << endl << "最短路径长度: " << shortest_length << endl;
            draw_path(shortest_path);
        }

        input_file.close();
        output_file.close();
    }
    else {
        output_file << "所有可能的路径:" << endl;
        output_file << "由于步长M:" << M << "大于等于可以从湖心岛一步跳跃到边界的距离:" << "42.5" << "这里路径/最短路径任意一条可行" << endl;
        output_file << "需要" <<  1 << "步" << endl;
        output_file << endl << "最短路径长度: " << 42.5 << endl;

        setlinecolor(RED);
        moveto(box_boundary.x, box_boundary.y);
        lineto(box_boundary.x, -50);

        input_file.close();
        output_file.close();
    }
    system("pause");
    return 0;
}


7.结语

        这个项目是楼主很早之前写的,之前没注意到一步跳出的情况,这次修改了想着就发出来,大家一起进步了。我看到csdn相关的这个项目还挺多的,我也贡献我的一份绵薄之力了。希望看到这篇文章的小伙伴,如果对你有帮助,给一个小小的赞吧!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值