Add pathfinding garbagio

This commit is contained in:
Ketchetwahmeegwun T. Southall 2024-02-03 00:03:45 -08:00
parent c5cad47762
commit a9fba17943
2 changed files with 99 additions and 56 deletions

View File

@ -27,6 +27,8 @@ type Game struct {
cellX, cellY int cellX, cellY int
fromX, fromY int fromX, fromY int
toX, toY int toX, toY int
path []sauce.Node
pathSuccess bool
whichFromTo bool whichFromTo bool
} }
@ -35,6 +37,10 @@ func NewGame() *Game {
g.world = sauce.NewWorld(3, 3) g.world = sauce.NewWorld(3, 3)
g.world.HueristicLine(10, 0, 10, 10, 1) g.world.HueristicLine(10, 0, 10, 10, 1)
g.world.HueristicLine(10, 13, 10, 30, 1) g.world.HueristicLine(10, 13, 10, 30, 1)
g.fromX = -1
g.fromY = -1
g.toX = -1
g.toY = -1
return g return g
} }
@ -62,10 +68,13 @@ func (g *Game) Update() error {
g.cellX = cursorX / CellSize g.cellX = cursorX / CellSize
g.cellY = cursorY / CellSize g.cellY = cursorY / CellSize
if cell := g.world.At(g.cellX, g.cellY); cell != nil { if cell := g.world.At(g.cellX, g.cellY); cell != nil {
var reroll bool
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) { if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
cell.Hueristic++ cell.Hueristic++
reroll = true
} else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) { } else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonRight) {
cell.Hueristic-- cell.Hueristic--
reroll = true
} else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonMiddle) { } else if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonMiddle) {
if !g.whichFromTo { if !g.whichFromTo {
g.fromX, g.fromY = g.cellX, g.cellY g.fromX, g.fromY = g.cellX, g.cellY
@ -73,6 +82,13 @@ func (g *Game) Update() error {
g.toX, g.toY = g.cellX, g.cellY g.toX, g.toY = g.cellX, g.cellY
} }
g.whichFromTo = !g.whichFromTo g.whichFromTo = !g.whichFromTo
reroll = true
}
if reroll {
if g.fromX != -1 && g.fromY != -1 && g.toX != -1 && g.toY != -1 {
g.path, g.pathSuccess = sauce.FindPath(g.world, g.fromX, g.fromY, g.toX, g.toY)
}
} }
} }
return nil return nil
@ -117,6 +133,18 @@ func (g *Game) Draw(screen *ebiten.Image) {
} }
} }
} }
// Draw path dots overtop.
for _, node := range g.path {
x := node.X*CellSize + CellSize/2
y := node.Y*CellSize + CellSize/2
c := color.RGBA{0, 255, 0, 255}
if !g.pathSuccess {
c = color.RGBA{255, 0, 0, 255}
}
vector.DrawFilledCircle(screen, float32(x), float32(y), 5, c, false)
}
ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS())) ebitenutil.DebugPrint(screen, fmt.Sprintf("TPS: %0.2f\nFPS: %0.2f", ebiten.ActualTPS(), ebiten.ActualFPS()))
} }

View File

@ -1,85 +1,100 @@
package sauce package sauce
type Node struct { import (
parent *Node "math"
x, y int )
f, g, h int
type Coord struct {
X, Y int16
} }
func FindPath(w *World, fromX, fromY int, toX, toY int) []Node { type Node struct {
openList := make([]*Node, 0) Coord
closedList := make([]*Node, 0) parent *Node
g int
f int
d int
}
startNode := &Node{x: fromX, y: fromY} type Nodes map[Coord]*Node
endNode := &Node{x: toX, y: toY}
openList = append(openList, startNode) func FindPath(w *World, fromX, fromY int, toX, toY int) ([]Node, bool) {
var open []*Node
visited := make(Nodes)
for len(openList) > 0 { open = append(open, &Node{Coord: Coord{int16(fromX), int16(fromY)}})
var cnode *Node
var cindex int for len(open) > 0 {
for i, node := range openList { var current *Node
if cnode == nil || node.f < cnode.f { var currentI int
cnode = node // Set current to lowest f in open
cindex = i for i, n := range open {
if current == nil || n.f < current.f {
current = n
currentI = i
} }
} }
openList = append(openList[:cindex], openList[cindex+1:]...)
closedList = append(closedList, cnode)
if cnode.x == endNode.x && cnode.y == endNode.y { // Return reconstructed path if current is the destination.
path := make([]Node, 0) if current.X == int16(toX) && current.Y == int16(toY) {
for cnode != nil { var path []Node
path = append(path, *cnode) for current.parent != nil {
cnode = cnode.parent path = append(path, *current)
current = current.parent
} }
return path return path, true
} }
// Remove current from the open set.
open = append(open[:currentI], open[currentI+1:]...)
var neighbors []Node // Get neighbors.
var neighbors []*Node
for x := -1; x <= 1; x++ { for x := -1; x <= 1; x++ {
for y := -1; y <= 1; y++ { for y := -1; y <= 1; y++ {
if x == 0 && y == 0 { if x == 0 && y == 0 {
continue continue
} }
if x != 0 && y != 0 { 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 {
continue continue
} }
if cell := w.At(cnode.x+x, cnode.y+y); cell != nil { neighbors = append(neighbors, &Node{Coord: coord, parent: current, g: math.MaxUint16, f: math.MaxUint16})
neighbors = append(neighbors, Node{x: cnode.x + x, y: cnode.y + y, parent: cnode})
}
} }
} }
// Iterate over neighbors.
for _, neighbor := range neighbors { for _, neighbor := range neighbors {
exists := false tentativeG := current.g + 1
for _, node := range closedList { distance := int(math.Abs(float64(neighbor.X)-float64(toX)) + math.Abs(float64(neighbor.Y)-float64(toY)))
if node.x == neighbor.x && node.y == neighbor.y { tentativeF := tentativeG + distance
exists = true
break var node *Node
if node = visited[neighbor.Coord]; node == nil || tentativeF < node.f {
if node == nil {
node = neighbor
} }
node.g = tentativeG
node.f = tentativeF
node.d = distance
visited[node.Coord] = node
open = append(open, node)
} }
if exists {
continue
}
exists = false
for _, node := range openList {
if node.x == neighbor.x && node.y == neighbor.y {
exists = true
break
}
}
if exists {
continue
}
neighbor.g = cnode.g + 1 // this value potentially should be a float and modified if a diagonal.
neighbor.h = (toX - neighbor.x) + (toY - neighbor.y) // Maybe should be calculated differently.
neighbor.f = neighbor.g + neighbor.h
openList = append(openList, &neighbor)
} }
} }
return nil
var current *Node
// Set current to lowest f in open
for _, n := range visited {
if current == nil || n.d < current.d {
current = n
}
}
// 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
} }