A*寻路之旅:用SDL图形化演示

news2024/9/22 15:33:37

前言

欢迎来到小K的数据结构专栏的第十小节,本节将为大家带来A*寻路算法的图形化详解,学了之后寻路不再迷路(✨当然也为大家准备了完整的源码,好像在文章顶部欸~ )~希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾

效果如下:

A*寻路算法图形化演示


文章目录

      • 前言
      • 一、简单介绍
      • 二、主要思想
      • 三、附上源码
      • 四、总结


一、简单介绍

由来
在 A * 算法之前有一种基于启发式探索的方法来提高Dijkstra算法的速度,这个算法叫做A1。后来的改进算法被称为A * 。 * 这个符号是从统计文献中借鉴来的,用来表示相对一个旧有标准的最优估计

启发式探索是利用问题拥有的启发信息来引导搜索,达到减少探索范围,降低问题复杂度的目的

✨A*寻路算法就是启发式探索的一个典型实践,在寻路的过程中,给每个节点绑定了一个估计值(即启发式),在对节点的遍历过程中是采取估计值优先原则,估计值更优的节点会被优先遍历。所以估计函数的定义十分重要,显著影响算法效率。
在这里插入图片描述

那么在上图中我们应该怎么评估出最短路径呐既然要评估,那肯定要有评估规则了,首先明确三个概念,H值,目前点到终点的曼哈顿距离(曼哈顿距离,就是两个位置长度差值和高度差值的和),G值,目前点到起点的消耗代价值,如果只是寻找路径,可以将该值也看成是这两点的曼哈顿距离,F值,H值和G值的和。所以A*寻路算法的评估由公示F=G+H来评估

✨我们先来尝试一下,假设每个格子的直线代价为10,斜线代价为14,则我们评估的起点周围的八个点的代价如下图所示:

在这里插入图片描述

怎么算的呐?我们以(2,2)为例,它到终点的曼哈顿距离我用黄色的矩形框起来了,横4纵4,然后乘上直线代价10,所以H为80,G一眼就可以看出,只有一个斜线代价,所以F为94

二、主要思想

在简单了解了A * 寻路算法了,我们不由得想,该怎么来寻?该用什么数据结构来描述?

  • ✨该怎么来寻?这个问题其实上边已经给出答案了,用F=G+H来评估,在这之前我们需要一个点类型,H比较好求,我们计算出当前点和终点之间的横纵坐标差,然后相加,乘上直线代价就好了,G值呐?我们通过下面的八叉树类型来解决~

    typedef struct Mypos 
    {
    	int row, col;
    	int f, g, h;
    }Mypos;
    //计算H值
    int getH(Mypos* pos, Mypos* endPos)
    {
        int x = ((pos->row > endPos->row) ? (pos->row - endPos->row) : (endPos->row - pos->row));
        int y = ((pos->col > endPos->col) ? (pos->col - endPos->col) : (endPos->col - pos->col));
        return (x + y) * ZXDJ;
    }
    
  • ✨该用什么数据结构?我首先想到的是八叉树,因为每个点周围都有八个点需要试探,下面是一个八叉树类型

    typedef struct MythreeNode 
    {
    	Mypos pos;                                     //点
    	struct MythreeNode* child[CHILD_NUM];          //孩子节点
    	struct MythreeNode* partent;                   //父节点
    	int child_Num;                                  //当前孩子数量
    }MythreeNode;
    
  • ✨具体的寻路过程如下

在这里插入图片描述

第一步,先遍历周围的八个节点,把他们的斜线代价计算出来

第二步,判断能不能走,能走就计算出F,存入树和数组中,不能走直接把该孩子删掉

第三步,从buffer数组中找到最小的F值,走,然后用辅助地图标记走过

第四步,我们要判断找没找到终点,退出循环有两种情况,要么是找到终点了,要么是buffer数组为空了

上述步骤中有一个小问题,就是如果遇到死胡同问题怎么办?比如下图:

在这里插入图片描述

第一步直接走到黄色的圈圈了,发现没路了,怎么办?我们思路回退一下,如果我们走完buffer数组中最小的,再把最小的删了不就可以了,这样下一步就会回到起点,这个问题就解决了

