2023 day 16 in Nim

0.39s user 0.01s system 99% cpu 0.392 total
This commit is contained in:
aru 2023-12-19 23:45:14 +01:00
parent 302c187e9f
commit d84bb161b4
2 changed files with 111 additions and 0 deletions

10
2023/data/16/example Normal file
View File

@ -0,0 +1,10 @@
.|...\....
|.-.\.....
.....|-...
........|.
..........
.........\
..../.\\..
.-.-/..|..
.|....-|.\
..//.|....

101
2023/nim/day16.nim Normal file
View File

@ -0,0 +1,101 @@
import std/strutils
import std/deques
import std/sets
import std/sequtils
type Point = tuple
x: int
y: int
type Movement = tuple
start: Point
direction: Point
type Area* = ref object
data: seq[string]
x, y: int
proc isWithin(p: Point, b: Area): bool =
p.x >= 0 and p.y >= 0 and p.x < b.x and p.y < b.y
proc charAt(a: Area, p: Point): char =
a.data[p.x][p.y]
proc add(p1: Point, p2: Point): Point =
(p1.x + p2.x, p1.y + p2.y)
proc rotateLeft(d: Point): Point =
if d.x > 0:
return (0, -1)
elif d.x < 0:
return (0, 1)
elif d.y > 0:
return (-1, 0)
elif d.y < 0:
return (1, 0)
proc rotateRight(d: Point): Point =
let p = d.rotateLeft
(-p.x, -p.y)
iterator nextMovements(c: char, m: Movement): Movement =
if c == '/':
let dir = m.direction.rotateLeft
let next = m.start.add(dir)
yield (next, dir)
elif c == '\\':
let dir = m.direction.rotateRight
let next = m.start.add(dir)
yield (next, dir)
elif (c == '|' and m.direction.x == 0) or (c == '-' and m.direction.y == 0):
let dir = m.direction.rotateLeft
let next = m.start.add(dir)
yield (next, dir)
let dir2 = m.direction.rotateRight
let next2 = m.start.add(dir2)
yield (next2, dir2)
else:
yield (m.start.add(m.direction), m.direction)
proc traceBeams(a: Area, start: Movement): int =
var energised: HashSet[Point] = initHashSet[Point]()
var visited: HashSet[(Point, Point)] = initHashSet[(Point, Point)]()
var queue: Deque[Movement] = [start].toDeque
while len(queue) > 0:
let entry = queue.popLast
if entry.start.isWithin(a):
energised.incl(entry.start)
for m in nextMovements(a.charAt(entry.start), entry):
if m.start.isWithin(a) and not visited.contains(m):
visited.incl(m)
queue.addLast(m)
return len(energised)
proc part1(a: Area): int =
traceBeams(a, ((0, 0), (0, 1)))
proc part2(a: Area): int =
var starts = newSeq[Movement]()
for y in 0..a.y - 1:
starts.add(((0, y), (1, 0)))
starts.add(((a.x - 1, y), (-1, 0)))
for x in 0..a.x - 1:
starts.add(((x, 0), (0, 1)))
starts.add(((x, a.y - 1), (0, -1)))
starts.mapIt(traceBeams(a, it)).max
proc main =
let s = readAll(stdin)
var lines = splitLines(s)
var a = Area(data: lines, x: (len lines) - 1, y: len lines[0])
let p1 = part1(a)
let p2 = part2(a)
echo "Part 1: $1" % [$p1]
echo "Part 2: $1" % [$p2]
when isMainModule:
main()