之前发表一个A*的python实现,连接:点击打开链接

最近正在学习Go语言,基本的语法等东西已经掌握了。但是纸上得来终觉浅,绝知此事要躬行嘛。必要的练手是一定要做的。正好离写python版的A*不那么久远。这个例子复杂度中等。还可以把之前用python实现是没有考虑的部分整理一下。

这一版的GO实现更加模块化了,同时用二叉堆来保证了openlist的查找性能。可以说离应用到实现工程中的要求差距不太远了。

  1. package main
  2. import (
  3. "container/heap"
  4. "fmt"
  5. "math"
  6. "strings"
  7. )
  8. import "strconv"
  9. type _Point struct {
  10. x int
  11. y int
  12. view string
  13. }
  14. //========================================================================================
  15. // 保存地图的基本信息
  16. type Map struct {
  17. points [][]_Point
  18. blocks map[string]*_Point
  19. maxX int
  20. maxY int
  21. }
  22. func NewMap(charMap []string) (m Map) {
  23. m.points = make([][]_Point, len(charMap))
  24. m.blocks = make(map[string]*_Point, len(charMap)*2)
  25. for x, row := range charMap {
  26. cols := strings.Split(row, " ")
  27. m.points[x] = make([]_Point, len(cols))
  28. for y, view := range cols {
  29. m.points[x][y] = _Point{x, y, view}
  30. if view == "X" {
  31. m.blocks[pointAsKey(x, y)] = &m.points[x][y]
  32. }
  33. } // end of cols
  34. } // end of row
  35. m.maxX = len(m.points)
  36. m.maxY = len(m.points[0])
  37. return m
  38. }
  39. func (this *Map) getAdjacentPoint(curPoint *_Point) (adjacents []*_Point) {
  40. if x, y := curPoint.x, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  41. adjacents = append(adjacents, &this.points[x][y])
  42. }
  43. if x, y := curPoint.x+1, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  44. adjacents = append(adjacents, &this.points[x][y])
  45. }
  46. if x, y := curPoint.x+1, curPoint.y; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  47. adjacents = append(adjacents, &this.points[x][y])
  48. }
  49. if x, y := curPoint.x+1, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  50. adjacents = append(adjacents, &this.points[x][y])
  51. }
  52. if x, y := curPoint.x, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  53. adjacents = append(adjacents, &this.points[x][y])
  54. }
  55. if x, y := curPoint.x-1, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  56. adjacents = append(adjacents, &this.points[x][y])
  57. }
  58. if x, y := curPoint.x-1, curPoint.y; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  59. adjacents = append(adjacents, &this.points[x][y])
  60. }
  61. if x, y := curPoint.x-1, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {
  62. adjacents = append(adjacents, &this.points[x][y])
  63. }
  64. return adjacents
  65. }
  66. func (this *Map) PrintMap(path *SearchRoad) {
  67. fmt.Println("map's border:", this.maxX, this.maxY)
  68. for x := 0; x < this.maxX; x++ {
  69. for y := 0; y < this.maxY; y++ {
  70. if path != nil {
  71. if x == path.start.x && y == path.start.y {
  72. fmt.Print("S")
  73. goto NEXT
  74. }
  75. if x == path.end.x && y == path.end.y {
  76. fmt.Print("E")
  77. goto NEXT
  78. }
  79. for i := 0; i < len(path.TheRoad); i++ {
  80. if path.TheRoad[i].x == x && path.TheRoad[i].y == y {
  81. fmt.Print("*")
  82. goto NEXT
  83. }
  84. }
  85. }
  86. fmt.Print(this.points[x][y].view)
  87. NEXT:
  88. }
  89. fmt.Println()
  90. }
  91. }
  92. func pointAsKey(x, y int) (key string) {
  93. key = strconv.Itoa(x) + "," + strconv.Itoa(y)
  94. return key
  95. }
  96. //========================================================================================
  97. type _AstarPoint struct {
  98. _Point
  99. father *_AstarPoint
  100. gVal int
  101. hVal int
  102. fVal int
  103. }
  104. func NewAstarPoint(p *_Point, father *_AstarPoint, end *_AstarPoint) (ap *_AstarPoint) {
  105. ap = &_AstarPoint{*p, father, 0, 0, 0}
  106. if end != nil {
  107. ap.calcFVal(end)
  108. }
  109. return ap
  110. }
  111. func (this *_AstarPoint) calcGVal() int {
  112. if this.father != nil {
  113. deltaX := math.Abs(float64(this.father.x - this.x))
  114. deltaY := math.Abs(float64(this.father.y - this.y))
  115. if deltaX == 1 && deltaY == 0 {
  116. this.gVal = this.father.gVal + 10
  117. } else if deltaX == 0 && deltaY == 1 {
  118. this.gVal = this.father.gVal + 10
  119. } else if deltaX == 1 && deltaY == 1 {
  120. this.gVal = this.father.gVal + 14
  121. } else {
  122. panic("father point is invalid!")
  123. }
  124. }
  125. return this.gVal
  126. }
  127. func (this *_AstarPoint) calcHVal(end *_AstarPoint) int {
  128. this.hVal = int(math.Abs(float64(end.x-this.x)) + math.Abs(float64(end.y-this.y)))
  129. return this.hVal
  130. }
  131. func (this *_AstarPoint) calcFVal(end *_AstarPoint) int {
  132. this.fVal = this.calcGVal() + this.calcHVal(end)
  133. return this.fVal
  134. }
  135. //========================================================================================
  136. type OpenList []*_AstarPoint
  137. func (self OpenList) Len() int { return len(self) }
  138. func (self OpenList) Less(i, j int) bool { return self[i].fVal < self[j].fVal }
  139. func (self OpenList) Swap(i, j int) { self[i], self[j] = self[j], self[i] }
  140. func (this *OpenList) Push(x interface{}) {
  141. // Push and Pop use pointer receivers because they modify the slice's length,
  142. // not just its contents.
  143. *this = append(*this, x.(*_AstarPoint))
  144. }
  145. func (this *OpenList) Pop() interface{} {
  146. old := *this
  147. n := len(old)
  148. x := old[n-1]
  149. *this = old[0 : n-1]
  150. return x
  151. }
  152. //========================================================================================
  153. type SearchRoad struct {
  154. theMap *Map
  155. start _AstarPoint
  156. end _AstarPoint
  157. closeLi map[string]*_AstarPoint
  158. openLi OpenList
  159. openSet map[string]*_AstarPoint
  160. TheRoad []*_AstarPoint
  161. }
  162. func NewSearchRoad(startx, starty, endx, endy int, m *Map) *SearchRoad {
  163. sr := &SearchRoad{}
  164. sr.theMap = m
  165. sr.start = *NewAstarPoint(&_Point{startx, starty, "S"}, nil, nil)
  166. sr.end = *NewAstarPoint(&_Point{endx, endy, "E"}, nil, nil)
  167. sr.TheRoad = make([]*_AstarPoint, 0)
  168. sr.openSet = make(map[string]*_AstarPoint, m.maxX+m.maxY)
  169. sr.closeLi = make(map[string]*_AstarPoint, m.maxX+m.maxY)
  170. heap.Init(&sr.openLi)
  171. heap.Push(&sr.openLi, &sr.start) // 首先把起点加入开放列表
  172. sr.openSet[pointAsKey(sr.start.x, sr.start.y)] = &sr.start
  173. // 将障碍点放入关闭列表
  174. for k, v := range m.blocks {
  175. sr.closeLi[k] = NewAstarPoint(v, nil, nil)
  176. }
  177. return sr
  178. }
  179. func (this *SearchRoad) FindoutRoad() bool {
  180. for len(this.openLi) > 0 {
  181. // 将节点从开放列表移到关闭列表当中。
  182. x := heap.Pop(&this.openLi)
  183. curPoint := x.(*_AstarPoint)
  184. delete(this.openSet, pointAsKey(curPoint.x, curPoint.y))
  185. this.closeLi[pointAsKey(curPoint.x, curPoint.y)] = curPoint
  186. //fmt.Println("curPoint :", curPoint.x, curPoint.y)
  187. adjacs := this.theMap.getAdjacentPoint(&curPoint._Point)
  188. for _, p := range adjacs {
  189. //fmt.Println("\t adjact :", p.x, p.y)
  190. theAP := NewAstarPoint(p, curPoint, &this.end)
  191. if pointAsKey(theAP.x, theAP.y) == pointAsKey(this.end.x, this.end.y) {
  192. // 找出路径了, 标记路径
  193. for theAP.father != nil {
  194. this.TheRoad = append(this.TheRoad, theAP)
  195. theAP.view = "*"
  196. theAP = theAP.father
  197. }
  198. return true
  199. }
  200. _, ok := this.closeLi[pointAsKey(p.x, p.y)]
  201. if ok {
  202. continue
  203. }
  204. existAP, ok := this.openSet[pointAsKey(p.x, p.y)]
  205. if !ok {
  206. heap.Push(&this.openLi, theAP)
  207. this.openSet[pointAsKey(theAP.x, theAP.y)] = theAP
  208. } else {
  209. oldGVal, oldFather := existAP.gVal, existAP.father
  210. existAP.father = curPoint
  211. existAP.calcGVal()
  212. // 如果新的节点的G值还不如老的节点就恢复老的节点
  213. if existAP.gVal > oldGVal {
  214. // restore father
  215. existAP.father = oldFather
  216. existAP.gVal = oldGVal
  217. }
  218. }
  219. }
  220. }
  221. return false
  222. }
  223. //========================================================================================
  224. func main() {
  225. presetMap := []string{
  226. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  227. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  228. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  229. "X . X X X X X X X X X X X X X X X X X X X X X X X X X",
  230. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  231. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  232. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  233. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  234. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  235. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  236. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  237. "X X X X X X X X X X X X X X X X X X X X X X X X . X X",
  238. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  239. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  240. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  241. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  242. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  243. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  244. ". . . . . . . . . . . . . . . . . . . . . . . . . . .",
  245. }
  246. m := NewMap(presetMap)
  247. m.PrintMap(nil)
  248. searchRoad := NewSearchRoad(0, 0, 18, 10, &m)
  249. if searchRoad.FindoutRoad() {
  250. fmt.Println("找到了, 你看!")
  251. m.PrintMap(searchRoad)
  252. } else {
  253. fmt.Println("找不到路径!")
  254. }
  255. }

