Watch
1
0
Fork
You've already forked advent-of-code
0

2023 Day 18 Part 2

This commit is contained in:
Jeremy Kaplan 2023-12-17 23:04:27 -08:00
commit 7cb7dc5b7a

View file

@ -1,4 +1,5 @@
import std/algorithm import std/algorithm
import std/bitops
import std/deques import std/deques
import std/enumerate import std/enumerate
import std/heapqueue import std/heapqueue
@ -50,28 +51,14 @@ func parseDirection(s: string): Direction =
else: else:
raise newException(ValueError, s) raise newException(ValueError, s)
func cw(d: Direction): Direction =
case d:
of N: E
of E: S
of S: W
of W: N
func ccw(d: Direction): Direction =
case d:
of N: W
of W: S
of S: E
of E: N
type Instruction = tuple type Instruction = tuple
dir: Direction dir: Direction
steps: int steps: int
color: string color: int
func parseInstruction(line: string): Instruction = func parseInstruction(line: string): Instruction =
var dir: string var dir: string
if not scanf(line, "$+ $i ($+)$.", dir, result.steps, result.color): if not scanf(line, "$+ $i (#$h)$.", dir, result.steps, result.color):
raise newException(ValueError, line) raise newException(ValueError, line)
result.dir = dir.parseDirection result.dir = dir.parseDirection
@ -82,6 +69,8 @@ type Point = tuple
r: int r: int
c: int c: int
func `$`(p: Point): string = "(" & $p.r & ", " & $p.c & ")"
func move(p: Point, d: Direction, n: int): Point = func move(p: Point, d: Direction, n: int): Point =
case d: case d:
of N: (p.r - n, p.c) of N: (p.r - n, p.c)
@ -89,90 +78,65 @@ func move(p: Point, d: Direction, n: int): Point =
of W: (p.r, p.c - n) of W: (p.r, p.c - n)
of E: (p.r, p.c + n) of E: (p.r, p.c + n)
type Lagoon = object func fix(i: Instruction): Instruction =
grid: Table[Point, char] let steps = i.color shr 4
let dir = case i.color.masked 0xf
of 0: "R"
of 1: "D"
of 2: "L"
of 3: "U"
else: raise newException(ValueError, $i.color)
(dir.parseDirection, steps, i.color)
rlo, rhi: int func `//`(a, b: int): int =
clo, chi: int assert a mod b == 0
a.floorDiv(b)
func assign(l: var Lagoon, p: Point, sym: char) = func polygon(path: seq[Instruction]): seq[Point] =
l.grid[p] = sym var pos = (0, 0)
result.add pos
l.rlo = min(l.rlo, p.r) for i in path:
l.rhi = max(l.rhi, p.r) pos = pos.move(i.dir, i.steps)
l.clo = min(l.clo, p.c) result.add pos
l.chi = max(l.chi, p.c)
func dig(l: var Lagoon, p: Point) = proc area(path: seq[Point]): int =
l.assign(p, '#') for i in 0 ..< path.len - 1:
let a = path[i]
let b = path[(i+1) mod path.len]
func inBoundsPadding(l: Lagoon, p: Point): bool = let area = a.r * b.c - b.r * a.c
p.r in (l.rlo - 1) .. (l.rhi + 1) and p.c in (l.clo - 1) .. (l.chi + 1) result.inc area
# echo a, " ", b, " = ", area, " => ", result
func neighborsFill(l: Lagoon, p: Point): seq[Point] = func axisAligned(a, b: Point): bool =
for (dr, dc) in [ a.r == b.r or a.c == b.c
(-1, 0), # Up
(+1, 0), # Down
(0, -1), # Left
(0, +1), # Right
]:
let n = (p.r + dr, p.c + dc)
if l.inBoundsPadding(n):
result.add n
proc floodFill(l: var Lagoon, start: Point, sym: char) = func distance(a, b: Point): int =
var queue: Deque[Point] abs(b.r - a.r) + abs(b.c - a.c)
queue.addLast start proc distance(path: seq[Point]): int =
for i in 0 ..< path.len - 1:
let a = path[i]
let b = path[(i+1) mod path.len]
assert axisAligned(a, b)
while queue.len > 0: let len = distance(a, b)
let p = queue.popFirst result.inc len
if p in l.grid: continue func lagoonArea(ii: seq[Instruction]): int =
l.grid[p] = sym let path = polygon(ii)
(path.area // 2).abs + (path.distance // 2) + 1
for n in l.neighborsFill(p):
queue.addLast n
proc fill(l: var Lagoon) =
let empty = (l.rlo - 1, l.clo - 1)
l.floodFill(empty, '.')
for r in l.rlo .. l.rhi:
for c in l.clo .. l.chi:
let p = (r, c)
if p notin l.grid:
l.dig(p)
func execute(l: var Lagoon, instructions: seq[Instruction]) =
var pos: Point = (0, 0)
l.dig(pos)
for i in instructions:
for _ in 1 .. i.steps:
pos = pos.move(i.dir, 1)
l.dig(pos)
func render(l: Lagoon): string =
for r in l.rlo .. l.rhi:
for c in l.clo .. l.chi:
result &= l.grid.getOrDefault((r, c), ' ')
result &= '\n'
func countDug(l: Lagoon): int =
for r in l.rlo .. l.rhi:
for c in l.clo .. l.chi:
if l.grid[(r, c)] == '#':
result.inc
proc part1(input: string): int = proc part1(input: string): int =
let text = readFile(input) let text = readFile(input)
let instructions = parseInstructions(text) let instructions = parseInstructions(text)
lagoonArea(instructions)
var lagoon: Lagoon proc part2(input: string): int =
lagoon.execute(instructions) let text = readFile(input)
lagoon.fill let instructions = parseInstructions(text)
lagoon.countDug lagoonArea(instructions.map(fix))
################### ###################
@ -183,3 +147,5 @@ proc timed[T](f: () -> T): T =
echo timed(proc(): int = part1("input/test.txt")) echo timed(proc(): int = part1("input/test.txt"))
echo timed(proc(): int = part1("input/day18.txt")) echo timed(proc(): int = part1("input/day18.txt"))
echo timed(proc(): int = part2("input/test.txt"))
echo timed(proc(): int = part2("input/day18.txt"))