三、附上源码

✨A.h

#ifndef _A_H_
#define _A_H_
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<string.h>
#include<assert.h>
#include<SDL.h>
//行列
#define ROWS 10
#define COLS 10
//代价
#define ZXDJ 10
#define XXDJ 14
//最大孩子数量
#define CHILD_NUM 8
//临时数组容量
#define NUMS_SIZE 1024
//路
enum type { road, wall };
//方向
enum Mydirect { p_up, p_down, p_left, p_right, p_upleft, p_upright, p_downleft, p_downright };
//点类型
typedef struct Mypos 
{
	int row, col;
	int f, g, h;
}Mypos;
//八叉树类型
typedef struct MythreeNode 
{
	Mypos pos;                                     //点
	struct MythreeNode* child[CHILD_NUM];          //孩子节点
	struct MythreeNode* partent;                   //父节点
	int child_Num;                                  //当前孩子数量
}MythreeNode;
//获得H值
int getH(Mypos* pos, Mypos* endPos);
//创建八叉树节点
MythreeNode* create_ThreeNode(Mypos* pos);
//判断能不能走
bool Can_Walk(Mypos* pos, bool map[ROWS][COLS], bool Pathmap[ROWS][COLS]);
//加载图片
SDL_Texture* load_BMP(SDL_Renderer* Ren, const char* fillname);
//绘图
void draw_Map(bool map[ROWS][COLS], Mypos* pos, SDL_Renderer* Ren, SDL_Texture** tex);

#endif // _A_H_


✨A.c

#include "A.h"

int getH(Mypos* pos, Mypos* endPos)
{
    int x = ((pos->row > endPos->row) ? (pos->row - endPos->row) : (endPos->row - pos->row));
    int y = ((pos->col > endPos->col) ? (pos->col - endPos->col) : (endPos->col - pos->col));
    return (x + y) * ZXDJ;
}

MythreeNode* create_ThreeNode(Mypos* pos)
{
    MythreeNode* newNode = (MythreeNode*)malloc(sizeof(MythreeNode));
    if (NULL == newNode) return newNode;
    memset(newNode, 0, sizeof(MythreeNode));
    newNode->pos.row = pos->row;
    newNode->pos.col = pos->col;
    newNode->pos.g = pos->g;
    return newNode;
}

bool Can_Walk(Mypos* pos, bool map[ROWS][COLS], bool Pathmap[ROWS][COLS])
{
    //越界
    if (pos->row < 0 || pos->row >= ROWS || pos->col < 0 || pos->col >= ROWS) return false;
    //是墙
    if (map[pos->row][pos->col]) return false;
    //走过
    if (Pathmap[pos->row][pos->col]) return false;
    return true;
}

SDL_Texture* load_BMP(SDL_Renderer* Ren, const char* fillname)
{
    SDL_Surface* sfc = SDL_LoadBMP(fillname);
    if (!sfc)
    {
        SDL_Log("sfc filed %s", SDL_GetError());
        return NULL;
    }
    SDL_Texture* tex = SDL_CreateTextureFromSurface(Ren, sfc);
    if (!tex)
    {
        SDL_Log("tex failed %s", SDL_GetError());
        SDL_FreeSurface(sfc);
        return NULL;
    }
    SDL_FreeSurface(sfc);
    return tex;
}

void draw_Map(bool map[ROWS][COLS], Mypos* pos,SDL_Renderer* Ren,SDL_Texture** tex)
{
    for (int i = 0; i < ROWS; i++)
    {
        for (int j = 0; j < COLS; j++) 
        {
            SDL_Rect rect = { j * 64,i * 64,64,64 };

            if (!map[i][j])
            {
                SDL_RenderCopy(Ren, tex[2], NULL, &rect);
            }
            else if (map[i][j])
            {
                SDL_RenderCopy(Ren, tex[3], NULL, &rect);
            }
            if (pos->row == i && pos->col == j) 
            {
                SDL_RenderCopy(Ren, tex[0], NULL, &rect);
            }
           if (7 == i && 6 == j)
           {
               SDL_RenderCopy(Ren, tex[1], NULL, &rect);
           }

        }
    }
}

