gridpathingtest/sauce/astar.go

101 lines
2.3 KiB
Go
Raw Normal View History

2024-02-02 15:59:24 -08:00
package sauce
2024-02-03 00:03:45 -08:00
import (
"math"
)
type Coord struct {
X, Y int16
}
2024-02-02 15:59:24 -08:00
type Node struct {
2024-02-03 00:03:45 -08:00
Coord
parent *Node
g int
f int
d int
2024-02-02 15:59:24 -08:00
}
2024-02-03 00:03:45 -08:00
type Nodes map[Coord]*Node
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
func FindPath(w *World, fromX, fromY int, toX, toY int) ([]Node, bool) {
var open []*Node
visited := make(Nodes)
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
open = append(open, &Node{Coord: Coord{int16(fromX), int16(fromY)}})
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
for len(open) > 0 {
var current *Node
var currentI int
// Set current to lowest f in open
for i, n := range open {
if current == nil || n.f < current.f {
current = n
currentI = i
2024-02-02 15:59:24 -08:00
}
}
2024-02-03 00:03:45 -08:00
// Return reconstructed path if current is the destination.
if current.X == int16(toX) && current.Y == int16(toY) {
var path []Node
for current.parent != nil {
path = append(path, *current)
current = current.parent
2024-02-02 15:59:24 -08:00
}
2024-02-03 00:03:45 -08:00
return path, true
2024-02-02 15:59:24 -08:00
}
2024-02-03 00:03:45 -08:00
// Remove current from the open set.
open = append(open[:currentI], open[currentI+1:]...)
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
// Get neighbors.
var neighbors []*Node
2024-02-02 15:59:24 -08:00
for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ {
if x == 0 && y == 0 {
continue
}
2024-02-03 00:03:45 -08:00
coord := Coord{current.X + int16(x), current.Y + int16(y)}
if cell := w.At(int(coord.X), int(coord.Y)); cell == nil || cell.Hueristic == 255 {
2024-02-02 15:59:24 -08:00
continue
}
2024-02-03 00:03:45 -08:00
neighbors = append(neighbors, &Node{Coord: coord, parent: current, g: math.MaxUint16, f: math.MaxUint16})
2024-02-02 15:59:24 -08:00
}
}
2024-02-03 00:03:45 -08:00
// Iterate over neighbors.
2024-02-02 15:59:24 -08:00
for _, neighbor := range neighbors {
2024-02-03 00:51:41 -08:00
tentativeG := current.g + 1 + int(w.At(int(neighbor.X), int(neighbor.Y)).Hueristic)
2024-02-03 00:03:45 -08:00
distance := int(math.Abs(float64(neighbor.X)-float64(toX)) + math.Abs(float64(neighbor.Y)-float64(toY)))
tentativeF := tentativeG + distance
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
var node *Node
if node = visited[neighbor.Coord]; node == nil || tentativeF < node.f {
if node == nil {
node = neighbor
2024-02-02 15:59:24 -08:00
}
2024-02-03 00:03:45 -08:00
node.g = tentativeG
node.f = tentativeF
node.d = distance
visited[node.Coord] = node
open = append(open, node)
2024-02-02 15:59:24 -08:00
}
2024-02-03 00:03:45 -08:00
}
}
2024-02-02 15:59:24 -08:00
2024-02-03 00:03:45 -08:00
var current *Node
// Set current to lowest f in open
for _, n := range visited {
if current == nil || n.d < current.d {
current = n
2024-02-02 15:59:24 -08:00
}
}
2024-02-03 00:03:45 -08:00
// Return reconstructed path if current is the destination.
var path []Node
for current != nil && current.parent != nil {
path = append(path, *current)
current = current.parent
}
return path, false
2024-02-02 15:59:24 -08:00
}