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