✨main.c

在这里插入图片描述

四、总结

本节讲解的数据结构——A*寻路算法,他不仅是一种算法思想,它还是路径规划,游戏中普通人物挂机状态的寻路的灵魂,所以它是值得我们花费时间去掌握的~下节见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ctfshow 每周大挑战 RCE极限挑战4、5

看过官方wp之后复现的&#xff0c;用的payload是自己后来写的&#xff0c;可能不如官方的看着清晰 有点强迫症似的在抠细节&#xff08;x 目录 挑战4最初的思路通过HackBar拿flag的写法写法一写法二 挑战5burp中的payload 大佬们也太极限啦 挑战4 最初的思路 第4题的长度限制…

UM2082F08 125k三通道低频无线唤醒ASK接收功能的SOC芯片 汽车PKE钥匙

1产品描述 UM2082F08是基于单周期8051内核的超低功耗8位、具有三通道低频无线唤醒ASK接收功能的SOC芯片。芯片可检测30KHz~300KHz范围的LF (低频)载波频率数据并触发唤醒信号&#xff0c;同时可以调节接收灵敏度&#xff0c;确保在各种应用环境下实现可靠唤醒&#xff0c;其拥…

母婴健康老人护理医护上门陪诊产后恢复预约上门小程序源码

母婴健康老人护理医护上门陪诊产后恢复预约上门小程序 在线预约 上门打针 产后恢复 会员卡 余额充值 优惠券 分销商 unippthinkphp <template> <view class"container" :style"{background:pagebase.base.bc}"> <Pengp…

Django+Vue实现文件上传下载功能

目录 前言 上传功能 后端代码 前端代码 下载功能 后端代码 前端代码 前言 首先我要实现的页面效果是这样的 当点击上传文件按钮&#xff0c;弹出上传文件的弹出框&#xff0c;可以上传多个文件&#xff0c;点击确定后才正式开始上传 点击右侧下载按钮&#xff0c;可以直…

springboot中将logback切换为log4j2

前言 springboot默认使用logback作为日志记录框架&#xff0c;常见的日志记录框架有log4j、logback、log4j2。这篇文章我们来学习怎样将logbak替换为log4j2。 一、为什么使用log4j2&#xff1f; 我们在项目中经常使用一个叫SLF4J的依赖&#xff0c;它是做什么的呢&#xff1f; …

Java 实现在顺序表末尾插入一个元素

一、思路 1.因为我们是用数组实现的顺序表&#xff0c;因此首先要保证数组有足够的空间来进行插入元素. 2.如果数组满了就需要将数组扩容&#xff0c;没满就开始插入. 3.当前数组中的元素个数就是每一次要插入的末尾位置的下标. 4.定义一个 usedSize 来表示当前的元素个数. 5.插…

Pandas+ChatGPT强强结合诞生PandasAI,数据分析师行业要变天了?

大家好&#xff0c;我是千与千寻&#xff0c;可以叫我千寻&#xff0c;我自己主要的编程语言是Python和Java。 说到Python编程语言&#xff0c;使用Python语言主要使用的是数据科学领域的从业者。 Python编程语言之所以在数据科学领域十分火热&#xff0c;源于Python语言的三…

9.Ansible Conditions介绍

Ansible条件语句 1)上面的例子在不同的机器上安装nginx&#xff0c;不同的操作系统风格使用不同的软件包管理器&#xff61;debian使用APT, Red Hat使用Yum, 但这是两个独立的Playbook,您必须为各自的服务器使用正确的剧本&#xff61; 可以使用条件语句&#xff0c;将这两个P…

Mongodb在Linux下载安装及部署

前言 一、下载安装包 Mongodb官网&#xff1a;Download MongoDB Community Server | MongoDB 二、安装及配置 博主下载的安装包是&#xff1a;mongodb-linux-x86_64-rhel70-6.0.6.tgz 新建目录 # 进入 usr 文件夹 cd /usr# 新建 mongodb 文件夹 mkdir mongodb# 进入 mongodb …

