aoc2024/day-16/internal/two/graph.go

92 lines
1.7 KiB
Go
Raw Normal View History

2024-12-19 01:27:45 +00:00
package two
import (
hp "container/heap"
"math"
"slices"
"strings"
log "github.com/sirupsen/logrus"
)
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 {
heap := newHeap()
hp.Push(heap, move{g.start, 0, []node{g.start}})
visited := make(map[node]int)
const turnCost int = 1000
lowestCost := math.MaxInt
bestPaths := [][]node{}
for heap.Len() > 0 {
current := hp.Pop(heap).(move)
// we're on a path that's already exceeded the lowest cost
if current.cost > lowestCost {
continue
}
if g.valueAt(current.node) == 'E' {
bestPaths = append(bestPaths, current.path)
lowestCost = current.cost
continue
}
if v, ok := visited[current.node]; ok {
if v < current.cost {
continue
}
}
visited[current.node] = current.cost
for _, n := range neighbours(current.node) {
if g.valueAt(current.node) == '#' {
continue
}
next_cost := current.cost + 1
if n.direction != current.node.direction {
next_cost += turnCost
}
hp.Push(heap, newMove(n, next_cost, append(slices.Clone(current.path), n)))
}
}
possibleSafe := make(map[coords]struct{})
for _, path := range bestPaths {
for _, n := range path {
possibleSafe[n.coords] = struct{}{}
}
}
log.Debugf("\n%s\n", g.debug(possibleSafe))
return len(possibleSafe)
}
func (g *graph) debug(possibleSafe map[coords]struct{}) string {
temp := slices.Clone(g.data)
for n := range possibleSafe {
temp[n.y] = replaceAtIndex(temp[n.y], 'O', n.x)
}
return strings.Join(temp, "\n")
}