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

2023 Day 14 Part 2

This commit is contained in:
Jeremy Kaplan 2023-12-13 22:15:35 -08:00
commit 4ee88bb358

View file

@ -15,7 +15,7 @@ proc dbg[T](v: T): T = (echo(v); v)
func empty[T](v: seq[T]): bool = v.len == 0
proc split[T](v: seq[T], pred: proc(elt: T): bool): seq[seq[T]] =
proc split[T](v: seq[T], pred: proc(elt: T): bool {.noSideEffect.}): seq[seq[T]] =
var current: seq[T]
for elt in v:
if pred(elt):
@ -41,8 +41,6 @@ type Platform = object
height: int
width: int
grid: Table[Point, char]
rows: seq[seq[char]]
cols: seq[seq[char]]
@ -59,10 +57,12 @@ func parsePlatform(text: string): Platform =
for (r, line) in enumerate(lines):
for (c, sym) in enumerate(line):
result.grid[(r, c)] = sym
result.rows[r] &= @[sym]
result.cols[c] &= @[sym]
func render(p: Platform): string =
p.rows.mapIt(it.mapIt($it).join("")).join("\n")
proc fromCols(cols: seq[seq[char]]): Platform =
result.cols = cols
result.width = cols.len
@ -73,36 +73,119 @@ proc fromCols(cols: seq[seq[char]]): Platform =
for (c, col) in enumerate(cols):
for (r, sym) in enumerate(col):
result.grid[(r, c)] = sym
result.rows[r] &= @[sym]
func render(p: Platform): string =
p.rows.mapIt(it.mapIt($it).join("")).join("\n")
proc fromRows(rows: seq[seq[char]]): Platform =
result.rows = rows
result.height = rows.len
result.width = rows[0].len
proc tiltNorth(col: seq[char]): seq[char] =
let parts = col.split(func (sym: char): bool = sym == '#')
for c in 0 ..< result.width:
result.cols.add @[]
for (r, row) in enumerate(rows):
for (c, sym) in enumerate(row):
result.cols[c] &= @[sym]
func tilt(rocks: seq[char], order: SortOrder): seq[char] =
let parts = rocks.split(func (sym: char): bool = sym == '#')
var rolled: seq[seq[char]]
for part in parts:
rolled.add part.sorted(Descending)
rolled.add part.sorted(order)
result = rolled.join('#')
proc tiltNorth(p: Platform): Platform =
func tiltCols(p: Platform, order: SortOrder): Platform =
var cols: seq[seq[char]]
for col in p.cols:
cols.add col.tiltNorth
cols.add col.tilt(order)
fromCols(cols)
func tiltRows(p: Platform, order: SortOrder): Platform =
var rows: seq[seq[char]]
for row in p.rows:
rows.add row.tilt(order)
fromRows(rows)
func tiltNorth(p: Platform): Platform =
p.tiltCols(Descending)
func tiltSouth(p: Platform): Platform =
p.tiltCols(Ascending)
func tiltWest(p: Platform): Platform =
p.tiltRows(Descending)
func tiltEast(p: Platform): Platform =
p.tiltRows(Ascending)
type Direction = enum
N
S
E
W
func tilt(p: Platform, d: Direction): Platform =
case d:
of N: p.tiltNorth
of S: p.tiltSouth
of E: p.tiltEast
of W: p.tiltWest
proc loadNorth(platform: Platform): int =
for (p, sym) in platform.grid.pairs:
for (r, row) in enumerate(platform.rows):
for sym in row:
if sym != 'O': continue
result.inc (platform.height - p.r)
result.inc (platform.height - r)
proc part1(input: string): int =
let text = readFile(input)
let platform = parsePlatform(text)
platform.tiltNorth.loadNorth
func cycle(p: Platform): Platform =
p.tiltNorth.tiltWest.tiltSouth.tiltEast
type Loop = tuple
start: int
stop: int
length: int
proc findLoop(p: Platform): (Loop, Platform) =
let cycle = @[N, W, S, E]
var seen: Table[Platform, int]
seen[p] = 0
var p = p
var i = 0
while true:
inc i
for dir in cycle:
p = p.tilt(dir)
if p in seen:
let start = seen[p]
return ((start, i, i - start), p)
seen[p] = i
proc part2(input: string): int =
let text = readFile(input)
let platform = parsePlatform(text)
let cycles = 1_000_000_000
let (loop, state) = platform.findLoop
let repeats = (cycles - loop.stop).floorDiv(loop.length)
let timeSkip = loop.stop + repeats * loop.length
let remaining = cycles - timeSkip
var p = state
for _ in 0 ..< remaining:
p = p.cycle
p.loadNorth
echo part1("input/test.txt")
echo part1("input/day14.txt")
# echo part2("input/test.txt")
# echo part2("input/day14.txt")
echo part2("input/test.txt")
echo part2("input/day14.txt")