2023 day 16 in Nim
0.39s user 0.01s system 99% cpu 0.392 total
This commit is contained in:
parent
302c187e9f
commit
d84bb161b4
|
@ -0,0 +1,10 @@
|
|||
.|...\....
|
||||
|.-.\.....
|
||||
.....|-...
|
||||
........|.
|
||||
..........
|
||||
.........\
|
||||
..../.\\..
|
||||
.-.-/..|..
|
||||
.|....-|.\
|
||||
..//.|....
|
|
@ -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()
|
Loading…
Reference in New Issue