diff --git a/2023/day10.nim b/2023/day10.nim new file mode 100644 index 0000000..3ada644 --- /dev/null +++ b/2023/day10.nim @@ -0,0 +1,99 @@ +import std/algorithm +import std/deques +import std/enumerate +import std/math +import std/sequtils +import std/sets +import std/strscans +import std/strutils +import std/sugar +import std/tables + +proc dbg[T](v: T): T = (echo(v); v) + +type Point = tuple + r: int + c: int + +type Sketch = object + rows: int + cols: int + start: (int, int) + grid: Table[Point, char] + +func parseSketch(text: string): Sketch = + let lines = text.strip.splitLines() + result.rows = lines.len + result.cols = lines[0].len + + for (r, line) in enumerate(lines): + for (c, sym) in enumerate(line): + result.grid[(r, c)] = sym + + if sym == 'S': + result.start = (r, c) + +func pipeAt(s: Sketch, p: Point): char = + if p.r in 0 ..< s.rows and p.c in 0 ..< s.cols: + s.grid[p] + else: + '.' + +type Direction = enum + N + S + E + W + +proc hasConn(s: Sketch, p: Point, d: Direction): bool = + case s.pipeAt(p): + of 'S': true + of '.': false + of '|': d in [N, S] + of '-': d in [W, E] + of 'L': d in [N, E] + of 'J': d in [N, W] + of '7': d in [W, S] + of 'F': d in [E, S] + else: raise newException(ValueError, $s.grid[p]) + +func neighbors(s: Sketch, p: Point): seq[Point] = + for (dr, dc, pDir, nDir) in [ + (-1, 0, N, S), # Up N-S + (+1, 0, S, N), # Down S-N + (0, -1, W, E), # Left W-E + (0, +1, E, W), # Right E-W + ]: + let n = (p.r + dr, p.c + dc) + if s.hasConn(p, pDir) and s.hasConn(n, nDir): + result.add(n) + +type State = tuple + point: Point + distance: int + +proc reachable(s: Sketch): Table[Point, int] = + var queue: Deque[State] + var seen: HashSet[Point] + + queue.addLast (s.start, 0) + + while queue.len > 0: + let state = queue.popFirst + if state.point in seen: + continue + + result[state.point] = state.distance + seen.incl state.point + + for n in s.neighbors(state.point): + queue.addLast (n, state.distance + 1) + +proc part1(): int = + let text = readFile("input/day10.txt") + let sketch = parseSketch(text) + + for d in values(sketch.reachable): + result = max(result, d) + +echo part1()