标签:
之前发表一个A*的python实现,连接:点击打开链接
最近正在学习Go语言,基本的语法等东西已经掌握了。但是纸上得来终觉浅,绝知此事要躬行嘛。必要的练手是一定要做的。正好离写python版的A*不那么久远。这个例子复杂度中等。还可以把之前用python实现是没有考虑的部分整理一下。
这一版的GO实现更加模块化了,同时用二叉堆来保证了openlist的查找性能。可以说离应用到实现工程中的要求差距不太远了。
package mainimport ("container/heap""fmt""math""strings")import "strconv"type _Point struct {x inty intview string}//========================================================================================// 保存地图的基本信息type Map struct {points [][]_Pointblocks map[string]*_PointmaxX intmaxY int}func NewMap(charMap []string) (m Map) {m.points = make([][]_Point, len(charMap))m.blocks = make(map[string]*_Point, len(charMap)*2)for x, row := range charMap {cols := strings.Split(row, " ")m.points[x] = make([]_Point, len(cols))for y, view := range cols {m.points[x][y] = _Point{x, y, view}if view == "X" {m.blocks[pointAsKey(x, y)] = &m.points[x][y]}} // end of cols} // end of rowm.maxX = len(m.points)m.maxY = len(m.points[0])return m}func (this *Map) getAdjacentPoint(curPoint *_Point) (adjacents []*_Point) {if x, y := curPoint.x, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x+1, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x+1, curPoint.y; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x+1, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x-1, curPoint.y+1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x-1, curPoint.y; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}if x, y := curPoint.x-1, curPoint.y-1; x >= 0 && x < this.maxX && y >= 0 && y < this.maxY {adjacents = append(adjacents, &this.points[x][y])}return adjacents}func (this *Map) PrintMap(path *SearchRoad) {fmt.Println("map‘s border:", this.maxX, this.maxY)for x := 0; x < this.maxX; x++ {for y := 0; y < this.maxY; y++ {if path != nil {if x == path.start.x && y == path.start.y {fmt.Print("S")goto NEXT}if x == path.end.x && y == path.end.y {fmt.Print("E")goto NEXT}for i := 0; i < len(path.TheRoad); i++ {if path.TheRoad[i].x == x && path.TheRoad[i].y == y {fmt.Print("*")goto NEXT}}}fmt.Print(this.points[x][y].view)NEXT:}fmt.Println()}}func pointAsKey(x, y int) (key string) {key = strconv.Itoa(x) + "," + strconv.Itoa(y)return key}//========================================================================================type _AstarPoint struct {_Pointfather *_AstarPointgVal inthVal intfVal int}func NewAstarPoint(p *_Point, father *_AstarPoint, end *_AstarPoint) (ap *_AstarPoint) {ap = &_AstarPoint{*p, father, 0, 0, 0}if end != nil {ap.calcFVal(end)}return ap}func (this *_AstarPoint) calcGVal() int {if this.father != nil {deltaX := math.Abs(float64(this.father.x - this.x))deltaY := math.Abs(float64(this.father.y - this.y))if deltaX == 1 && deltaY == 0 {this.gVal = this.father.gVal + 10} else if deltaX == 0 && deltaY == 1 {this.gVal = this.father.gVal + 10} else if deltaX == 1 && deltaY == 1 {this.gVal = this.father.gVal + 14} else {panic("father point is invalid!")}}return this.gVal}func (this *_AstarPoint) calcHVal(end *_AstarPoint) int {this.hVal = int(math.Abs(float64(end.x-this.x)) + math.Abs(float64(end.y-this.y)))return this.hVal}func (this *_AstarPoint) calcFVal(end *_AstarPoint) int {this.fVal = this.calcGVal() + this.calcHVal(end)return this.fVal}//========================================================================================type OpenList []*_AstarPointfunc (self OpenList) Len() int { return len(self) }func (self OpenList) Less(i, j int) bool { return self[i].fVal < self[j].fVal }func (self OpenList) Swap(i, j int) { self[i], self[j] = self[j], self[i] }func (this *OpenList) Push(x interface{}) {// Push and Pop use pointer receivers because they modify the slice‘s length,// not just its contents.*this = append(*this, x.(*_AstarPoint))}func (this *OpenList) Pop() interface{} {old := *thisn := len(old)x := old[n-1]*this = old[0 : n-1]return x}//========================================================================================type SearchRoad struct {theMap *Mapstart _AstarPointend _AstarPointcloseLi map[string]*_AstarPointopenLi OpenListopenSet map[string]*_AstarPointTheRoad []*_AstarPoint}func NewSearchRoad(startx, starty, endx, endy int, m *Map) *SearchRoad {sr := &SearchRoad{}sr.theMap = msr.start = *NewAstarPoint(&_Point{startx, starty, "S"}, nil, nil)sr.end = *NewAstarPoint(&_Point{endx, endy, "E"}, nil, nil)sr.TheRoad = make([]*_AstarPoint, 0)sr.openSet = make(map[string]*_AstarPoint, m.maxX+m.maxY)sr.closeLi = make(map[string]*_AstarPoint, m.maxX+m.maxY)heap.Init(&sr.openLi)heap.Push(&sr.openLi, &sr.start) // 首先把起点加入开放列表sr.openSet[pointAsKey(sr.start.x, sr.start.y)] = &sr.start// 将障碍点放入关闭列表for k, v := range m.blocks {sr.closeLi[k] = NewAstarPoint(v, nil, nil)}return sr}func (this *SearchRoad) FindoutRoad() bool {for len(this.openLi) > 0 {// 将节点从开放列表移到关闭列表当中。x := heap.Pop(&this.openLi)curPoint := x.(*_AstarPoint)delete(this.openSet, pointAsKey(curPoint.x, curPoint.y))this.closeLi[pointAsKey(curPoint.x, curPoint.y)] = curPoint//fmt.Println("curPoint :", curPoint.x, curPoint.y)adjacs := this.theMap.getAdjacentPoint(&curPoint._Point)for _, p := range adjacs {//fmt.Println("\t adjact :", p.x, p.y)theAP := NewAstarPoint(p, curPoint, &this.end)if pointAsKey(theAP.x, theAP.y) == pointAsKey(this.end.x, this.end.y) {// 找出路径了, 标记路径for theAP.father != nil {this.TheRoad = append(this.TheRoad, theAP)theAP.view = "*"theAP = theAP.father}return true}_, ok := this.closeLi[pointAsKey(p.x, p.y)]if ok {continue}existAP, ok := this.openSet[pointAsKey(p.x, p.y)]if !ok {heap.Push(&this.openLi, theAP)this.openSet[pointAsKey(theAP.x, theAP.y)] = theAP} else {oldGVal, oldFather := existAP.gVal, existAP.fatherexistAP.father = curPointexistAP.calcGVal()// 如果新的节点的G值还不如老的节点就恢复老的节点if existAP.gVal > oldGVal {// restore fatherexistAP.father = oldFatherexistAP.gVal = oldGVal}}}}return false}//========================================================================================func main() {presetMap := []string{". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .","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",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .","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",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",". . . . . . . . . . . . . . . . . . . . . . . . . . .",}m := NewMap(presetMap)m.PrintMap(nil)searchRoad := NewSearchRoad(0, 0, 18, 10, &m)if searchRoad.FindoutRoad() {fmt.Println("找到了, 你看!")m.PrintMap(searchRoad)} else {fmt.Println("找不到路径!")}}
标签:
原文地址:http://www.cnblogs.com/nobugtodebug/p/4500280.html