A*(A星)算法Go lang實現

gww3 9年前發布 | 1K 次閱讀 Golang 算法

package main

import ( "container/heap" "fmt" "math" "strings" ) import "strconv"

type OpenList []*_AstarPoint

func (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 := this n := len(old) x := old[n-1] *this = old[0 : n-1] return x }

type _Point struct { x int y int view string }

//========================================================================================

// 保存地圖的基本信息 type Map struct { points [][]_Point blocks map[string]*_Point maxX int maxY 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 row

m.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 { _Point father *_AstarPoint gVal int hVal int fVal 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 SearchRoad struct { theMap Map start _AstarPoint end _AstarPoint closeLi map[string]_AstarPoint openLi OpenList openSet map[string]_AstarPoint TheRoad []_AstarPoint }

func NewSearchRoad(startx, starty, endx, endy int, m Map) SearchRoad { sr := &SearchRoad{} sr.theMap = m sr.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.father
            existAP.father = curPoint
            existAP.calcGVal()
            // 如果新的節點的G值還不如老的節點就恢復老的節點
            if existAP.gVal > oldGVal {
                // restore father
                existAP.father = oldFather
                existAP.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("找不到路徑!")
}

} </pre>

 本文由用戶 gww3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!