115 lines
2.7 KiB
Python
115 lines
2.7 KiB
Python
import shared
|
|
from pprint import pprint
|
|
from dataclasses import dataclass
|
|
|
|
|
|
@dataclass
|
|
class Mapping:
|
|
dst: int
|
|
src: int
|
|
ran: int # RANGE
|
|
|
|
|
|
maps_parts = [
|
|
"seed-to-soil",
|
|
"soil-to-fertilizer",
|
|
"fertilizer-to-water",
|
|
"water-to-light",
|
|
"light-to-temperature",
|
|
"temperature-to-humidity",
|
|
"humidity-to-location",
|
|
]
|
|
|
|
group = lambda l, s: list(zip(*(iter(l),) * s))
|
|
|
|
|
|
def line_ints(s):
|
|
return [int(x) for x in s.split() if s]
|
|
|
|
|
|
def parse_line(line):
|
|
return Mapping(*line)
|
|
|
|
|
|
class Mapper:
|
|
def __init__(self, rows):
|
|
self.parse(rows)
|
|
|
|
def parse(self, rows):
|
|
seeds = rows.pop(0)
|
|
rows.pop(0) # Discard empty to start at a clean slate
|
|
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:
|
|
# print(f"\t{source} less than {p.src}")
|
|
continue
|
|
if source > p.src + p.ran:
|
|
# print(f"\t{source} greater than {p.src}+{p.ran}={p.src+p.ran}")
|
|
continue
|
|
# print(f"\t{source} in range")
|
|
# print(f"\t{source} is {p.dst + (source - p.src)}")
|
|
return p.dst + (source - p.src)
|
|
break
|
|
return source
|
|
|
|
|
|
# @shared.profile
|
|
def part1(rows):
|
|
mapper = Mapper(rows[:])
|
|
locations = []
|
|
|
|
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:
|
|
for seed in range(seed_group[0], seed_group[0] + seed_group[1]):
|
|
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()
|