package two import ( "errors" "math" "slices" "strings" "github.com/onyx-and-iris/aoc2024/day-18/internal/queue" ) type graph struct { start point end point data []string } func newGraph(width, height, numCorruptions int, corruptedCoords [][]int) *graph { var data []string var sb strings.Builder for range height { for range width { sb.WriteRune('.') } data = append(data, sb.String()) sb.Reset() } for _, coords := range corruptedCoords[:numCorruptions] { data[coords[1]] = replaceAtIndex(data[coords[1]], '#', coords[0]) } return &graph{point{0, 0}, point{len(data[0]) - 1, len(data) - 1}, data} } func (g *graph) String() string { return strings.Join(g.data, "\n") } func (g *graph) isOutOfBounds(p point) bool { return p.x < 0 || p.y < 0 || p.y >= len(g.data) || p.x >= len(g.data[p.y]) } func (g *graph) valueAt(p point) rune { return rune(g.data[p.y][p.x]) } func (g *graph) addCorruption(coords []int) { g.data[coords[1]] = replaceAtIndex(g.data[coords[1]], '#', coords[0]) } func (g *graph) dijkstra(start, end point) ([]point, error) { queue := queue.New[point]() queue.Enqueue(start) visited := make(map[point]struct{}) costs := make(map[point]int) prev := make(map[point]point) for !queue.IsEmpty() { current := queue.Dequeue() // we found a shortest path if current == end { return g.generatePath(start, end, prev), nil } _, ok := visited[current] if ok { continue } visited[current] = struct{}{} for _, n := range neighbours(current) { if g.isOutOfBounds(n) { continue } if g.valueAt(n) == '#' { continue } _, ok := costs[n] if !ok { costs[n] = math.MaxInt } new_cost := costs[current] + 1 if new_cost < costs[n] { costs[n] = new_cost prev[n] = current queue.Enqueue(n) } } } return nil, errors.New("unable to find a shortest path") } func (g *graph) generatePath(start, end point, prev map[point]point) []point { path := []point{end} node := prev[end] for node != start { path = append(path, prev[node]) node = prev[node] } return path } func (g *graph) debug(path []point) string { temp := slices.Clone(g.data) for _, p := range path { if g.valueAt(p) == '#' { continue } temp[p.y] = replaceAtIndex(temp[p.y], 'O', p.x) } return strings.Join(temp, "\n") }