This commit is contained in:
Christoph Stahl 2023-12-14 01:55:54 +01:00
parent ef470926c0
commit d606451b8c
2 changed files with 35 additions and 119 deletions

View file

@ -108,6 +108,8 @@ class Aoc2(ABC, Generic[T1, T2]):
return str(self.part2(self.parseinput2(inpt)))
def run(self) -> None:
print(f"Running Day {self._day:02d}")
s_time = default_timer()
print("Example:\t", end="")
print(f"{self.run_example_1()}\t", end="")
print(f"{self.run_example_2()}")
@ -115,6 +117,8 @@ class Aoc2(ABC, Generic[T1, T2]):
print("Real input:\t", end="")
print(f"{self.run_1()}\t", end="")
print(f"{self.run_2()}")
e_time = default_timer()
print(f"Time: {e_time-s_time}")
class Aoc(Generic[T1], Aoc2[T1, T1]):
@ -188,11 +192,7 @@ def run_latest() -> None:
if file.name.endswith(".py") and file.name.startswith("day")
]
day = days[-1]
print(f"Running {day.__name__}")
s_time = default_timer()
day.main()
e_time = default_timer()
print(f"Time: {e_time-s_time}")
def new() -> None:
@ -251,11 +251,7 @@ def main() -> None:
]
b_time = default_timer()
for day in days:
print(f"Running {day.__name__}")
s_time = default_timer()
day.main()
e_time = default_timer()
print(f"Time: {e_time-s_time}")
print()
f_time = default_timer()
print(f"Overall time: {f_time - b_time}")

View file

@ -1,151 +1,71 @@
from __future__ import annotations
from typing import TypeAlias
from collections import defaultdict
from dataclasses import dataclass
from itertools import groupby
from collections import deque
from typing import TypeAlias
from .aoc import Aoc2, AocParseLines
from .aoc import Aoc2, AocParseLines, AocSameImplementation
@dataclass
@dataclass(frozen=True)
class Line:
springs: str
spring_groups: deque[tuple[int, str]]
groups: list[int]
groups: tuple[int, ...]
@classmethod
def from_str(cls, inpt: str) -> Line:
def from_str(cls, inpt: str, multi: int) -> Line:
springs, groups_str = inpt.split(" ")
groups = [int(d) for d in groups_str.split(",")]
springs = "?".join([springs] * multi)
groups = tuple(int(d) for d in groups_str.split(",")) * multi
springs_group = deque((len(list(d)), i) for i, d in groupby(springs))
return Line("." + springs + ".", springs_group, groups)
@classmethod
def from_str2(cls, inpt: str) -> Line:
springs, groups_str = inpt.split(" ")
springs = "?".join([springs] * 5)
groups = [int(d) for d in groups_str.split(",")]
groups = groups + groups + groups + groups + groups
springs_group = deque((len(list(d)), i) for i, d in groupby(springs))
return Line("." + springs + ".", springs_group, groups)
return Line("." + springs + ".", groups)
P1: TypeAlias = list[Line]
P2: TypeAlias = list[Line]
class Day12(AocParseLines[Line, Line], Aoc2[P1, P2]):
class Day12(AocSameImplementation[P1], AocParseLines[Line, Line], Aoc2[P1, P2]):
def parseline1(self, inpt: str) -> Line:
return Line.from_str(inpt)
return Line.from_str(inpt, 1)
def parseline2(self, inpt: str) -> Line:
return Line.from_str2(inpt)
return Line.from_str(inpt, 5)
@staticmethod
def fits(line: str, startpos: int, length: int) -> bool:
if startpos + length >= len(line):
return False
starter = line[startpos - 1]
segment = line[startpos : startpos + length]
stopper = line[startpos + length]
return starter != "#" and stopper != "#" and ("." not in segment)
return "#" not in (starter, stopper) and "." not in segment
def part1(self, inpt: P1) -> int:
def part(self, inpt: P1) -> int:
accum = 0
# inpt = inpt[:1]
# print(inpt)
for line in inpt:
belegungen = [[0]]
ends = {0: 1}
for i, group in enumerate(line.groups):
# print(f"{belegungen=}")
next_belegungen = []
for belegung in belegungen:
last_end = belegung[-1]
# print(f"{last_start=}, {last_end=}, {group=}, {len(line.springs)=}")
# try:
# first_hash = line.springs[last_end:].index("#") + 1
# # print("First hash", first_hash)
# except ValueError:
# first_hash = len(line.springs) - 1
for startvalue in range(last_end + 1, len(line.springs)):
# print(startvalue)
if "#" in line.springs[last_end:startvalue]:
continue
fits = self.fits(line.springs, startvalue, group)
next_ends: dict[int, int] = defaultdict(lambda: 0)
for end, amount in ends.items():
for startvalue in range(end + 1, len(line.springs) - group):
if not (
"#" in line.springs[end:startvalue]
or (
i == len(line.groups) - 1
and "#" in line.springs[startvalue + group :]
)
or not Day12.fits(line.springs, startvalue, group)
):
next_ends[startvalue + group] += amount
if i == len(line.groups) - 1:
if "#" in line.springs[startvalue + group :]:
continue
if fits:
# print(f"Y {i=}, {startvalue=}, {group=}")
next_belegungen.append(belegung + [startvalue + group])
# else:
# print(f"N {i=}, {startvalue=}, {group=}")
belegungen = next_belegungen
# print(belegungen)
# print(line.springs[1:-1], line.groups, len(belegungen))
# if len(belegungen) == 1:
# print(
# f"{line.springs=}, {line.groups=}, {[line.springs[x] for x in belegungen[0]]}"
# )
for belegung in belegungen:
last_belegung = belegung[-1]
if "#" in line.springs[last_belegung:]:
print(line.springs, line.groups)
if len(set((tuple(x) for x in belegungen))) != len(belegungen):
print("X")
# print(line.springs, line.groups)
for belegung in belegungen:
self.check_belegung(line, belegung)
accum += len(belegungen)
# print(len(belegungen))
# print(belegungen)
# print(belegungen)
print(accum)
ends = next_ends
accum += sum(ends.values())
return accum
def check_belegung(self, line, belegung):
if "#" in [line.springs[x] for x in belegung]:
print(f"Wrong # in {line=}")
if len(belegung) != 1 + len(line.groups):
print(f"Groups Wrong in {line=}")
for ends, lengths in zip(belegung[1:], line.groups):
b = line.springs[ends - lengths : ends]
if "." in b:
print("{line=}")
last_end = 0
bstr = "."
for ends, lengths in zip(belegung[1:], line.groups):
beginning = ends - lengths
bstr += "." * (beginning - len(bstr))
bstr += "#" * lengths
if (line.springs[beginning - 1] == "#") or line.springs[ends] == "#":
print("X")
if beginning - last_end < 1:
print("XXX")
last_end = ends
# print(bstr)
def part2(self, inpt: P2) -> int:
for line in inpt:
print(line)
return self.part1(inpt)
def main() -> None:
aoc = Day12(2023, 12, example_code_nr1=1, example_code_nr2=1)
aoc.run_example_2()
aoc.run()
if __name__ == "__main__":