package one import ( hp "container/heap" "errors" "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, 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) const turnCost int = 1000 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") }