mirror of
https://github.com/onyx-and-iris/aoc2024.git
synced 2025-01-09 22:30:47 +00:00
101 lines
1.9 KiB
Go
101 lines
1.9 KiB
Go
package one
|
|
|
|
import (
|
|
hp "container/heap"
|
|
"errors"
|
|
"math"
|
|
"slices"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const turnCost int = 1000
|
|
|
|
type graph struct {
|
|
start node
|
|
end node
|
|
data []string
|
|
}
|
|
|
|
func newGraph() *graph {
|
|
return &graph{}
|
|
}
|
|
|
|
func (g *graph) String() string {
|
|
return strings.Join(g.data, "\n")
|
|
}
|
|
|
|
func (g *graph) valueAt(n node) rune {
|
|
return rune(g.data[n.y][n.x])
|
|
}
|
|
|
|
func (g *graph) dijkstra() (int, error) {
|
|
heap := newHeap()
|
|
hp.Push(heap, move{g.start, 0})
|
|
visited := make(map[node]struct{})
|
|
costs := make(map[node]int)
|
|
prev := make(map[node]node)
|
|
|
|
for heap.Len() > 0 {
|
|
current := hp.Pop(heap).(move)
|
|
|
|
if current.node.coords == g.end.coords {
|
|
log.Debugf("\n%s\n", g.debug(prev, costs))
|
|
return costs[g.end], nil
|
|
}
|
|
|
|
if _, ok := visited[current.node]; ok {
|
|
continue
|
|
}
|
|
visited[current.node] = struct{}{}
|
|
|
|
for _, n := range neighbours(current.node) {
|
|
if g.valueAt(n) == '#' {
|
|
continue
|
|
}
|
|
|
|
next_cost := current.cost + 1
|
|
if n.direction != current.node.direction {
|
|
next_cost += turnCost
|
|
}
|
|
|
|
_, ok := costs[n]
|
|
if !ok {
|
|
costs[n] = math.MaxInt
|
|
}
|
|
|
|
if next_cost < costs[n] {
|
|
costs[n] = next_cost
|
|
prev[n] = current.node
|
|
hp.Push(heap, move{n, next_cost})
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0, errors.New("unable to get shortest path cost")
|
|
}
|
|
|
|
func (g *graph) debug(prev map[node]node, costs map[node]int) string {
|
|
path := []node{g.end}
|
|
|
|
node := prev[g.end]
|
|
for node != g.start {
|
|
path = append(path, prev[node])
|
|
node = prev[node]
|
|
}
|
|
|
|
temp := slices.Clone(g.data)
|
|
for _, node := range path {
|
|
if g.valueAt(node) == 'S' || g.valueAt(node) == 'E' {
|
|
continue
|
|
}
|
|
temp[node.y] = replaceAtIndex(temp[node.y], []rune{'^', '>', 'v', '<'}[node.direction], node.x)
|
|
}
|
|
|
|
log.Debugf("len of shortest path: %d", len(path))
|
|
log.Debugf("cost of shortest path: %d", costs[g.end])
|
|
|
|
return strings.Join(temp, "\n")
|
|
}
|