Speed improvements and time measurement
This commit is contained in:
parent
0f233f8324
commit
8197d2a3df
3 changed files with 54 additions and 41 deletions
10
aoc/aoc.py
10
aoc/aoc.py
|
@ -4,6 +4,7 @@ from typing import Any, Generic, Protocol, TypeVar
|
|||
from urllib.request import Request, urlopen
|
||||
from html.parser import HTMLParser
|
||||
from importlib import import_module
|
||||
from timeit import default_timer
|
||||
|
||||
T1 = TypeVar("T1")
|
||||
T2 = TypeVar("T2")
|
||||
|
@ -187,7 +188,10 @@ def run_latest() -> None:
|
|||
]
|
||||
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 main() -> None:
|
||||
|
@ -196,10 +200,16 @@ def main() -> None:
|
|||
for file in sorted(Path("aoc").iterdir())
|
||||
if file.name.endswith(".py") and file.name.startswith("day")
|
||||
]
|
||||
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}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
20
aoc/day08.py
20
aoc/day08.py
|
@ -44,21 +44,19 @@ class Day08(AocSameParser[Map], Aoc2[Map, Map]):
|
|||
|
||||
def part2(self, inpt: Map) -> int:
|
||||
current = [node for node in inpt.rules.keys() if node.endswith("A")]
|
||||
steps_to_z: list[list[int]] = [[] for _ in current]
|
||||
loops: list[Optional[tuple[int, int]]] = [None for _ in current]
|
||||
|
||||
for steps, direction in enumerate(itertools.cycle(inpt.directions)):
|
||||
steps_to_z = [0] * len(current)
|
||||
for direction in itertools.cycle(inpt.directions):
|
||||
dirty = False
|
||||
for n, node in enumerate(current):
|
||||
if node.endswith("Z"):
|
||||
steps_to_z[n].append(steps)
|
||||
loops[n] = self.find_loop(steps_to_z[n])
|
||||
|
||||
if not any(loop is None for loop in loops):
|
||||
continue
|
||||
dirty = True
|
||||
steps_to_z[n] += 1
|
||||
current[n] = inpt.rules[node][direction]
|
||||
if not dirty:
|
||||
break
|
||||
current = [inpt.rules[node][direction] for node in current]
|
||||
|
||||
# Turns out, each path directly loops :/
|
||||
return math.lcm(*(loop[0] for loop in loops if loop is not None))
|
||||
return math.lcm(*steps_to_z)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
|
65
aoc/day11.py
65
aoc/day11.py
|
@ -1,8 +1,9 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from array import array
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Callable, Iterable
|
||||
from dataclasses import dataclass
|
||||
from itertools import accumulate, combinations
|
||||
|
||||
from .aoc import Aoc2, AocSameParser
|
||||
|
||||
|
@ -64,43 +65,50 @@ class Matrix:
|
|||
return "\n".join((x.tounicode() for x in self.iter_rows()))
|
||||
|
||||
def finditer(self, element: str) -> Iterable[Position]:
|
||||
for y, line in enumerate(self.iter_rows()):
|
||||
for x, char in enumerate(line):
|
||||
if char == element:
|
||||
yield Position(x, y)
|
||||
return (
|
||||
Position(x, y)
|
||||
for y, line in enumerate(self.iter_rows())
|
||||
for x, char in enumerate(line)
|
||||
if char == element
|
||||
)
|
||||
|
||||
def filter_row_ids(self, predicate: Callable[[array[str]], bool]) -> Iterable[int]:
|
||||
return (y for y, row in enumerate(self.iter_rows()) if predicate(row))
|
||||
|
||||
def filter_col_ids(self, predicate: Callable[[array[str]], bool]) -> Iterable[int]:
|
||||
return (x for x, col in enumerate(self.iter_cols()) if predicate(col))
|
||||
|
||||
|
||||
@dataclass
|
||||
class Map:
|
||||
map: Matrix
|
||||
galaxies: list[Position]
|
||||
adjusted_galaxies: list[Position]
|
||||
large_adjusted_galaxies: list[Position]
|
||||
galaxies: Iterable[tuple[Position, Position]]
|
||||
|
||||
@classmethod
|
||||
def from_input(cls, inpt: str) -> Map:
|
||||
matrix = Matrix(inpt)
|
||||
missing_xs = array(
|
||||
"I",
|
||||
accumulate([1 if col.count("#") == 0 else 0 for col in matrix.iter_cols()]),
|
||||
)
|
||||
|
||||
galaxies = list(matrix.finditer("#"))
|
||||
missing_ys = [
|
||||
y for y, row in enumerate(matrix.iter_rows()) if row.count("#") == 0
|
||||
]
|
||||
missing_xs = [
|
||||
x for x, col in enumerate(matrix.iter_cols()) if col.count("#") == 0
|
||||
]
|
||||
missing_ys = array(
|
||||
"I",
|
||||
accumulate([1 if row.count("#") == 0 else 0 for row in matrix.iter_rows()]),
|
||||
)
|
||||
|
||||
adjusted_galaxies = []
|
||||
large_adjusted_galaxies = []
|
||||
|
||||
for pos in galaxies:
|
||||
offset = Position(
|
||||
len([m for m in missing_xs if m < pos.x]),
|
||||
len([m for m in missing_ys if m < pos.y]),
|
||||
offset_galaxies = (
|
||||
(
|
||||
Position(
|
||||
missing_xs[pos.x],
|
||||
missing_ys[pos.y],
|
||||
),
|
||||
pos,
|
||||
)
|
||||
adjusted_galaxies.append(pos + offset)
|
||||
large_adjusted_galaxies.append(pos + 999_999 * offset)
|
||||
for pos in matrix.finditer("#")
|
||||
)
|
||||
|
||||
return cls(matrix, galaxies, adjusted_galaxies, large_adjusted_galaxies)
|
||||
return cls(matrix, offset_galaxies)
|
||||
|
||||
|
||||
class Day11(AocSameParser[Map], Aoc2[Map, Map]):
|
||||
|
@ -109,16 +117,13 @@ class Day11(AocSameParser[Map], Aoc2[Map, Map]):
|
|||
|
||||
def part1(self, inpt: Map) -> int:
|
||||
return sum(
|
||||
g1 | g2
|
||||
for i, g1 in enumerate(inpt.adjusted_galaxies)
|
||||
for g2 in inpt.adjusted_galaxies[i + 1 :]
|
||||
g1 | g2 for g1, g2 in combinations(((o + g) for o, g in inpt.galaxies), 2)
|
||||
)
|
||||
|
||||
def part2(self, inpt: Map) -> int:
|
||||
return sum(
|
||||
g1 | g2
|
||||
for i, g1 in enumerate(inpt.large_adjusted_galaxies)
|
||||
for g2 in inpt.large_adjusted_galaxies[i + 1 :]
|
||||
for g1, g2 in combinations(((999_999 * o + g) for o, g in inpt.galaxies), 2)
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue