2023 Day 5 Part 2
This commit is contained in:
parent
2cebadb5d0
commit
422a378ec0
1 changed files with 88 additions and 3 deletions
|
|
@ -44,8 +44,8 @@ func lookup(m: Map, src: int): int =
|
|||
return remap.lookup(src)
|
||||
src
|
||||
|
||||
type Almanac = tuple
|
||||
seeds: HashSet[int]
|
||||
type Almanac = object
|
||||
seeds: seq[int]
|
||||
mapsBySrc: Table[string, Map]
|
||||
mapsByDst: Table[string, Map]
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ func parseAlmanac(s: string): Almanac =
|
|||
raise newException(ValueError, sections[0])
|
||||
|
||||
for num in seeds.strip.splitWhitespace:
|
||||
result.seeds.incl num.parseInt
|
||||
result.seeds.add num.parseInt
|
||||
|
||||
for section in sections[1..^1]:
|
||||
let map = parseMap(section)
|
||||
|
|
@ -85,4 +85,89 @@ proc part1(): int =
|
|||
|
||||
locations.min
|
||||
|
||||
type Range = tuple
|
||||
lo: int
|
||||
hi: int
|
||||
|
||||
func newRange(start: int, length: int): Range =
|
||||
(start, start + length - 1)
|
||||
|
||||
func empty(r: Range): bool =
|
||||
r.lo > r.hi
|
||||
|
||||
func intersect(a: Range, b: Range): Range =
|
||||
(max(a.lo, b.lo), min(a.hi, b.hi))
|
||||
|
||||
proc lookup(r: Remap, src: Range): Range =
|
||||
let delta = r.dst_start - r.src_start
|
||||
(src.lo + delta, src.hi + delta)
|
||||
|
||||
proc lookup(m: Map, src: Range): seq[Range] =
|
||||
var unmapped = @[src]
|
||||
|
||||
for remap in m.remaps:
|
||||
var still_unmapped: seq[Range]
|
||||
for src in unmapped:
|
||||
let rr = newRange(remap.src_start, remap.length)
|
||||
if src.intersect(rr).empty:
|
||||
still_unmapped.add src
|
||||
continue
|
||||
|
||||
let dn = src.lo
|
||||
let lo = max(src.lo, rr.lo)
|
||||
let hi = min(src.hi, rr.hi)
|
||||
let up = src.hi
|
||||
|
||||
let prefix = (dn, lo - 1)
|
||||
let inside = (lo, hi)
|
||||
let suffix = (hi + 1, up)
|
||||
|
||||
if not prefix.empty:
|
||||
still_unmapped.add prefix
|
||||
|
||||
if not suffix.empty:
|
||||
still_unmapped.add suffix
|
||||
|
||||
if not inside.empty:
|
||||
result.add remap.lookup(inside)
|
||||
|
||||
unmapped = still_unmapped
|
||||
|
||||
for src in unmapped:
|
||||
result.add src
|
||||
|
||||
proc lookup(m: Map, srcs: seq[Range]): seq[Range] =
|
||||
for src in srcs:
|
||||
result.add m.lookup(src)
|
||||
|
||||
proc lookup(a: Almanac, dst: string, seeds: seq[Range]): seq[Range] =
|
||||
var map = a.mapsBySrc["seed"]
|
||||
var src = seeds
|
||||
|
||||
while true:
|
||||
src = map.lookup(src)
|
||||
if map.dst == dst:
|
||||
return src
|
||||
|
||||
map = a.mapsBySrc[map.dst]
|
||||
|
||||
proc part2(): int =
|
||||
let text = readFile("input/day05.txt")
|
||||
let almanac = parseAlmanac(text)
|
||||
|
||||
var ranges: seq[Range]
|
||||
|
||||
for i in 0 ..< floorDiv(almanac.seeds.len, 2):
|
||||
let start = almanac.seeds[2*i]
|
||||
let len = almanac.seeds[2*i + 1]
|
||||
ranges.add newRange(start, len)
|
||||
|
||||
let locations = collect(newSeq):
|
||||
for locs in almanac.lookup("location", ranges):
|
||||
if not locs.empty:
|
||||
locs.lo
|
||||
|
||||
locations.min
|
||||
|
||||
echo part1()
|
||||
echo part2()
|
||||
|
|
|
|||
Loading…
Reference in a new issue