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") }