如何自学成为黑客

学习路线 不BB&#xff0c;直接上干货。 学完下面的内容&#xff0c;绝对可以进入黑客圈。 文末有福利噢&#xff01; 第一步&#xff1a;计算机基础 了解计算机基本常识&#xff0c;常用软件使用。需要学会基本使用的软件或技术有&#xff1a;Word、VMware、VPN、Visual St…

快速实现工程化部署,亚马逊云科技为AIGC产品化提供可靠基础

本文将以Stable Diffusion Quick Kit在亚马逊云科技Amazon SageMaker上的部署来介绍Stable Diffusion模型基础知识&#xff0c;HuggingFace Diffusers接口&#xff0c;以及如何使用Quick Kit在SageMaker Endpoint上快速部署推理服务。 Stable Diffusion模型 2022年由Stability…

自己拍摄的视频剪辑时如何消音?

由于录制环境的影响&#xff0c;有时制作出来的视频原始声音可能无法达到令人满意的效果&#xff0c;可能有噪声存在。这个时候&#xff0c;就应该先消除视频原始声音&#xff0c;然后后期再去给视频添加配音。有哪些适合给自己拍摄的视频调为静音的方法&#xff0c;来看看有哪…

详解 Windows 10 安装 CUDA 和 CUDNN

目录 查看本机 Window 10 系统已经安装 NIVIDIA 的驱动版本说在前面查看驱动版本 CUDA下载直接下载最新的 CUDA下载历史版本的 CUDA 安装测试 CUDNN下载 下载最新版本的 cuDNN下载历史版本的 cuDNN, 如: cuDNN 12.0安装 关于添加系统环境变量的问题 ⭐️⭐️说在前面!!! 建议 先…

平均年薪20W,自动化测试工程师这么吃香?

自动化测试工程师&#xff0c;平均年薪20w绝对不是空穴来凤&#xff0c;甚至我还说少了&#xff0c;加上年终奖和奖金等等年薪可能还不止20w这个水平&#xff0c;让我们看看下方截图&#xff0c;【来自于职友集】 本篇文章将由以下4个部分来展开&#xff1a; 1. 什么是自动化测…

PaddleClas初体验

PaddleClas初体验 该包是由百度PaddlePaddle组织下开源的项目&#xff0c;主要用于图像分类&#xff0c;图像搜索等相关任务。 项目地址&#xff1a; https://github.com/PaddlePaddle/PaddleClashttps://pypi.org/project/paddleclas 主要构件&#xff1a; PP-ShiTu&…

企业的数据信息值钱吗?如何提升数据信息的价值?

越来越多的企业也将数据视为转型发展、重塑竞争优势和提升组织治理能力的重要战略资产&#xff0c;并对这一重要资产进行系统性、体系化的管理&#xff0c;以便充分挖掘数据的战略、战术价值。鉴于此&#xff0c;对数据资产进行体全面盘点、构建企业级的数据资产目录成为了数据…

aigc分享

AIGC技术分享 AIGC概述 AIGC的概念、应用场景和发展历程 机器学习基础 机器学习的基本概念、分类和常用算法&#xff0c;如线性回归、决策树、支持向量机、神经网络等。 深度学习基础 深度学习的基本概念、分类和常用算法&#xff0c;如卷积神经网络、循环神经网络、自编…

面试专题:java多线程(2)-- 线程池

1.为什么要用线程池&#xff1f; 线程池提供了一种限制和管理资源&#xff08;包括执行一个任务&#xff09;。 每个线程池还维护一些基本统计信息&#xff0c;例如已完成任务的数量。 这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处&#xff1a; 降低资源消…

【嵌入式烧录/刷写文件】-1.6-剪切/保留Motorola S-record(S19/SREC/mot/SX)文件中指定地址范围内的数据

案例背景&#xff1a; 有如下一段S19文件&#xff0c;保留地址范围0x9140-0x91BF内的数据&#xff0c;删除地址范围0x9140-0x91BF外的数据。 S0110000486578766965772056312E30352EA6 S123910058595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576775B S12391207…