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
|
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]
|
var current: seq[T]
|
||||||
for elt in v:
|
for elt in v:
|
||||||
if pred(elt):
|
if pred(elt):
|
||||||
|
|
@ -41,8 +41,6 @@ type Platform = object
|
||||||
height: int
|
height: int
|
||||||
width: int
|
width: int
|
||||||
|
|
||||||
grid: Table[Point, char]
|
|
||||||
|
|
||||||
rows: seq[seq[char]]
|
rows: seq[seq[char]]
|
||||||
cols: seq[seq[char]]
|
cols: seq[seq[char]]
|
||||||
|
|
||||||
|
|
@ -59,10 +57,12 @@ func parsePlatform(text: string): Platform =
|
||||||
|
|
||||||
for (r, line) in enumerate(lines):
|
for (r, line) in enumerate(lines):
|
||||||
for (c, sym) in enumerate(line):
|
for (c, sym) in enumerate(line):
|
||||||
result.grid[(r, c)] = sym
|
|
||||||
result.rows[r] &= @[sym]
|
result.rows[r] &= @[sym]
|
||||||
result.cols[c] &= @[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 =
|
proc fromCols(cols: seq[seq[char]]): Platform =
|
||||||
result.cols = cols
|
result.cols = cols
|
||||||
result.width = cols.len
|
result.width = cols.len
|
||||||
|
|
@ -73,36 +73,119 @@ proc fromCols(cols: seq[seq[char]]): Platform =
|
||||||
|
|
||||||
for (c, col) in enumerate(cols):
|
for (c, col) in enumerate(cols):
|
||||||
for (r, sym) in enumerate(col):
|
for (r, sym) in enumerate(col):
|
||||||
result.grid[(r, c)] = sym
|
|
||||||
result.rows[r] &= @[sym]
|
result.rows[r] &= @[sym]
|
||||||
|
|
||||||
func render(p: Platform): string =
|
proc fromRows(rows: seq[seq[char]]): Platform =
|
||||||
p.rows.mapIt(it.mapIt($it).join("")).join("\n")
|
result.rows = rows
|
||||||
|
result.height = rows.len
|
||||||
|
result.width = rows[0].len
|
||||||
|
|
||||||
proc tiltNorth(col: seq[char]): seq[char] =
|
for c in 0 ..< result.width:
|
||||||
let parts = col.split(func (sym: char): bool = sym == '#')
|
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]]
|
var rolled: seq[seq[char]]
|
||||||
for part in parts:
|
for part in parts:
|
||||||
rolled.add part.sorted(Descending)
|
rolled.add part.sorted(order)
|
||||||
result = rolled.join('#')
|
result = rolled.join('#')
|
||||||
|
|
||||||
proc tiltNorth(p: Platform): Platform =
|
func tiltCols(p: Platform, order: SortOrder): Platform =
|
||||||
var cols: seq[seq[char]]
|
var cols: seq[seq[char]]
|
||||||
for col in p.cols:
|
for col in p.cols:
|
||||||
cols.add col.tiltNorth
|
cols.add col.tilt(order)
|
||||||
fromCols(cols)
|
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 =
|
proc loadNorth(platform: Platform): int =
|
||||||
for (p, sym) in platform.grid.pairs:
|
for (r, row) in enumerate(platform.rows):
|
||||||
if sym != 'O': continue
|
for sym in row:
|
||||||
result.inc (platform.height - p.r)
|
if sym != 'O': continue
|
||||||
|
result.inc (platform.height - r)
|
||||||
|
|
||||||
proc part1(input: string): int =
|
proc part1(input: string): int =
|
||||||
let text = readFile(input)
|
let text = readFile(input)
|
||||||
let platform = parsePlatform(text)
|
let platform = parsePlatform(text)
|
||||||
platform.tiltNorth.loadNorth
|
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/test.txt")
|
||||||
echo part1("input/day14.txt")
|
echo part1("input/day14.txt")
|
||||||
# echo part2("input/test.txt")
|
echo part2("input/test.txt")
|
||||||
# echo part2("input/day14.txt")
|
echo part2("input/day14.txt")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue