implemented day05... finally

This commit is contained in:
Christoph Stahl 2023-12-06 11:39:24 +01:00
parent 0f3bcc7aa7
commit 418a537df6

141
day05.py
View file

@ -1,6 +1,5 @@
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
from itertools import chain
import bisect import bisect
from typing import Optional from typing import Optional
@ -12,65 +11,42 @@ from aoc import Aoc2, AocSameParser
class Map: class Map:
def __init__(self, group: list[str]) -> None: def __init__(self, group: list[str]) -> None:
self.maps = [] self.maps: list[tuple[int, int, int]] = []
for line in group: for line in group:
start_dest, start_source, id_range = [ start_dest, start_source, id_range = [
int(d) for d in re.findall(r"\d+", line) int(d) for d in re.findall(r"\d+", line)
] ]
bisect.insort(self.maps, (start_source, start_dest - start_source, id_range)) bisect.insort(
self.maps,
(start_source, start_dest - start_source, start_source + id_range - 1),
)
zero_offsets = [] zero_offsets = []
start = 0 start = 0
for source, _, rnge in self.maps: for section_start, _, section_end in self.maps:
if source > start: if section_start > start:
zero_offsets.append((start, 0, source - start)) zero_offsets.append((start, 0, start - 1))
start = source + rnge start = section_end + 1
for m in zero_offsets: for m in zero_offsets:
bisect.insort(self.maps, m) bisect.insort(self.maps, m)
def find_bucket(self, x: int) -> Optional[int]: def find_bucket(self, x: int) -> Optional[int]:
for idx, (source, offset, rnge) in enumerate(self.maps): for idx, (source, _, end) in enumerate(self.maps):
if x >= source and x < source + rnge: if source <= x <= end:
return idx return idx
return None return None
def __getitem__(self, x: int) -> int: def __getitem__(self, x: int) -> int:
for (source, offset, rnge) in self.maps: for source, offset, end in self.maps:
if x >= source and x < source + rnge: if source <= x <= end:
return x + offset return x + offset
return x return x
# index = bisect.bisect_left(self.maps, (x+1,0,0)) - 1
# # index -= 1
# # if index < 0:
# # return x
#
# source, offset, id_range = self.maps[index]
# if x >= source + id_range:
# return x
# # if x < source + id_range:
# return x + offset
# return x
#
def merge(self, other: Map) -> None:
newmappings = []
for osource, ooffset, orange in other.maps:
for ssource, soffset, srange in self.maps:
if osource >= ssource and osource <= ssource + srange:
pass
def __repr__(self) -> str: def __repr__(self) -> str:
l = [] map_strs = []
for k, offset, x in self.maps: for k, offset, end in self.maps:
l.append(f"{k} - {k + x - 1}: {k+offset} - {k+ offset + x - 1}") map_strs.append(f"{k} - {end}: {k+offset} - {k+ offset + end}")
return f"Map({', '.join(l)})" return f"Map({', '.join(map_strs)})"
@dataclass @dataclass
@ -82,11 +58,10 @@ class Problem:
target = cat_from target = cat_from
output_value = value output_value = value
while target != cat_to: while target != cat_to:
new_target= list(filter(lambda fromto: fromto[0] == target, self.maps.keys()))[0][1] new_target = list(
# print(f"{target}({output_value})") filter(lambda fromto: fromto[0] == target, self.maps.keys())
)[0][1]
output_value = self.maps[(target, new_target)][output_value] output_value = self.maps[(target, new_target)][output_value]
# print(f"{new_target}({output_value})")
# self.cache[(old_value, target)] = (output_value, new_target)
target = new_target target = new_target
return output_value return output_value
@ -97,6 +72,7 @@ class Problem:
raise RuntimeError(f'Could not parse "{line}" as group header') raise RuntimeError(f'Could not parse "{line}" as group header')
return header_match["source"], header_match["dest"] return header_match["source"], header_match["dest"]
@staticmethod @staticmethod
def from_input(inpt: str) -> Problem: def from_input(inpt: str) -> Problem:
lines = inpt.splitlines() lines = inpt.splitlines()
@ -105,7 +81,7 @@ class Problem:
raise RuntimeError(f'Could not parse "{lines[0]}" as seed list') raise RuntimeError(f'Could not parse "{lines[0]}" as seed list')
seeds = [int(s) for s in seed_match.captures("seedid")] seeds = [int(s) for s in seed_match.captures("seedid")]
groups = [] groups: list[list[str]] = []
for line in lines[1:]: for line in lines[1:]:
if not line: if not line:
groups.append([]) groups.append([])
@ -123,62 +99,57 @@ class Day05(AocSameParser[Problem], Aoc2[Problem, Problem]):
return Problem.from_input(inpt) return Problem.from_input(inpt)
def part1(self, inpt: Problem) -> int: def part1(self, inpt: Problem) -> int:
# print([inpt.maps["seed", "soil"][x] for x in range(100)]) return min(inpt.convert("seed", "location", x) for x in inpt.seeds)
#
# print(inpt.maps["soil", "fertilizer"])
# print(inpt.maps["soil", "fertilizer"][14])
# print([inpt.maps["soil", "fertilizer"][x] for x in range(100)])
return (min([inpt.convert("seed", "location", x) for x in inpt.seeds]))
def part2(self, inpt: Problem) -> int: def part2(self, inpt: Problem) -> int:
order = [("seed", "soil"), ("soil", "fertilizer"), ("fertilizer", "water"), ("water", "light"), ("light", "temperature"), ("temperature", "humidity"), ("humidity", "location")] order = [
("seed", "soil"),
("soil", "fertilizer"),
("fertilizer", "water"),
("water", "light"),
("light", "temperature"),
("temperature", "humidity"),
("humidity", "location"),
]
seed_iter = iter(inpt.seeds) seed_iter = iter(inpt.seeds)
seeds = list(zip(seed_iter, seed_iter)) seeds = [
(start, start + rnge - 1)
for (start, rnge) in list(zip(seed_iter, seed_iter))
]
for translation in order: for translation in order:
print(translation)
print(seeds)
new_to_convert = [] new_to_convert = []
current_map = inpt.maps[translation] current_map = inpt.maps[translation]
# print(seeds[1])
# print(current_map)
for seed in seeds: for seed in seeds:
cur_range_start, cur_range_range = seed cur_start, cur_end = seed
cur_end = cur_range_start + cur_range_range index = current_map.find_bucket(cur_start)
index = current_map.find_bucket(cur_range_start)
if index is not None: if index is not None:
# print(current_map.maps[index]) section_start, section_offset, section_end = current_map.maps[index]
section_start, section_offset, section_range = current_map.maps[index] while cur_end > section_end:
section_end = section_start + section_range
if cur_end <= section_end:
new_to_convert.append((cur_range_start + section_offset, cur_range_range))
else:
# split
new_to_convert.append((cur_range_start + section_offset, section_end - cur_range_start))
if index == len(current_map.maps) - 1: if index == len(current_map.maps) - 1:
new_to_convert.append((section_end, cur_end - section_start)) new_to_convert.append((section_end + 1, cur_end))
else: break
next_start, next_offset, next_range = current_map.maps[index + 1] new_to_convert.append(
next_end = next_start + next_range (cur_start + section_offset, section_end + section_offset)
new_to_convert.append((section_end + next_offset, cur_end - section_start)) )
if cur_end > next_end: index += 1
print("Oh no") section_start, section_offset, section_end = current_map.maps[
index
]
cur_start = section_start
new_to_convert.append(
(cur_start + section_offset, cur_end + section_offset)
)
else: else:
new_to_convert.append(seed) new_to_convert.append(seed)
seeds = new_to_convert seeds = new_to_convert
return min(x[0] for x in seeds)
def main() -> None:
# return min(inpt.convert("seed", "location", x) for x in seeds)
def main():
day5 = Day05() day5 = Day05()
print(day5.run_example_2()) day5.run()
if __name__ == "__main__": if __name__ == "__main__":