A*(A星)算法Go lang实现的更多相关文章

  1. POJ 2449 Remmarguts' Date (SPFA + A星算法) - from lanshui_Yang

    题目大意:给你一个有向图,并给你三个数s.t 和 k ,让你求从点 s 到 点 t 的第 k 短的路径.如果第 k 短路不存在,则输出“-1” ,否则,输出第 k 短路的长度. 解题思路:这道题是一道 ...

  2. 算法起步之A星算法

    原文:算法起步之A星算法 用途: 寻找最短路径,优于bfs跟dfs 描述: 基本描述是,在深度优先搜索的基础上,增加了一个启发式算法,在选择节点的过程中,不是盲目选择,而是有目的的选的,F=G+H,f ...

  3. Cocos2d-x 3.1.1 学习日志16--A星算法(A*搜索算法)学问

    A *搜索算法称为A星算法.这是一个在图形平面,路径.求出最低通过成本的算法. 经常使用于游戏中的NPC的移动计算,或线上游戏的BOT的移动计算上. 首先:1.在Map地图中任取2个点,開始点和结束点 ...

  4. A*搜寻算法(A星算法)

    A*搜寻算法[编辑] 维基百科,自由的百科全书 本条目需要补充更多来源.(2015年6月30日) 请协助添加多方面可靠来源以改善这篇条目,无法查证的内容可能会被提出异议而移除. A*搜索算法,俗称A星 ...

  5. Java开源-astar:A 星算法

    astar A星算法Java实现 一.适用场景 在一张地图中,绘制从起点移动到终点的最优路径,地图中会有障碍物,必须绕开障碍物. 二.算法思路 1. 回溯法得到路径 (如果有路径)采用“结点与结点的父 ...

  6. A星算法(Java实现)

    一.适用场景 在一张地图中.绘制从起点移动到终点的最优路径,地图中会有障碍物.必须绕开障碍物. 二.算法思路 1. 回溯法得到路径 (假设有路径)採用"结点与结点的父节点"的关系从 ...

  7. JAVA根据A星算法规划起点到终点二维坐标的最短路径

    工具类 AStarUtil.java import java.util.*; import java.util.stream.Collectors; /** * A星算法工具类 */ public c ...

  8. AStar A* A星 算法TypeScript版本

    一 演示效果 二  参考教程 <ActionScript3.0 高级动画教程> + 源码 http://download.csdn.net/download/zhengchengpeng/ ...

  9. 基于HTML5的WebGL呈现A星算法3D可视化

    http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现 ...

