goonscape/game/pathfinding.go
2025-02-14 13:35:09 +01:00

114 lines
2.4 KiB
Go

package game
import (
"fmt"
"gitea.boner.be/bdnugget/goonscape/types"
)
type Node struct {
Tile types.Tile
Parent *Node
G, H, F float32
}
func FindPath(start, end types.Tile) []types.Tile {
openList := []*Node{}
closedList := make(map[[2]int]bool)
startNode := &Node{Tile: start, G: 0, H: heuristic(start, end)}
startNode.F = startNode.G + startNode.H
openList = append(openList, startNode)
for len(openList) > 0 {
current := openList[0]
currentIndex := 0
for i, node := range openList {
if node.F < current.F {
current = node
currentIndex = i
}
}
openList = append(openList[:currentIndex], openList[currentIndex+1:]...)
closedList[[2]int{current.Tile.X, current.Tile.Y}] = true
if current.Tile.X == end.X && current.Tile.Y == end.Y {
path := []types.Tile{}
node := current
for node != nil {
path = append([]types.Tile{node.Tile}, path...)
node = node.Parent
}
fmt.Printf("Path found: %v\n", path)
return path
}
neighbors := GetNeighbors(current.Tile)
for _, neighbor := range neighbors {
if !neighbor.Walkable || closedList[[2]int{neighbor.X, neighbor.Y}] {
continue
}
tentativeG := current.G + distance(current.Tile, neighbor)
inOpen := false
var existingNode *Node
for _, node := range openList {
if node.Tile.X == neighbor.X && node.Tile.Y == neighbor.Y {
existingNode = node
inOpen = true
break
}
}
if !inOpen || tentativeG < existingNode.G {
newNode := &Node{
Tile: neighbor,
Parent: current,
G: tentativeG,
H: heuristic(neighbor, end),
}
newNode.F = newNode.G + newNode.H
if !inOpen {
openList = append(openList, newNode)
}
}
}
}
return nil
}
func heuristic(a, b types.Tile) float32 {
return float32(abs(a.X-b.X) + abs(a.Y-b.Y))
}
func distance(a, b types.Tile) float32 {
_, _ = a, b
return 1.0 // uniform cost for now
}
func GetNeighbors(tile types.Tile) []types.Tile {
directions := [][2]int{
{1, 0}, {-1, 0}, {0, 1}, {0, -1},
{1, 1}, {-1, -1}, {1, -1}, {-1, 1},
}
neighbors := []types.Tile{}
grid := GetMapGrid()
for _, dir := range directions {
nx, ny := tile.X+dir[0], tile.Y+dir[1]
if nx >= 0 && nx < types.MapWidth && ny >= 0 && ny < types.MapHeight {
if grid[nx][ny].Walkable {
neighbors = append(neighbors, grid[nx][ny])
}
}
}
return neighbors
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}