package one import ( "slices" "strings" "github.com/onyx-and-iris/aoc2024/day-20/internal/point" "github.com/elliotchance/orderedmap/v3" ) type graph struct { start, end point.Point data []string } func newGraph(data []string) *graph { return &graph{data: data} } func (g *graph) String() string { return strings.Join(g.data, "\n") } func (g *graph) isOutOfBounds(p point.Point) bool { return p.X < 1 || p.Y < 1 || p.Y >= len(g.data)-1 || p.X >= len(g.data[p.Y])-1 } func (g *graph) valueAt(p point.Point) rune { return rune(g.data[p.Y][p.X]) } func (g *graph) isValidCheatPosition(p point.Point) bool { allowed := []rune{'.', 'S', 'E'} ns := neighbours(p) return slices.Contains(allowed, g.valueAt(ns[N])) && slices.Contains(allowed, g.valueAt(ns[S])) || slices.Contains(allowed, g.valueAt(ns[W])) && slices.Contains(allowed, g.valueAt(ns[E])) } func (g *graph) getConnectingPoint(dir direction, p point.Point) point.Point { ns := neighbours(p) return ns[dir] } func (g *graph) set(p point.Point, value rune) { g.data[p.Y] = replaceAtIndex(g.data[p.Y], value, p.X) } func (g *graph) path( current point.Point, om *orderedmap.OrderedMap[point.Point, int], dist int, ) *orderedmap.OrderedMap[point.Point, int] { if current == g.end { return om } var n point.Point for _, n = range neighbours(current) { _, ok := om.Get(n) if ok { continue } if g.valueAt(n) == '.' || g.valueAt(n) == 'E' { break } } om.Set(n, dist) return g.path(n, om, dist+1) } func (g *graph) debug(path *orderedmap.OrderedMap[point.Point, int]) string { temp := slices.Clone(g.data) for n := range path.Keys() { if g.valueAt(n) == cheatChar { continue } temp[n.Y] = replaceAtIndex(temp[n.Y], 'O', n.X) } return strings.Join(temp, "\n") }