一個簡單的可視化的A星自動尋路

一個簡單的應用場景,流程圖連線

源碼:

    addExample("A星路徑查找", function () {return {template: `<div><div ref="main"></div></div>`,data() { return {}; },computed: {},methods: {},mounted() {var container = this.$refs.main;var render = new CanvasShapeRender(container, {width: 700,height: 700,background: '#efefef'})var group = render.addShape({ type: 'group', x: 50, y: 50 })const start = Vector.create(2, 2)const end = Vector.create(8, 6)let dragObjconst tileMap = group.addShape({type: 'tileMap',visibleGrid: true,onCreateTileData(col, row) {if (row === start.y && col === start.x) {return {type: 'rect',color: '#ff0000',value: 1,canMove: true}}else if (row === end.y && col === end.x) {return {type: 'rect',color: '#00ff00',value: 2,canMove: true}} else {return {type: 'rect',color: '#ddd',value: 0}}},onAfterDrawMapCell(ctx, col, row, x, y, data) {if (!gui.visibleDist || data.value !== 4) {return}ctx.beginPath()ctx.fillStyle = '#000'ctx.font = '12px sans-serif'ctx.textAlign = 'start'ctx.textBaseline = 'base'const getDist = distOps[gui.dist]const startDist = Number(data.startDist.toFixed(2)) // Number(getDist({ col: start.x, row: start.y }, { col, row }).toFixed(2))const endDist = Number(data.endDist.toFixed(2))// Number(getDist({ col, row }, { col: end.x, row: end.y }).toFixed(2))const dist = Number(data.dist.toFixed(2))//Number((endDist + startDist).toFixed(2))ctx.fillText('' + startDist, x, y + 10)ctx.fillText('' + endDist, x, y + this.cellSize[1] - 5)ctx.beginPath()ctx.font = '14px sans-serif'ctx.textAlign = 'center'ctx.textBaseline = 'middle'//  CanvasRenderingContext2D.prototype.textBaselinectx.fillText('' + dist, x + this.cellSize[0] / 2, y + this.cellSize[1] / 2)},cellSize: [50, 50],mapSize: [10, 10],mousedown(e) {const downPoint = e.downPointconst [x, y] = group.transformLocalCoord(downPoint.x, downPoint.y)const [col, row] = this.getMapCoordinate(x, y)const data = this.getCellData(col, row)if (data && data.canMove) {dragObj = {col,row,data}} else if (data && (data.value == 0 || data.value == 3)) {dragObj = {col,row,data: {value: data.value}}}},drag(e) {if (dragObj) {const point = e.pointconst [x, y] = group.transformLocalCoord(point.x, point.y)let [col, row] = this.getMapCoordinate(x, y)const data = this.getCellData(col, row)if (dragObj.data.value === 0 && !data.canMove) {// 變成障礙data.value = 3data.color = '#666'this.setCellData(col, row, data)render.requestDraw()} else if (dragObj.data.value === 3 && !data.canMove) {// 移除障礙data.value = 0data.color = '#ddd'this.setCellData(col, row, data)render.requestDraw()}else if (dragObj.data.canMove && data && data !== dragObj.data) {this.setCellData(dragObj.col, dragObj.row, data)this.setCellData(col, row, dragObj.data)if (dragObj.data.value === 1) {start.x = colstart.y = row}if (dragObj.data.value === 2) {end.x = colend.y = row}dragObj.col = coldragObj.row = rowrender.requestDraw()}}},mouseup() {dragObj = null}})render.requestDraw()const map = tileMap.map // 0 空 1 起點 2終點 3障礙const clear = () => {tileMap.visitMap(tileMap.map, (r, c, data) => {if (data.value === 4) {data.value = 0data.color = '#ddd'}})render.requestDraw()}const renderPaths = (paths, color, renderPath, duration = 1000) => {if (paths.length <= 0) {return}let start = performance.now()let len = paths.length - 1const animate = (time) => {const d = performance.now() - startconst p = Math.min(d / duration, 1)const index = Math.floor(p * len);const data = paths[index]if (renderPath || !data.isPath) {tileMap.setCellData(data.col, data.row, {...data,type: 'rect',value: 4,color: color})}render.requestDraw()if (p < 1) {requestAnimationFrame(animate)}}requestAnimationFrame(animate)}// 計算兩個點的距離//Manhattan Distanceconst getManhattanDist = (a, b) => {// 曼哈頓距離 return Math.abs(a.col - b.col) + Math.abs(a.row - b.row)}// 歐幾里得距離( Euclidean distance)也稱歐氏距離const getEuclideanDist = (a, b) => {const x = a.col - b.colconst y = a.row - b.rowreturn Math.sqrt(x * x + y * y)}//,切比雪夫距離(Chebyshev distance)const getChebyshevDist = (a, b) => {const x = a.col - b.colconst y = a.row - b.rowreturn Math.max(Math.abs(x), Math.abs(y))}const distOps = {getManhattanDist,getEuclideanDist,getChebyshevDist}// 返回最短路徑const findPath = function* (start, end, _map) {// 創建圖頂點信息const map = _map.map((rd, row) => {return rd.map((cd, col) => {return {...cd,row,col,value: cd.value,isPath: false,visited: false,// 是否訪問過// 無有可走的路closed: false, // 已經查找過parent: null,startDist: 0, // 起點距離當前格子endDist: 0, // 當前距離終點dist: 0, // 總距離weight: 0, // 權重order: 0,}})})const rows = map.length, cols = map[0].lengthconst getNode = (col, row) => {if (col < 0 || col >= cols || row < 0 || row >= rows) {return null}return map[row][col]}// 找相鄰的const getAdjacent = (node) => {const c = node.colconst r = node.rowconst left = getNode(c - 1, r) // leftconst top = getNode(c, r - 1) // topconst right = getNode(c + 1, r) // rightconst bottom = getNode(c, r + 1) // bottomreturn [left, top, right, bottom].filter(Boolean)}const getCost=()=>{return 0.1}const findNearestDistance = (node) => {const adjacent = getAdjacent(node)let min = Infinity, minNode// let resultNode;adj:for (let i = 0; i < adjacent.length; i++) {const adj = adjacent[i]// 如果已關閉或是障礙,不處理if (adj.closed || adj.value === 3) {continue;}let startDist=node.startDist+getCost(adj,node) //getDist(adj,node)// 如果還未訪問if (!adj.visited) {// g(n)表示從初始結點到任意結點n的代價,// h(n)表示從結點n到目標點的啟發式評估代價(heuristic estimated cost)。// f=g(n)+h(n)// getDist(startNode, adj)adj.startDist = startDistadj.endDist = getDist(adj, endNode)adj.dist = adj.startDist + adj.endDist //getDist(adj, startNode)adj.parent = nodeadj.visited = trueopenList.push(adj)// 如果是空閑if (adj.value === 0) {visitedPaths.push(adj)}}else{if(startDist<node.startDist){adj.parent = nodeadj.startDist = startDistadj.dist = adj.startDist + adj.endDist //getDist(adj, startNode)}}if (adj.value === 2) {return adj}}openList.sort((a, b) => a.dist - b.dist)// openList.sort((a, b) => a.dist === b.dist ? a.dist - b.dist : a.order - b.order)}const getDist = distOps[gui.dist]// 查找鄰居四個方位,上下左右let current = nulllet startNode = getNode(start[0], start[1])let endNode = getNode(end[0], end[1])let paths = []let visitedPaths = []let openList = []openList.push(startNode)let resultNode;path:while (openList.length) {yield { visitedPaths, paths };current = openList.shift()current.closed = true;if (current === endNode) {resultNode = currentbreak}resultNode = findNearestDistance(current)if (resultNode) {break}}current = resultNode ? resultNode.parent : nullwhile (current && current !== startNode) {current.isPath = true;paths.unshift(current)current = current.parent}return {paths: paths,visitedPaths}}const resultGenerator = (result) => {let current;do {current = result.next();} while (!current.done)return current.value}const stepGenerator = (generatorFn, callback) => {let result;let isStart = falseconst next = () => {if (!isStart) {isStart = true;result = generatorFn()}let current = result.next();callback(current.value)if (current.done) {isStart = false}}return {next,}}const distList = Object.keys(distOps)const step = stepGenerator(function* () {return yield* findPath([start.x, start.y], [end.x, end.y], map)}, ({ visitedPaths, paths }) => {renderPaths(visitedPaths, '#aaa', false)renderPaths(paths, '#ffff00', true)})const gui = addGuiScheme(this.$gui, {source: {dist: 'getEuclideanDist',visibleDist: false,start: () => {const { paths, visitedPaths } = resultGenerator(findPath([start.x, start.y], [end.x, end.y], map))renderPaths(visitedPaths, '#aaa', false)renderPaths(paths, '#ffff00', true)},step: () => {step.next()},clear() {clear()}},schemes: {dist: { type: 'list', params: distList }},onChange() {render.requestDraw()}})}}})

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210137.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210137.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210137.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python中的比較兩個字符串

更多資料獲取 &#x1f4da; 個人網站&#xff1a;ipengtao.com 在Python編程中&#xff0c;字符串比較是一項常見且關鍵的操作&#xff0c;涵蓋了諸多方法和技巧。比較兩個字符串是否相等、大小寫是否一致&#xff0c;或者在一個字符串中尋找特定的子字符串&#xff0c;都是日…

征途漫漫:汽車MCU的國產替代往事

01.西雁東飛&#xff0c;南下創業 1985年&#xff0c;山東大學物理系畢業的周生明加入878廠&#xff08;“北霸天”&#xff09;參與MOS電路研發&#xff0c;隨后幾年&#xff0c;大洋彼岸的英特爾相繼推出CPU 386\486、奔騰系列等產品。在摩爾定律的凸顯、進口和走私的劇烈沖…

基于Java房屋租賃管理系統

基于Java房屋租賃管理系統 功能需求 1、房源信息管理&#xff1a;系統需要能夠記錄和管理所有房源的詳細信息&#xff0c;包括房屋地址、房屋面積、租金、付款方式、房屋類型等。管理員應該可以添加、編輯和刪除房源信息。 2、租戶信息管理&#xff1a;系統需要能夠記錄和管…

class067 二維動態規劃【算法】

class067 二維動態規劃 code1 64. 最小路徑和 // 最小路徑和 // 給定一個包含非負整數的 m x n 網格 grid // 請找出一條從左上角到右下角的路徑&#xff0c;使得路徑上的數字總和為最小。 // 說明&#xff1a;每次只能向下或者向右移動一步。 // 測試鏈接 : https://leetcode…

<JavaEE> 經典設計模式之 -- 線程池

目錄 一、線程池的概念 二、Java 標準庫中的線程池類 2.1 ThreadPoolExecutor 類 2.1.1 corePoolSize 和 maximumPoolSize 2.1.2 keepAliveTime 和 unit 2.1.3 workQueue 2.1.4 threadFactory 2.1.5 handler 2.1.6 創建一個參數自定義的線程池 2.2 Executors 類 2.3…

go學習筆記(17)Blob and ArrayBuffer

最近在學習go websocket的時候&#xff0c;在學習實驗過程遇到一個比較奇怪問題。為什么我的數據返回是blob&#xff0c;而不是arrayBuffer&#xff1f;百思不得其解。 直到同事打包的時候微信小游戲遇到了一個報錯。FileReader不支持。 經過在社區查詢&#xff0c;官方答復是…

Qt之QCache和QContiguousCache

一.QCache QCache在構造的時候指定了緩存中允許的最大成本,也就是如下構造函數中的參數maxCost。默認情況下,QCaches maxCost() 是100。 QCache(int maxCost = 100) ~QCache() void clear() bool contains(const Key &key) const int count() const bool insert(const …

[原創] 電源芯片輸出端的紋波測試

網上有很多文章講解&#xff0c;電源芯片的紋波測試&#xff0c;原理圖各種講解&#xff0c;理論有余&#xff0c;實質性測試細節不夠細致&#xff0c;想寫一些測試步驟&#xff0c;作為分享和記錄。 1、設置示波器參數 1.1 校準示波器 1.2 探頭按鈕推到X1&#xff08;代表波…

[RoBERTa]論文實現:RoBERTa: A Robustly Optimized BERT Pretraining Approach

文章目錄 一、完整代碼二、論文解讀2.1 模型架構2.2 參數設置2.3 數據2.4 評估 三、對比四、整體總結 論文&#xff1a;RoBERTa&#xff1a;A Robustly Optimized BERT Pretraining Approach 作者&#xff1a;Yinhan Liu, Myle Ott, Naman Goyal, Jingfei Du, Mandar Joshi, Da…

【Qt5】Q_UNUSED()

2023年12月9日&#xff0c;周六晚上 Q_UNUSED()是一個用于告訴編譯器不使用&#xff08;或者未使用&#xff09;特定變量的宏。 有時候&#xff0c;在函數簽名中聲明了某些參數&#xff0c;但是在函數體內并沒有使用它們。這可能是因為在某些情況下&#xff0c;函數可能需要接…

P10 Linux進程編程 fork創建子進程

目錄 前言 01 fork()創建子進程 示例 1使用 fork()創建子進程。 02 fork創建新進程時發生了什么事&#xff1f; 2.1 父、子進程中對應的文件描述符指向了相同的文件表 前言 &#x1f3ac; 個人主頁&#xff1a;ChenPi &#x1f43b;推薦專欄1: 《Linux C應用編程&#xf…

異步回調模式

異步回調 所謂異步回調&#xff0c;本質上就是多線程中線程的通信&#xff0c;如今很多業務系統中&#xff0c;某個業務或者功能調用多個外部接口&#xff0c;通常這種調用就是異步的調用。如何得到這些異步調用的結果自然也就很重要了。 Callable、Future、FutureTask publi…

半導體劃片機助力氧化鋁陶瓷片切割:科技與工藝的完美結合

在當今半導體制造領域&#xff0c;氧化鋁陶瓷片作為一種高性能、高可靠性的材料&#xff0c;被廣泛應用于各種電子設備中。而半導體劃片機的出現&#xff0c;則為氧化鋁陶瓷片的切割提供了新的解決方案&#xff0c;實現了科技與工藝的完美結合。 氧化鋁陶瓷片是一種以氧化鋁為基…

《巫師3》缺失vcomp110.dll如何解決,如何快速修復vcomp110.dll丟失問題

在日常使用電腦的過程中&#xff0c;我們可能會遇到一些錯誤提示&#xff0c;其中之一就是“vcomp110.dll丟失”。這個錯誤提示通常意味著vcomp110.dll文件在系統中無法找到或加載。那么&#xff0c;vcomp110.dll丟失的原因是什么&#xff1f;它對電腦有什么影響&#xff1f;本…

高德地圖vue實現自定義標點熱力圖效果(縮放時展示不同數據)

高德地圖插件引入省略。。。樣式和vue基礎組件省略。。。 如果每個標點沒有數值&#xff0c;則可以用點聚合來實現功能下面例子&#xff0c;每個標點會有按市統計的數值&#xff0c;而且縮放一定程度時&#xff0c;需要展示按省統計的標點&#xff0c;因此需要自定義標點樣式和…

leetcode刷題日志-54螺旋矩陣

思路&#xff1a; 上下左右設置四個邊界 每走完一行或者一列&#xff0c;移動相應邊界&#xff0c;當左邊界大于右邊界&#xff0c;或者上邊界大于下邊界時&#xff0c;結束 代碼如下&#xff1a; class Solution {public List<Integer> spiralOrder(int[][] matrix) {…

線程上下文切換

線程上下文切換 巧妙地利用了時間片輪轉的方式, CPU 給每個任務都服務一定的時間&#xff0c;然后把當前任務的狀態保存下來&#xff0c;在加載下一任務的狀態后&#xff0c;繼續服務下一任務&#xff0c;任務的狀態保存及再加載, 這段過程就叫做上下文切換。時間片輪轉的方式…

Determining Which Version of GDS is Installed

Determining Which Version of GDS is Installed To determine which version of GDS you have, run the following command: $ gdscheck.py -v Example output: GDS release version: 1.0.0.78 nvidia_fs version: 2.7 libcufile version: 2.4

冒泡排序和直接選擇排序(C/C++實現)

文章目錄 冒泡排序(交換排序&#xff09;基本思想特性總結代碼實現 直接選擇排序基本思想特性總結代碼實現&#xff08;優化&#xff0c;每次循環同時選擇最小和最大的數&#xff09; 冒泡排序(交換排序&#xff09; 基本思想 基本思想&#xff1a;所謂交換&#xff0c;就是根…

class065 A星、Floyd、Bellman-Ford與SPFA【算法】

class065 A星、Floyd、Bellman-Ford與SPFA【算法】 2023-12-9 19:27:02 算法講解065【必備】A星、Floyd、Bellman-Ford與SPFA code1 A*算法模版 // A*算法模版&#xff08;對數器驗證&#xff09; package class065;import java.util.PriorityQueue;// A*算法模版&#xff…