2023 Day 14 Part 2
This commit is contained in:
parent
43f5d46b9f
commit
4ee88bb358
1 changed files with 100 additions and 17 deletions
117
2023/day14.nim
117
2023/day14.nim
|
|
@ -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:
|
||||
if sym != 'O': continue
|
||||
result.inc (platform.height - p.r)
|
||||
for (r, row) in enumerate(platform.rows):
|
||||
for sym in row:
|
||||
if sym != 'O': continue
|
||||
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")
|
||||
|
|
|
|||
Loading…
Reference in a new issue