Start refactoring code better flexibility.
This commit is contained in:
parent
1caf93b38b
commit
a9bcf9ef8f
@ -1,27 +1,9 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
lookups_1 = {str(d): d for d in range(1, 10)}
|
|
||||||
lookups_2 = lookups_1 | {
|
|
||||||
d: i + 1
|
|
||||||
for i, d in enumerate(
|
|
||||||
(
|
|
||||||
"one",
|
|
||||||
"two",
|
|
||||||
"three",
|
|
||||||
"four",
|
|
||||||
"five",
|
|
||||||
"six",
|
|
||||||
"seven",
|
|
||||||
"eight",
|
|
||||||
"nine",
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def find_values(lookups: dict[str, int]) -> list[int]:
|
def find_values(lines: list[str], lookups: dict[str, int]) -> list[int]:
|
||||||
values: list[int] = []
|
values: list[int] = []
|
||||||
|
|
||||||
for line in filter(bool, lines):
|
for line in filter(bool, lines):
|
||||||
@ -41,5 +23,27 @@ def find_values(lookups: dict[str, int]) -> list[int]:
|
|||||||
return values
|
return values
|
||||||
|
|
||||||
|
|
||||||
print(f"answer 1 is {sum(find_values(lookups_1))}")
|
class Solver(BaseSolver):
|
||||||
print(f"answer 2 is {sum(find_values(lookups_2))}")
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lookups_1 = {str(d): d for d in range(1, 10)}
|
||||||
|
lookups_2 = lookups_1 | {
|
||||||
|
d: i + 1
|
||||||
|
for i, d in enumerate(
|
||||||
|
(
|
||||||
|
"one",
|
||||||
|
"two",
|
||||||
|
"three",
|
||||||
|
"four",
|
||||||
|
"five",
|
||||||
|
"six",
|
||||||
|
"seven",
|
||||||
|
"eight",
|
||||||
|
"nine",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
|
yield sum(find_values(lines, lookups_1))
|
||||||
|
yield sum(find_values(lines, lookups_2))
|
||||||
|
@ -1,43 +1,43 @@
|
|||||||
import math
|
import math
|
||||||
import sys
|
from typing import Any, Iterator, Literal, TypeAlias, cast
|
||||||
from typing import Literal, TypeAlias, cast
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
CubeType: TypeAlias = Literal["red", "blue", "green"]
|
CubeType: TypeAlias = Literal["red", "blue", "green"]
|
||||||
|
|
||||||
MAX_CUBES: dict[CubeType, int] = {"red": 12, "green": 13, "blue": 14}
|
MAX_CUBES: dict[CubeType, int] = {"red": 12, "green": 13, "blue": 14}
|
||||||
|
|
||||||
# parse games
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
games: dict[int, list[dict[CubeType, int]]] = {}
|
|
||||||
for line in filter(bool, lines):
|
|
||||||
id_part, sets_part = line.split(":")
|
|
||||||
|
|
||||||
games[int(id_part.split(" ")[-1])] = [
|
class Solver(BaseSolver):
|
||||||
{
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
cast(CubeType, s[1]): int(s[0])
|
lines = input.splitlines()
|
||||||
for cube_draw in cube_set_s.strip().split(", ")
|
games: dict[int, list[dict[CubeType, int]]] = {}
|
||||||
if (s := cube_draw.split(" "))
|
for line in filter(bool, lines):
|
||||||
}
|
id_part, sets_part = line.split(":")
|
||||||
for cube_set_s in sets_part.strip().split(";")
|
|
||||||
]
|
|
||||||
|
|
||||||
# part 1
|
games[int(id_part.split(" ")[-1])] = [
|
||||||
answer_1 = sum(
|
{
|
||||||
id
|
cast(CubeType, s[1]): int(s[0])
|
||||||
for id, set_of_cubes in games.items()
|
for cube_draw in cube_set_s.strip().split(", ")
|
||||||
if all(
|
if (s := cube_draw.split(" "))
|
||||||
n_cubes <= MAX_CUBES[cube]
|
}
|
||||||
for cube_set in set_of_cubes
|
for cube_set_s in sets_part.strip().split(";")
|
||||||
for cube, n_cubes in cube_set.items()
|
]
|
||||||
)
|
|
||||||
)
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
yield sum(
|
||||||
answer_2 = sum(
|
id
|
||||||
math.prod(
|
for id, set_of_cubes in games.items()
|
||||||
max(cube_set.get(cube, 0) for cube_set in set_of_cubes) for cube in MAX_CUBES
|
if all(
|
||||||
)
|
n_cubes <= MAX_CUBES[cube]
|
||||||
for set_of_cubes in games.values()
|
for cube_set in set_of_cubes
|
||||||
)
|
for cube, n_cubes in cube_set.items()
|
||||||
print(f"answer 2 is {answer_2}")
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
yield sum(
|
||||||
|
math.prod(
|
||||||
|
max(cube_set.get(cube, 0) for cube_set in set_of_cubes)
|
||||||
|
for cube in MAX_CUBES
|
||||||
|
)
|
||||||
|
for set_of_cubes in games.values()
|
||||||
|
)
|
||||||
|
@ -1,53 +1,53 @@
|
|||||||
import string
|
import string
|
||||||
import sys
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
from typing import Any, Iterator
|
||||||
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
NOT_A_SYMBOL = "." + string.digits
|
NOT_A_SYMBOL = "." + string.digits
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
values: list[int] = []
|
class Solver(BaseSolver):
|
||||||
gears: dict[tuple[int, int], list[int]] = defaultdict(list)
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
for i, line in enumerate(lines):
|
values: list[int] = []
|
||||||
j = 0
|
gears: dict[tuple[int, int], list[int]] = defaultdict(list)
|
||||||
while j < len(line):
|
|
||||||
# skip everything until a digit is found (start of a number)
|
|
||||||
if line[j] not in string.digits:
|
|
||||||
j += 1
|
|
||||||
continue
|
|
||||||
|
|
||||||
# extract the range of the number and its value
|
for i, line in enumerate(lines):
|
||||||
k = j + 1
|
j = 0
|
||||||
while k < len(line) and line[k] in string.digits:
|
while j < len(line):
|
||||||
k += 1
|
# skip everything until a digit is found (start of a number)
|
||||||
|
if line[j] not in string.digits:
|
||||||
|
j += 1
|
||||||
|
continue
|
||||||
|
|
||||||
value = int(line[j:k])
|
# extract the range of the number and its value
|
||||||
|
k = j + 1
|
||||||
|
while k < len(line) and line[k] in string.digits:
|
||||||
|
k += 1
|
||||||
|
|
||||||
# lookup around the number if there is a symbol - we go through the number
|
value = int(line[j:k])
|
||||||
# itself but that should not matter since it only contains digits
|
|
||||||
found = False
|
|
||||||
for i2 in range(max(0, i - 1), min(i + 1, len(lines) - 1) + 1):
|
|
||||||
for j2 in range(max(0, j - 1), min(k, len(line) - 1) + 1):
|
|
||||||
assert i2 >= 0 and i2 < len(lines)
|
|
||||||
assert j2 >= 0 and j2 < len(line)
|
|
||||||
|
|
||||||
if lines[i2][j2] not in NOT_A_SYMBOL:
|
# lookup around the number if there is a symbol - we go through the number
|
||||||
found = True
|
# itself but that should not matter since it only contains digits
|
||||||
|
found = False
|
||||||
|
for i2 in range(max(0, i - 1), min(i + 1, len(lines) - 1) + 1):
|
||||||
|
for j2 in range(max(0, j - 1), min(k, len(line) - 1) + 1):
|
||||||
|
assert i2 >= 0 and i2 < len(lines)
|
||||||
|
assert j2 >= 0 and j2 < len(line)
|
||||||
|
|
||||||
if lines[i2][j2] == "*":
|
if lines[i2][j2] not in NOT_A_SYMBOL:
|
||||||
gears[i2, j2].append(value)
|
found = True
|
||||||
|
|
||||||
if found:
|
if lines[i2][j2] == "*":
|
||||||
values.append(value)
|
gears[i2, j2].append(value)
|
||||||
|
|
||||||
# continue starting from the end of the number
|
if found:
|
||||||
j = k
|
values.append(value)
|
||||||
|
|
||||||
# part 1
|
# continue starting from the end of the number
|
||||||
answer_1 = sum(values)
|
j = k
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
yield sum(values)
|
||||||
answer_2 = sum(v1 * v2 for v1, v2 in filter(lambda vs: len(vs) == 2, gears.values()))
|
yield sum(v1 * v2 for v1, v2 in filter(lambda vs: len(vs) == 2, gears.values()))
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import sys
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, Iterator
|
||||||
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@ -9,33 +11,34 @@ class Card:
|
|||||||
values: list[int]
|
values: list[int]
|
||||||
|
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
cards: list[Card] = []
|
cards: list[Card] = []
|
||||||
for line in lines:
|
for line in lines:
|
||||||
id_part, e_part = line.split(":")
|
id_part, e_part = line.split(":")
|
||||||
numbers_s, values_s = e_part.split("|")
|
numbers_s, values_s = e_part.split("|")
|
||||||
cards.append(
|
cards.append(
|
||||||
Card(
|
Card(
|
||||||
id=int(id_part.split()[1]),
|
id=int(id_part.split()[1]),
|
||||||
numbers=[int(v.strip()) for v in numbers_s.strip().split()],
|
numbers=[int(v.strip()) for v in numbers_s.strip().split()],
|
||||||
values=[int(v.strip()) for v in values_s.strip().split()],
|
values=[int(v.strip()) for v in values_s.strip().split()],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
winnings = [sum(1 for n in card.values if n in card.numbers) for card in cards]
|
winnings = [sum(1 for n in card.values if n in card.numbers) for card in cards]
|
||||||
|
|
||||||
# part 1
|
# part 1
|
||||||
answer_1 = sum(2 ** (winning - 1) for winning in winnings if winning > 0)
|
yield sum(2 ** (winning - 1) for winning in winnings if winning > 0)
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
# part 2
|
||||||
card2cards = {i: list(range(i + 1, i + w + 1)) for i, w in enumerate(winnings)}
|
card2cards = {i: list(range(i + 1, i + w + 1)) for i, w in enumerate(winnings)}
|
||||||
card2values = {i: 0 for i in range(len(cards))}
|
card2values = {i: 0 for i in range(len(cards))}
|
||||||
|
|
||||||
for i in range(len(cards)):
|
for i in range(len(cards)):
|
||||||
card2values[i] += 1
|
card2values[i] += 1
|
||||||
for j in card2cards[i]:
|
for j in card2cards[i]:
|
||||||
card2values[j] += card2values[i]
|
card2values[j] += card2values[i]
|
||||||
|
|
||||||
print(f"answer 2 is {sum(card2values.values())}")
|
yield sum(card2values.values())
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import sys
|
from typing import Any, Iterator, Sequence
|
||||||
from typing import Sequence
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
MAP_ORDER = [
|
MAP_ORDER = [
|
||||||
"seed",
|
"seed",
|
||||||
@ -12,55 +13,6 @@ MAP_ORDER = [
|
|||||||
"location",
|
"location",
|
||||||
]
|
]
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
# mappings from one category to another, each list contains
|
|
||||||
# ranges stored as (source, target, length), ordered by start and
|
|
||||||
# completed to have no "hole"
|
|
||||||
maps: dict[tuple[str, str], list[tuple[int, int, int]]] = {}
|
|
||||||
|
|
||||||
# parsing
|
|
||||||
index = 2
|
|
||||||
while index < len(lines):
|
|
||||||
p1, _, p2 = lines[index].split()[0].split("-")
|
|
||||||
|
|
||||||
# extract the existing ranges from the file - we store as (source, target, length)
|
|
||||||
# whereas the file is in order (target, source, length)
|
|
||||||
index += 1
|
|
||||||
values: list[tuple[int, int, int]] = []
|
|
||||||
while index < len(lines) and lines[index]:
|
|
||||||
n1, n2, n3 = lines[index].split()
|
|
||||||
values.append((int(n2), int(n1), int(n3)))
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
# sort by source value
|
|
||||||
values.sort()
|
|
||||||
|
|
||||||
# add a 'fake' interval starting at 0 if missing
|
|
||||||
if values[0][0] != 0:
|
|
||||||
values.insert(0, (0, 0, values[0][0]))
|
|
||||||
|
|
||||||
# fill gaps between intervals
|
|
||||||
for i in range(len(values) - 1):
|
|
||||||
next_start = values[i + 1][0]
|
|
||||||
end = values[i][0] + values[i][2]
|
|
||||||
if next_start != end:
|
|
||||||
values.insert(
|
|
||||||
i + 1,
|
|
||||||
(end, end, next_start - end),
|
|
||||||
)
|
|
||||||
|
|
||||||
# add an interval covering values up to at least 2**32 at the end
|
|
||||||
last_start, _, last_length = values[-1]
|
|
||||||
values.append((last_start + last_length, last_start + last_length, 2**32))
|
|
||||||
|
|
||||||
assert all(v1[0] + v1[2] == v2[0] for v1, v2 in zip(values[:-1], values[1:]))
|
|
||||||
assert values[0][0] == 0
|
|
||||||
assert values[-1][0] + values[-1][-1] >= 2**32
|
|
||||||
|
|
||||||
maps[p1, p2] = values
|
|
||||||
index += 1
|
|
||||||
|
|
||||||
|
|
||||||
def find_range(
|
def find_range(
|
||||||
values: tuple[int, int], map: list[tuple[int, int, int]]
|
values: tuple[int, int], map: list[tuple[int, int, int]]
|
||||||
@ -111,19 +63,71 @@ def find_range(
|
|||||||
return ranges
|
return ranges
|
||||||
|
|
||||||
|
|
||||||
def find_location_ranges(seeds: Sequence[tuple[int, int]]) -> Sequence[tuple[int, int]]:
|
class Solver(BaseSolver):
|
||||||
for map1, map2 in zip(MAP_ORDER[:-1], MAP_ORDER[1:]):
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
seeds = [s2 for s1 in seeds for s2 in find_range(s1, maps[map1, map2])]
|
lines = input.splitlines()
|
||||||
return seeds
|
|
||||||
|
|
||||||
|
# mappings from one category to another, each list contains
|
||||||
|
# ranges stored as (source, target, length), ordered by start and
|
||||||
|
# completed to have no "hole"
|
||||||
|
maps: dict[tuple[str, str], list[tuple[int, int, int]]] = {}
|
||||||
|
|
||||||
# part 1 - use find_range() with range of length 1
|
def find_location_ranges(
|
||||||
seeds_p1 = [(int(s), 1) for s in lines[0].split(":")[1].strip().split()]
|
seeds: Sequence[tuple[int, int]],
|
||||||
answer_1 = min(start for start, _ in find_location_ranges(seeds_p1))
|
) -> Sequence[tuple[int, int]]:
|
||||||
print(f"answer 1 is {answer_1}")
|
for map1, map2 in zip(MAP_ORDER[:-1], MAP_ORDER[1:]):
|
||||||
|
seeds = [s2 for s1 in seeds for s2 in find_range(s1, maps[map1, map2])]
|
||||||
|
return seeds
|
||||||
|
|
||||||
# # part 2
|
# parsing
|
||||||
parts = lines[0].split(":")[1].strip().split()
|
index = 2
|
||||||
seeds_p2 = [(int(s), int(e)) for s, e in zip(parts[::2], parts[1::2])]
|
while index < len(lines):
|
||||||
answer_2 = min(start for start, _ in find_location_ranges(seeds_p2))
|
p1, _, p2 = lines[index].split()[0].split("-")
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
# extract the existing ranges from the file - we store as (source, target, length)
|
||||||
|
# whereas the file is in order (target, source, length)
|
||||||
|
index += 1
|
||||||
|
values: list[tuple[int, int, int]] = []
|
||||||
|
while index < len(lines) and lines[index]:
|
||||||
|
n1, n2, n3 = lines[index].split()
|
||||||
|
values.append((int(n2), int(n1), int(n3)))
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
# sort by source value
|
||||||
|
values.sort()
|
||||||
|
|
||||||
|
# add a 'fake' interval starting at 0 if missing
|
||||||
|
if values[0][0] != 0:
|
||||||
|
values.insert(0, (0, 0, values[0][0]))
|
||||||
|
|
||||||
|
# fill gaps between intervals
|
||||||
|
for i in range(len(values) - 1):
|
||||||
|
next_start = values[i + 1][0]
|
||||||
|
end = values[i][0] + values[i][2]
|
||||||
|
if next_start != end:
|
||||||
|
values.insert(
|
||||||
|
i + 1,
|
||||||
|
(end, end, next_start - end),
|
||||||
|
)
|
||||||
|
|
||||||
|
# add an interval covering values up to at least 2**32 at the end
|
||||||
|
last_start, _, last_length = values[-1]
|
||||||
|
values.append((last_start + last_length, last_start + last_length, 2**32))
|
||||||
|
|
||||||
|
assert all(
|
||||||
|
v1[0] + v1[2] == v2[0] for v1, v2 in zip(values[:-1], values[1:])
|
||||||
|
)
|
||||||
|
assert values[0][0] == 0
|
||||||
|
assert values[-1][0] + values[-1][-1] >= 2**32
|
||||||
|
|
||||||
|
maps[p1, p2] = values
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
# part 1 - use find_range() with range of length 1
|
||||||
|
seeds_p1 = [(int(s), 1) for s in lines[0].split(":")[1].strip().split()]
|
||||||
|
yield min(start for start, _ in find_location_ranges(seeds_p1))
|
||||||
|
|
||||||
|
# # part 2
|
||||||
|
parts = lines[0].split(":")[1].strip().split()
|
||||||
|
seeds_p2 = [(int(s), int(e)) for s, e in zip(parts[::2], parts[1::2])]
|
||||||
|
yield min(start for start, _ in find_location_ranges(seeds_p2))
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import sys
|
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from typing import Any, Iterator
|
||||||
|
|
||||||
values = list(map(int, sys.stdin.read().strip().split()))
|
from ..base import BaseSolver
|
||||||
|
|
||||||
column_1 = sorted(values[::2])
|
|
||||||
column_2 = sorted(values[1::2])
|
|
||||||
counter_2 = Counter(column_2)
|
|
||||||
|
|
||||||
answer_1 = sum(abs(v1 - v2) for v1, v2 in zip(column_1, column_2, strict=True))
|
class Solver(BaseSolver):
|
||||||
answer_2 = sum(value * counter_2.get(value, 0) for value in column_1)
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
values = list(map(int, input.split()))
|
||||||
|
|
||||||
print(f"answer 1 is {answer_1}")
|
column_1 = sorted(values[::2])
|
||||||
print(f"answer 2 is {answer_2}")
|
column_2 = sorted(values[1::2])
|
||||||
|
|
||||||
|
yield sum(abs(v1 - v2) for v1, v2 in zip(column_1, column_2, strict=True))
|
||||||
|
|
||||||
|
counter_2 = Counter(column_2)
|
||||||
|
yield sum(value * counter_2.get(value, 0) for value in column_1)
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,22 +1,23 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
def is_safe(level: list[int]) -> bool:
|
class Solver(BaseSolver):
|
||||||
diff = [a - b for a, b in zip(level[:-1], level[1:], strict=True)]
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
def is_safe(level: list[int]) -> bool:
|
||||||
|
diff = [a - b for a, b in zip(level[:-1], level[1:], strict=True)]
|
||||||
|
|
||||||
return sum(d > 0 for d in diff) in (0, len(diff)) and all(
|
return sum(d > 0 for d in diff) in (0, len(diff)) and all(
|
||||||
1 <= abs(d) <= 3 for d in diff
|
1 <= abs(d) <= 3 for d in diff
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def is_any_safe(level: list[int]) -> bool:
|
||||||
|
return any(
|
||||||
|
is_safe(level[:i] + level[i + 1 :]) for i in range(0, len(level))
|
||||||
|
)
|
||||||
|
|
||||||
def is_any_safe(level: list[int]) -> bool:
|
levels = [[int(c) for c in r.split()] for r in input.splitlines()]
|
||||||
return any(is_safe(level[:i] + level[i + 1 :]) for i in range(0, len(level)))
|
|
||||||
|
|
||||||
|
yield sum(is_safe(level) for level in levels)
|
||||||
levels = [[int(c) for c in r.split()] for r in sys.stdin.read().strip().splitlines()]
|
yield sum(is_safe(level) or is_any_safe(level) for level in levels)
|
||||||
|
|
||||||
answer_1 = sum(is_safe(level) for level in levels)
|
|
||||||
answer_2 = sum(is_safe(level) or is_any_safe(level) for level in levels)
|
|
||||||
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,34 +1,30 @@
|
|||||||
import re
|
import re
|
||||||
import sys
|
from typing import Any, Iterator
|
||||||
from typing import Iterator
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
def extract_multiply(line: str) -> Iterator[int]:
|
class Solver(BaseSolver):
|
||||||
for m in re.finditer(r"mul\(([0-9]{1,3}),\s*([0-9]{1,3})\)", line):
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
yield int(m.group(1)) * int(m.group(2))
|
def extract_multiply(line: str) -> Iterator[int]:
|
||||||
|
for m in re.finditer(r"mul\(([0-9]{1,3}),\s*([0-9]{1,3})\)", line):
|
||||||
|
yield int(m.group(1)) * int(m.group(2))
|
||||||
|
|
||||||
|
def valid_memory_blocks(line: str) -> Iterator[str]:
|
||||||
|
accumulate = True
|
||||||
|
while line:
|
||||||
|
if accumulate:
|
||||||
|
if (dont_i := line.find("don't()")) != -1:
|
||||||
|
yield line[:dont_i]
|
||||||
|
line, accumulate = line[dont_i:], False
|
||||||
|
else:
|
||||||
|
yield line
|
||||||
|
line = ""
|
||||||
|
else:
|
||||||
|
if (do_i := line.find("do()")) != -1:
|
||||||
|
line, accumulate = line[do_i:], True
|
||||||
|
else:
|
||||||
|
line = ""
|
||||||
|
|
||||||
def valid_memory_blocks(line: str) -> Iterator[str]:
|
yield sum(extract_multiply(input))
|
||||||
accumulate = True
|
yield sum(sum(extract_multiply(block)) for block in valid_memory_blocks(input))
|
||||||
while line:
|
|
||||||
if accumulate:
|
|
||||||
if (dont_i := line.find("don't()")) != -1:
|
|
||||||
yield line[:dont_i]
|
|
||||||
line, accumulate = line[dont_i:], False
|
|
||||||
else:
|
|
||||||
yield line
|
|
||||||
line = ""
|
|
||||||
else:
|
|
||||||
if (do_i := line.find("do()")) != -1:
|
|
||||||
line, accumulate = line[do_i:], True
|
|
||||||
else:
|
|
||||||
line = ""
|
|
||||||
|
|
||||||
|
|
||||||
line = sys.stdin.read().strip()
|
|
||||||
|
|
||||||
answer_1 = sum(extract_multiply(line))
|
|
||||||
answer_2 = sum(sum(extract_multiply(block)) for block in valid_memory_blocks(line))
|
|
||||||
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,31 +1,37 @@
|
|||||||
import itertools as it
|
import itertools as it
|
||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().strip().splitlines()
|
from ..base import BaseSolver
|
||||||
n = len(lines)
|
|
||||||
|
|
||||||
answer_1 = sum(
|
|
||||||
line.count("XMAS") + line.count("SAMX")
|
|
||||||
for i in range(n)
|
|
||||||
for ri, rk, ro, ci, ck, cm in (
|
|
||||||
(1, 0, 0, 0, 1, n),
|
|
||||||
(0, 1, 0, 1, 0, n),
|
|
||||||
(0, 1, 0, 1, 1, n - i),
|
|
||||||
(0, -1, -1, 1, 1, n - i),
|
|
||||||
(1, 1, 0, 0, 1, n - i if i != 0 else 0),
|
|
||||||
(-1, -1, -1, 0, 1, n - i if i != 0 else 0),
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
line := "".join(lines[ri * i + rk * k + ro][ci * i + ck * k] for k in range(cm))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
answer_2 = sum(
|
class Solver(BaseSolver):
|
||||||
lines[i][j] == "A"
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
and "".join(lines[i + di][j + dj] for di, dj in it.product((-1, 1), (-1, 1)))
|
lines = input.splitlines()
|
||||||
in {"MSMS", "SSMM", "MMSS", "SMSM"}
|
n = len(lines)
|
||||||
for i, j in it.product(range(1, n - 1), range(1, n - 1))
|
|
||||||
)
|
|
||||||
|
|
||||||
print(f"answer 1 is {answer_1}")
|
yield sum(
|
||||||
print(f"answer 2 is {answer_2}")
|
line.count("XMAS") + line.count("SAMX")
|
||||||
|
for i in range(n)
|
||||||
|
for ri, rk, ro, ci, ck, cm in (
|
||||||
|
(1, 0, 0, 0, 1, n),
|
||||||
|
(0, 1, 0, 1, 0, n),
|
||||||
|
(0, 1, 0, 1, 1, n - i),
|
||||||
|
(0, -1, -1, 1, 1, n - i),
|
||||||
|
(1, 1, 0, 0, 1, n - i if i != 0 else 0),
|
||||||
|
(-1, -1, -1, 0, 1, n - i if i != 0 else 0),
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
line := "".join(
|
||||||
|
lines[ri * i + rk * k + ro][ci * i + ck * k] for k in range(cm)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
yield sum(
|
||||||
|
lines[i][j] == "A"
|
||||||
|
and "".join(
|
||||||
|
lines[i + di][j + dj] for di, dj in it.product((-1, 1), (-1, 1))
|
||||||
|
)
|
||||||
|
in {"MSMS", "SSMM", "MMSS", "SMSM"}
|
||||||
|
for i, j in it.product(range(1, n - 1), range(1, n - 1))
|
||||||
|
)
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
answer_1 = ...
|
|
||||||
|
|
||||||
answer_2 = ...
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from .base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser("Holt59 Advent-Of-Code Runner")
|
parser = argparse.ArgumentParser("Holt59 Advent-Of-Code Runner")
|
||||||
@ -40,8 +42,7 @@ def main():
|
|||||||
day: int = args.day
|
day: int = args.day
|
||||||
|
|
||||||
# TODO: change this
|
# TODO: change this
|
||||||
if verbose:
|
logging.basicConfig(level=logging.INFO if verbose else logging.WARNING)
|
||||||
os.environ["AOC_VERBOSE"] = "True"
|
|
||||||
|
|
||||||
if input_path is None:
|
if input_path is None:
|
||||||
input_path = Path(__file__).parent.joinpath(
|
input_path = Path(__file__).parent.joinpath(
|
||||||
@ -49,11 +50,18 @@ def main():
|
|||||||
)
|
)
|
||||||
assert input_path.exists(), f"{input_path} missing"
|
assert input_path.exists(), f"{input_path} missing"
|
||||||
|
|
||||||
|
solver_class: type[BaseSolver] = importlib.import_module(
|
||||||
|
f".{year}.day{day}", __package__
|
||||||
|
).Solver
|
||||||
|
|
||||||
|
solver = solver_class(logging.getLogger("AOC"), year, day)
|
||||||
|
|
||||||
|
data: str
|
||||||
if stdin:
|
if stdin:
|
||||||
importlib.import_module(f".{year}.day{day}", __package__)
|
data = sys.stdin.read()
|
||||||
else:
|
else:
|
||||||
with open(input_path) as fp:
|
with open(input_path) as fp:
|
||||||
sys.stdin = fp
|
data = fp.read()
|
||||||
importlib.import_module(f".{year}.day{day}", __package__)
|
|
||||||
|
|
||||||
sys.stdin = sys.__stdin__
|
for i_answer, answer in enumerate(solver.solve(data.strip())):
|
||||||
|
print(f"answer {i_answer + 1} is {answer}")
|
||||||
|
13
src/holt59/aoc/base.py
Normal file
13
src/holt59/aoc/base.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
from logging import Logger
|
||||||
|
from typing import Any, Final, Iterator
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSolver:
|
||||||
|
def __init__(self, logger: Logger, year: int, day: int):
|
||||||
|
self.logger: Final = logger
|
||||||
|
self.year: Final = year
|
||||||
|
self.day: Final = day
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def solve(self, input: str) -> Iterator[Any]: ...
|
Loading…
Reference in New Issue
Block a user