advent-of-code/2023/python/day05.py

115 lines
2.7 KiB
Python
Raw Permalink Normal View History

2023-12-05 06:56:53 +00:00
import shared
from pprint import pprint
from dataclasses import dataclass
2023-12-08 18:42:42 +00:00
2023-12-05 06:56:53 +00:00
@dataclass
class Mapping:
dst: int
src: int
2023-12-08 18:42:42 +00:00
ran: int # RANGE
2023-12-05 06:56:53 +00:00
maps_parts = [
"seed-to-soil",
"soil-to-fertilizer",
"fertilizer-to-water",
"water-to-light",
"light-to-temperature",
"temperature-to-humidity",
"humidity-to-location",
]
2023-12-08 18:42:42 +00:00
group = lambda l, s: list(zip(*(iter(l),) * s))
2023-12-05 06:56:53 +00:00
def line_ints(s):
return [int(x) for x in s.split() if s]
2023-12-08 18:42:42 +00:00
2023-12-05 06:56:53 +00:00
def parse_line(line):
return Mapping(*line)
2023-12-08 18:42:42 +00:00
2023-12-05 06:56:53 +00:00
class Mapper:
def __init__(self, rows):
self.parse(rows)
def parse(self, rows):
seeds = rows.pop(0)
2023-12-08 18:42:42 +00:00
rows.pop(0) # Discard empty to start at a clean slate
2023-12-05 06:56:53 +00:00
seeds = line_ints(seeds.split(":")[1])
maps = {}
current_map = None
for row in rows:
if ":" in row:
current_map = row[:-5]
maps[current_map] = []
continue
if row == "":
continue
maps[current_map].append(parse_line(line_ints(row)))
self.seeds = seeds
self.maps = maps
def calculate(self, step, source):
possibilities = self.maps[step]
for p in possibilities:
if source < p.src:
2023-12-08 18:42:42 +00:00
# print(f"\t{source} less than {p.src}")
2023-12-05 06:56:53 +00:00
continue
2023-12-08 18:42:42 +00:00
if source > p.src + p.ran:
# print(f"\t{source} greater than {p.src}+{p.ran}={p.src+p.ran}")
2023-12-05 06:56:53 +00:00
continue
2023-12-08 18:42:42 +00:00
# print(f"\t{source} in range")
# print(f"\t{source} is {p.dst + (source - p.src)}")
2023-12-05 06:56:53 +00:00
return p.dst + (source - p.src)
break
return source
2023-12-08 18:42:42 +00:00
2023-12-05 06:56:53 +00:00
# @shared.profile
def part1(rows):
mapper = Mapper(rows[:])
locations = []
2023-12-08 18:42:42 +00:00
2023-12-05 06:56:53 +00:00
for seed in mapper.seeds:
next = seed
for part in maps_parts:
_part = next
next = mapper.calculate(part, next)
locations.append(next)
print(locations)
print(min(locations))
# @shared.profile
def part2(rows):
mapper = Mapper(rows[:])
locations = []
seeds = group(mapper.seeds, 2)
for seed_group in seeds:
2023-12-08 18:42:42 +00:00
for seed in range(seed_group[0], seed_group[0] + seed_group[1]):
2023-12-05 06:56:53 +00:00
next = seed
for part in maps_parts:
_part = next
next = mapper.calculate(part, next)
locations.append(next)
print(min(locations))
def main():
rows = [row for row in shared.load_rows(5)]
with shared.elapsed_timer() as elapsed:
part1(rows)
print("🕒", elapsed())
with shared.elapsed_timer() as elapsed:
part2(rows)
print("🕒", elapsed())
if __name__ == "__main__":
main()