随机推荐

  1. 这次一定理清晰ThinkPHP之中的模型、数据库之间命名规范

    ServiceSiteModel.class.php 这个模型操控的数据库是service_site表: <?php namespace Admin\Model; use Think\Model ...

  2. 一款jQuery实现重力弹动模拟效果特效,弹弹弹,弹走IE6

    一款jQuery实现重力弹动模拟效果特效 鼠标经过两块黑色div中间的红色线时,下方的黑快会突然掉落, 并在掉落地上那一刻出现了弹跳的jquery特效效果,非常不错,还兼容所有的浏览器, 适用浏览器: ...

  3. 基于jQuery打造的选项卡向上弹出jquery焦点图切换特效

    基于jQuery打造的选项卡向上弹出jquery焦点图切换特效 鼠标经过标题栏,会出现层特效向上滑动,并且在同时进行幻灯片切换,效果十分不错. 有兴趣的童鞋可以下载看看,在IE6方面兼容性也不错,只有 ...

  4. PHP学习之路 (2)

    我们如果坚持用windows做PHP开发,就会错误不断,所以,无论如何都要学习Linux的使用和安装.说实话<鸟哥的linux私房菜>是一本非常不错的书,但是如果你想照着书上面一步一步安装 ...

  5. .Net之美

    第1章 C#类型基础 1.1 值类型和引用类型值类型和引用类型是以它们在计算机内存中是如何被分配的来划分的.值类型包括了结构和枚举,引用类型则包括了类. 接口. 委托等. 还有一种特殊的值类型,称为简 ...

  6. 在usercontrol中如何使用验证控件CustomValidator 中的客户端验证

    在用户控件中,为一个文本控件添加CustomValidator验证,然后设置CustomValidator 的ClientValidationFunction 属性为客户端的Validate(sour ...

  7. Python 网页投票信息抓取

    最近学习python,为了巩固一下学过的知识,花了半天(主要还是因为自己正则表达式不熟)写了个小脚本来抓取一个网站上的投票信息,排名后进行输出. 抓取的网站网址是http://www.mudidi.n ...

  8. C基础 北京大公司面试简单总结

    作者有话说 这是关于程序员面试的一篇文章, 希望对你有帮助. 干了快3年了. 可以简单参考, 对比总结.虽然本人很水. 很喜欢当前做的手游项目.做的很认真.后端每个人技术都很好.但是结果都不如意.在死 ...

  9. C++ json库jsoncpp 吐槽

    Explain 最近在做游戏接入SDK时用到C++的json库jsoncpp,jsoncpp 是一款优秀的json库,但恶心的一点是它采用Assert作为错误处理方法,而assert在linux下通过 ...

  10. wpa_supplicant软件架构分析

    wpa_supplicant软件架构分析 1. 启动命令 wpa supplicant 在启动时,启动命令可以带有很多参数,目前我们的启动命令如下: wpa_supplicant /system/bi ...