Compare commits
2 Commits
6fd569aeba
...
1b4dd32898
Author | SHA1 | Date | |
---|---|---|---|
|
1b4dd32898 | ||
|
cd96140378 |
@ -1,14 +1,17 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
values = [int(line) for line in lines]
|
|
||||||
|
|
||||||
# part 1
|
class Solver(BaseSolver):
|
||||||
answer_1 = sum(v2 > v1 for v1, v2 in zip(values[:-1], values[1:]))
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
print(f"answer 1 is {answer_1}")
|
lines = input.splitlines()
|
||||||
|
|
||||||
# part 2
|
values = [int(line) for line in lines]
|
||||||
runnings = [sum(values[i : i + 3]) for i in range(len(values) - 2)]
|
|
||||||
answer_2 = sum(v2 > v1 for v1, v2 in zip(runnings[:-1], runnings[1:]))
|
# part 1
|
||||||
print(f"answer 2 is {answer_2}")
|
yield sum(v2 > v1 for v1, v2 in zip(values[:-1], values[1:]))
|
||||||
|
|
||||||
|
# part 2
|
||||||
|
runnings = [sum(values[i : i + 3]) for i in range(len(values) - 2)]
|
||||||
|
yield sum(v2 > v1 for v1, v2 in zip(runnings[:-1], runnings[1:]))
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,41 +1,38 @@
|
|||||||
import sys
|
|
||||||
from math import prod
|
from math import prod
|
||||||
from typing import Literal, TypeAlias, cast
|
from typing import Any, Iterator, Literal, TypeAlias, cast
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
Command: TypeAlias = Literal["forward", "up", "down"]
|
Command: TypeAlias = Literal["forward", "up", "down"]
|
||||||
|
|
||||||
commands: list[tuple[Command, int]] = [
|
|
||||||
(cast(Command, (p := line.split())[0]), int(p[1])) for line in lines
|
|
||||||
]
|
|
||||||
|
|
||||||
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
def depth_and_position(use_aim: bool):
|
commands: list[tuple[Command, int]] = [
|
||||||
aim, pos, depth = 0, 0, 0
|
(cast(Command, (p := line.split())[0]), int(p[1])) for line in lines
|
||||||
for command, value in commands:
|
]
|
||||||
d_depth = 0
|
|
||||||
match command:
|
|
||||||
case "forward":
|
|
||||||
pos += value
|
|
||||||
depth += value * aim
|
|
||||||
case "up":
|
|
||||||
d_depth = -value
|
|
||||||
case "down":
|
|
||||||
d_depth = value
|
|
||||||
|
|
||||||
if use_aim:
|
def depth_and_position(use_aim: bool):
|
||||||
aim += d_depth
|
aim, pos, depth = 0, 0, 0
|
||||||
else:
|
for command, value in commands:
|
||||||
depth += value
|
d_depth = 0
|
||||||
|
match command:
|
||||||
|
case "forward":
|
||||||
|
pos += value
|
||||||
|
depth += value * aim
|
||||||
|
case "up":
|
||||||
|
d_depth = -value
|
||||||
|
case "down":
|
||||||
|
d_depth = value
|
||||||
|
|
||||||
return depth, pos
|
if use_aim:
|
||||||
|
aim += d_depth
|
||||||
|
else:
|
||||||
|
depth += value
|
||||||
|
|
||||||
|
return depth, pos
|
||||||
|
|
||||||
# part 1
|
yield prod(depth_and_position(False))
|
||||||
answer_1 = prod(depth_and_position(False))
|
yield prod(depth_and_position(True))
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
|
||||||
answer_2 = prod(depth_and_position(True))
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
# part 1
|
|
||||||
answer_1 = ...
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
class Solver(BaseSolver):
|
||||||
answer_2 = ...
|
def solve(self, input: str) -> Iterator[Any]: ...
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import sys
|
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
from typing import Literal
|
from typing import Any, Iterator, Literal
|
||||||
|
|
||||||
|
from ..base import BaseSolver
|
||||||
|
|
||||||
|
|
||||||
def generator_rating(
|
def generator_rating(
|
||||||
@ -20,20 +21,23 @@ def generator_rating(
|
|||||||
return values[0]
|
return values[0]
|
||||||
|
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
|
# part 1
|
||||||
|
most_and_least_common = [
|
||||||
|
tuple(
|
||||||
|
Counter(line[col] for line in lines).most_common(2)[m][0]
|
||||||
|
for m in range(2)
|
||||||
|
)
|
||||||
|
for col in range(len(lines[0]))
|
||||||
|
]
|
||||||
|
gamma_rate = int("".join(most for most, _ in most_and_least_common), base=2)
|
||||||
|
epsilon_rate = int("".join(least for _, least in most_and_least_common), base=2)
|
||||||
|
yield gamma_rate * epsilon_rate
|
||||||
|
|
||||||
# part 1
|
# part 2
|
||||||
most_and_least_common = [
|
oxygen_generator_rating = int(generator_rating(lines, True, "1"), base=2)
|
||||||
tuple(Counter(line[col] for line in lines).most_common(2)[m][0] for m in range(2))
|
co2_scrubber_rating = int(generator_rating(lines, False, "0"), base=2)
|
||||||
for col in range(len(lines[0]))
|
yield oxygen_generator_rating * co2_scrubber_rating
|
||||||
]
|
|
||||||
gamma_rate = int("".join(most for most, _ in most_and_least_common), base=2)
|
|
||||||
epsilon_rate = int("".join(least for _, least in most_and_least_common), base=2)
|
|
||||||
print(f"answer 1 is {gamma_rate * epsilon_rate}")
|
|
||||||
|
|
||||||
# part 2
|
|
||||||
oxygen_generator_rating = int(generator_rating(lines, True, "1"), base=2)
|
|
||||||
co2_scrubber_rating = int(generator_rating(lines, False, "0"), base=2)
|
|
||||||
answer_2 = oxygen_generator_rating * co2_scrubber_rating
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,45 +1,52 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
numbers = [int(c) for c in lines[0].split(",")]
|
|
||||||
|
|
||||||
boards = np.asarray(
|
class Solver(BaseSolver):
|
||||||
[
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
[[int(c) for c in line.split()] for line in lines[start : start + 5]]
|
lines = input.splitlines()
|
||||||
for start in range(2, len(lines), 6)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
# (round, score) for each board (-1 when not found)
|
numbers = [int(c) for c in lines[0].split(",")]
|
||||||
winning_rounds: list[tuple[int, int]] = [(-1, -1) for _ in range(len(boards))]
|
|
||||||
marked = np.zeros_like(boards, dtype=bool)
|
|
||||||
|
|
||||||
for round, number in enumerate(numbers):
|
boards = np.asarray(
|
||||||
# mark boards
|
[
|
||||||
marked[boards == number] = True
|
[[int(c) for c in line.split()] for line in lines[start : start + 5]]
|
||||||
|
for start in range(2, len(lines), 6)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
# check each board for winning
|
# (round, score) for each board (-1 when not found)
|
||||||
for index in range(len(boards)):
|
winning_rounds: list[tuple[int, int]] = [(-1, -1) for _ in range(len(boards))]
|
||||||
if winning_rounds[index][0] > 0:
|
marked = np.zeros_like(boards, dtype=bool)
|
||||||
continue
|
|
||||||
|
|
||||||
if np.any(np.all(marked[index], axis=0) | np.all(marked[index], axis=1)):
|
for round, number in enumerate(numbers):
|
||||||
winning_rounds[index] = (
|
# mark boards
|
||||||
round,
|
marked[boards == number] = True
|
||||||
number * int(np.sum(boards[index][~marked[index]])),
|
|
||||||
)
|
|
||||||
|
|
||||||
# all boards are winning - break
|
# check each board for winning
|
||||||
if np.all(marked.all(axis=1) | marked.all(axis=2)):
|
for index in range(len(boards)):
|
||||||
break
|
if winning_rounds[index][0] > 0:
|
||||||
|
continue
|
||||||
|
|
||||||
# part 1
|
if np.any(
|
||||||
(_, score) = min(winning_rounds, key=lambda w: w[0])
|
np.all(marked[index], axis=0) | np.all(marked[index], axis=1)
|
||||||
print(f"answer 1 is {score}")
|
):
|
||||||
|
winning_rounds[index] = (
|
||||||
|
round,
|
||||||
|
number * int(np.sum(boards[index][~marked[index]])),
|
||||||
|
)
|
||||||
|
|
||||||
# part 2
|
# all boards are winning - break
|
||||||
(_, score) = max(winning_rounds, key=lambda w: w[0])
|
if np.all(marked.all(axis=1) | marked.all(axis=2)):
|
||||||
print(f"answer 2 is {score}")
|
break
|
||||||
|
|
||||||
|
# part 1
|
||||||
|
(_, score) = min(winning_rounds, key=lambda w: w[0])
|
||||||
|
yield score
|
||||||
|
|
||||||
|
# part 2
|
||||||
|
(_, score) = max(winning_rounds, key=lambda w: w[0])
|
||||||
|
yield score
|
||||||
|
@ -1,48 +1,48 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
lines: list[str] = sys.stdin.read().splitlines()
|
from ..base import BaseSolver
|
||||||
|
|
||||||
sections: list[tuple[tuple[int, int], tuple[int, int]]] = [
|
|
||||||
(
|
|
||||||
(
|
|
||||||
int(line.split(" -> ")[0].split(",")[0]),
|
|
||||||
int(line.split(" -> ")[0].split(",")[1]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
int(line.split(" -> ")[1].split(",")[0]),
|
|
||||||
int(line.split(" -> ")[1].split(",")[1]),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
for line in lines
|
|
||||||
]
|
|
||||||
|
|
||||||
np_sections = np.array(sections).reshape(-1, 4)
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = input.splitlines()
|
||||||
|
|
||||||
x_min, x_max, y_min, y_max = (
|
sections: list[tuple[tuple[int, int], tuple[int, int]]] = [
|
||||||
min(np_sections[:, 0].min(), np_sections[:, 2].min()),
|
(
|
||||||
max(np_sections[:, 0].max(), np_sections[:, 2].max()),
|
(
|
||||||
min(np_sections[:, 1].min(), np_sections[:, 3].min()),
|
int(line.split(" -> ")[0].split(",")[0]),
|
||||||
max(np_sections[:, 1].max(), np_sections[:, 3].max()),
|
int(line.split(" -> ")[0].split(",")[1]),
|
||||||
)
|
),
|
||||||
|
(
|
||||||
|
int(line.split(" -> ")[1].split(",")[0]),
|
||||||
|
int(line.split(" -> ")[1].split(",")[1]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for line in lines
|
||||||
|
]
|
||||||
|
|
||||||
counts_1 = np.zeros((y_max + 1, x_max + 1), dtype=int)
|
np_sections = np.array(sections).reshape(-1, 4)
|
||||||
counts_2 = counts_1.copy()
|
|
||||||
|
|
||||||
for (x1, y1), (x2, y2) in sections:
|
x_max, y_max = (
|
||||||
x_rng = range(x1, x2 + 1, 1) if x2 >= x1 else range(x1, x2 - 1, -1)
|
max(np_sections[:, 0].max(), np_sections[:, 2].max()),
|
||||||
y_rng = range(y1, y2 + 1, 1) if y2 >= y1 else range(y1, y2 - 1, -1)
|
max(np_sections[:, 1].max(), np_sections[:, 3].max()),
|
||||||
|
)
|
||||||
|
|
||||||
if x1 == x2 or y1 == y2:
|
counts_1 = np.zeros((y_max + 1, x_max + 1), dtype=int)
|
||||||
counts_1[list(y_rng), list(x_rng)] += 1
|
counts_2 = counts_1.copy()
|
||||||
counts_2[list(y_rng), list(x_rng)] += 1
|
|
||||||
elif abs(x2 - x1) == abs(y2 - y1):
|
|
||||||
for i, j in zip(y_rng, x_rng):
|
|
||||||
counts_2[i, j] += 1
|
|
||||||
|
|
||||||
answer_1 = (counts_1 >= 2).sum()
|
for (x1, y1), (x2, y2) in sections:
|
||||||
print(f"answer 1 is {answer_1}")
|
x_rng = range(x1, x2 + 1, 1) if x2 >= x1 else range(x1, x2 - 1, -1)
|
||||||
|
y_rng = range(y1, y2 + 1, 1) if y2 >= y1 else range(y1, y2 - 1, -1)
|
||||||
|
|
||||||
answer_2 = (counts_2 >= 2).sum()
|
if x1 == x2 or y1 == y2:
|
||||||
print(f"answer 2 is {answer_2}")
|
counts_1[list(y_rng), list(x_rng)] += 1
|
||||||
|
counts_2[list(y_rng), list(x_rng)] += 1
|
||||||
|
elif abs(x2 - x1) == abs(y2 - y1):
|
||||||
|
for i, j in zip(y_rng, x_rng):
|
||||||
|
counts_2[i, j] += 1
|
||||||
|
|
||||||
|
yield (counts_1 >= 2).sum()
|
||||||
|
yield (counts_2 >= 2).sum()
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
values = [int(c) for c in sys.stdin.read().strip().split(",")]
|
from ..base import BaseSolver
|
||||||
|
|
||||||
days = 256
|
|
||||||
lanterns = {day: 0 for day in range(days)}
|
|
||||||
for value in values:
|
|
||||||
for day in range(value, days, 7):
|
|
||||||
lanterns[day] += 1
|
|
||||||
|
|
||||||
for day in range(days):
|
class Solver(BaseSolver):
|
||||||
for day2 in range(day + 9, days, 7):
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
lanterns[day2] += lanterns[day]
|
values = [int(c) for c in input.split(",")]
|
||||||
|
|
||||||
# part 1
|
days = 256
|
||||||
answer_1 = sum(v for k, v in lanterns.items() if k < 80) + len(values)
|
lanterns = {day: 0 for day in range(days)}
|
||||||
print(f"answer 1 is {answer_1}")
|
for value in values:
|
||||||
|
for day in range(value, days, 7):
|
||||||
|
lanterns[day] += 1
|
||||||
|
|
||||||
# part 2
|
for day in range(days):
|
||||||
answer_2 = sum(lanterns.values()) + len(values)
|
for day2 in range(day + 9, days, 7):
|
||||||
print(f"answer 2 is {answer_2}")
|
lanterns[day2] += lanterns[day]
|
||||||
|
|
||||||
|
yield sum(v for k, v in lanterns.items() if k < 80) + len(values)
|
||||||
|
yield sum(lanterns.values()) + len(values)
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import sys
|
from typing import Any, Iterator
|
||||||
|
|
||||||
positions = [int(c) for c in sys.stdin.read().strip().split(",")]
|
from ..base import BaseSolver
|
||||||
|
|
||||||
min_position, max_position = min(positions), max(positions)
|
|
||||||
|
|
||||||
# part 1
|
class Solver(BaseSolver):
|
||||||
answer_1 = min(
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
sum(abs(p - position) for p in positions)
|
positions = [int(c) for c in input.split(",")]
|
||||||
for position in range(min_position, max_position + 1)
|
|
||||||
)
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
min_position, max_position = min(positions), max(positions)
|
||||||
answer_2 = min(
|
|
||||||
sum(abs(p - position) * (abs(p - position) + 1) // 2 for p in positions)
|
# part 1
|
||||||
for position in range(min_position, max_position + 1)
|
yield min(
|
||||||
)
|
sum(abs(p - position) for p in positions)
|
||||||
print(f"answer 2 is {answer_2}")
|
for position in range(min_position, max_position + 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
# part 2
|
||||||
|
yield min(
|
||||||
|
sum(abs(p - position) * (abs(p - position) + 1) // 2 for p in positions)
|
||||||
|
for position in range(min_position, max_position + 1)
|
||||||
|
)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import itertools
|
import itertools
|
||||||
import os
|
from typing import Any, Iterator
|
||||||
import sys
|
|
||||||
|
|
||||||
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
|
from ..base import BaseSolver
|
||||||
|
|
||||||
digits = {
|
digits = {
|
||||||
"abcefg": 0,
|
"abcefg": 0,
|
||||||
@ -17,71 +16,74 @@ digits = {
|
|||||||
"abcdfg": 9,
|
"abcdfg": 9,
|
||||||
}
|
}
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
# part 1
|
class Solver(BaseSolver):
|
||||||
lengths = {len(k) for k, v in digits.items() if v in (1, 4, 7, 8)}
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
answer_1 = sum(
|
lines = input.splitlines()
|
||||||
len(p) in lengths for line in lines for p in line.split("|")[1].strip().split()
|
|
||||||
)
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
|
||||||
# part 2
|
# part 1
|
||||||
values: list[int] = []
|
lengths = {len(k) for k, v in digits.items() if v in (1, 4, 7, 8)}
|
||||||
|
yield sum(
|
||||||
|
len(p) in lengths
|
||||||
|
for line in lines
|
||||||
|
for p in line.split("|")[1].strip().split()
|
||||||
|
)
|
||||||
|
|
||||||
for line in lines:
|
# part 2
|
||||||
parts = line.split("|")
|
values: list[int] = []
|
||||||
broken_digits = sorted(parts[0].strip().split(), key=len)
|
|
||||||
|
|
||||||
per_length = {
|
for line in lines:
|
||||||
k: list(v)
|
parts = line.split("|")
|
||||||
for k, v in itertools.groupby(sorted(broken_digits, key=len), key=len)
|
broken_digits = sorted(parts[0].strip().split(), key=len)
|
||||||
}
|
|
||||||
|
|
||||||
# a can be found immediately
|
per_length = {
|
||||||
a = next(u for u in per_length[3][0] if u not in per_length[2][0])
|
k: list(v)
|
||||||
|
for k, v in itertools.groupby(sorted(broken_digits, key=len), key=len)
|
||||||
|
}
|
||||||
|
|
||||||
# c and f have only two possible values corresponding to the single entry of
|
# a can be found immediately
|
||||||
# length 2
|
a = next(u for u in per_length[3][0] if u not in per_length[2][0])
|
||||||
cf = list(per_length[2][0])
|
|
||||||
|
|
||||||
# the only digit of length 4 contains bcdf, so we can deduce bd by removing cf
|
# c and f have only two possible values corresponding to the single entry of
|
||||||
bd = [u for u in per_length[4][0] if u not in cf]
|
# length 2
|
||||||
|
cf = list(per_length[2][0])
|
||||||
|
|
||||||
# the 3 digits of length 5 have a, d and g in common
|
# the only digit of length 4 contains bcdf, so we can deduce bd by removing cf
|
||||||
adg = [u for u in per_length[5][0] if all(u in pe for pe in per_length[5][1:])]
|
bd = [u for u in per_length[4][0] if u not in cf]
|
||||||
|
|
||||||
# we can remove a
|
# the 3 digits of length 5 have a, d and g in common
|
||||||
dg = [u for u in adg if u != a]
|
adg = [
|
||||||
|
u for u in per_length[5][0] if all(u in pe for pe in per_length[5][1:])
|
||||||
|
]
|
||||||
|
|
||||||
# we can deduce d and g
|
# we can remove a
|
||||||
d = next(u for u in dg if u in bd)
|
dg = [u for u in adg if u != a]
|
||||||
g = next(u for u in dg if u != d)
|
|
||||||
|
|
||||||
# then b
|
# we can deduce d and g
|
||||||
b = next(u for u in bd if u != d)
|
d = next(u for u in dg if u in bd)
|
||||||
|
g = next(u for u in dg if u != d)
|
||||||
|
|
||||||
# f is in the three 6-length digits, while c is only in 2
|
# then b
|
||||||
f = next(u for u in cf if all(u in p for p in per_length[6]))
|
b = next(u for u in bd if u != d)
|
||||||
|
|
||||||
# c is not f
|
# f is in the three 6-length digits, while c is only in 2
|
||||||
c = next(u for u in cf if u != f)
|
f = next(u for u in cf if all(u in p for p in per_length[6]))
|
||||||
|
|
||||||
# e is the last one
|
# c is not f
|
||||||
e = next(u for u in "abcdefg" if u not in {a, b, c, d, f, g})
|
c = next(u for u in cf if u != f)
|
||||||
|
|
||||||
mapping = dict(zip((a, b, c, d, e, f, g), "abcdefg"))
|
# e is the last one
|
||||||
|
e = next(u for u in "abcdefg" if u not in {a, b, c, d, f, g})
|
||||||
|
|
||||||
value = 0
|
mapping = dict(zip((a, b, c, d, e, f, g), "abcdefg"))
|
||||||
for number in parts[1].strip().split():
|
|
||||||
digit = "".join(sorted(mapping[c] for c in number))
|
|
||||||
value = 10 * value + digits[digit]
|
|
||||||
|
|
||||||
if VERBOSE:
|
value = 0
|
||||||
print(value)
|
for number in parts[1].strip().split():
|
||||||
|
digit = "".join(sorted(mapping[c] for c in number))
|
||||||
|
value = 10 * value + digits[digit]
|
||||||
|
|
||||||
values.append(value)
|
self.logger.info(f"value for '{line}' is {value}")
|
||||||
|
|
||||||
|
values.append(value)
|
||||||
|
|
||||||
answer_2 = sum(values)
|
yield sum(values)
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import sys
|
|
||||||
from math import prod
|
from math import prod
|
||||||
|
from typing import Any, Iterator
|
||||||
|
|
||||||
values = [[int(c) for c in row] for row in sys.stdin.read().splitlines()]
|
from ..base import BaseSolver
|
||||||
n_rows, n_cols = len(values), len(values[0])
|
|
||||||
|
|
||||||
|
|
||||||
def neighbors(point: tuple[int, int]):
|
def neighbors(point: tuple[int, int], n_rows: int, n_cols: int):
|
||||||
i, j = point
|
i, j = point
|
||||||
for di, dj in ((-1, 0), (+1, 0), (0, -1), (0, +1)):
|
for di, dj in ((-1, 0), (+1, 0), (0, -1), (0, +1)):
|
||||||
if 0 <= i + di < n_rows and 0 <= j + dj < n_cols:
|
if 0 <= i + di < n_rows and 0 <= j + dj < n_cols:
|
||||||
yield (i + di, j + dj)
|
yield (i + di, j + dj)
|
||||||
|
|
||||||
|
|
||||||
def basin(start: tuple[int, int]) -> set[tuple[int, int]]:
|
def basin(values: list[list[int]], start: tuple[int, int]) -> set[tuple[int, int]]:
|
||||||
|
n_rows, n_cols = len(values), len(values[0])
|
||||||
visited: set[tuple[int, int]] = set()
|
visited: set[tuple[int, int]] = set()
|
||||||
queue = [start]
|
queue = [start]
|
||||||
|
|
||||||
@ -23,22 +23,25 @@ def basin(start: tuple[int, int]) -> set[tuple[int, int]]:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
visited.add((i, j))
|
visited.add((i, j))
|
||||||
queue.extend(neighbors((i, j)))
|
queue.extend(neighbors((i, j), n_rows, n_cols))
|
||||||
|
|
||||||
return visited
|
return visited
|
||||||
|
|
||||||
|
|
||||||
low_points = [
|
class Solver(BaseSolver):
|
||||||
(i, j)
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
for i in range(n_rows)
|
values = [[int(c) for c in row] for row in input.splitlines()]
|
||||||
for j in range(n_cols)
|
n_rows, n_cols = len(values), len(values[0])
|
||||||
if all(values[ti][tj] > values[i][j] for ti, tj in neighbors((i, j)))
|
|
||||||
]
|
|
||||||
|
|
||||||
# part 1
|
low_points = [
|
||||||
answer_1 = sum(values[i][j] + 1 for i, j in low_points)
|
(i, j)
|
||||||
print(f"answer 1 is {answer_1}")
|
for i in range(n_rows)
|
||||||
|
for j in range(n_cols)
|
||||||
|
if all(
|
||||||
|
values[ti][tj] > values[i][j]
|
||||||
|
for ti, tj in neighbors((i, j), n_rows, n_cols)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
# part 2
|
yield sum(values[i][j] + 1 for i, j in low_points)
|
||||||
answer_2 = prod(sorted(len(basin(point)) for point in low_points)[-3:])
|
yield prod(sorted(len(basin(values, point)) for point in low_points)[-3:])
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import itertools as it
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -20,9 +21,7 @@ class Solver(BaseSolver):
|
|||||||
no_beacons_row_l.append(sx + np.arange(0, d - abs(sy - row) + 1)) # type: ignore
|
no_beacons_row_l.append(sx + np.arange(0, d - abs(sy - row) + 1)) # type: ignore
|
||||||
|
|
||||||
beacons_at_row = set(bx for (bx, by) in sensor_to_beacon.values() if by == row)
|
beacons_at_row = set(bx for (bx, by) in sensor_to_beacon.values() if by == row)
|
||||||
no_beacons_row = set(np.concatenate(no_beacons_row_l)).difference(
|
no_beacons_row = set(it.chain(*no_beacons_row_l)).difference(beacons_at_row) # type: ignore
|
||||||
beacons_at_row
|
|
||||||
) # type: ignore
|
|
||||||
|
|
||||||
return len(no_beacons_row)
|
return len(no_beacons_row)
|
||||||
|
|
||||||
@ -92,5 +91,5 @@ class Solver(BaseSolver):
|
|||||||
|
|
||||||
# x, y, a2 = part2_cplex(sensor_to_beacon, xy_max)
|
# x, y, a2 = part2_cplex(sensor_to_beacon, xy_max)
|
||||||
x, y, a2 = self.part2_intervals(sensor_to_beacon, xy_max)
|
x, y, a2 = self.part2_intervals(sensor_to_beacon, xy_max)
|
||||||
self.logger.info("answer 2 is {at} (x={x}, y={y})")
|
self.logger.info(f"answer 2 is {a2} (x={x}, y={y})")
|
||||||
yield a2
|
yield a2
|
||||||
|
@ -3,7 +3,6 @@ from __future__ import annotations
|
|||||||
import heapq
|
import heapq
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, FrozenSet, Iterator, NamedTuple
|
from typing import Any, FrozenSet, Iterator, NamedTuple
|
||||||
|
|
||||||
@ -38,8 +37,8 @@ def breadth_first_search(pipes: dict[str, Pipe], pipe: Pipe) -> dict[Pipe, int]:
|
|||||||
Runs a BFS from the given pipe and return the shortest distance (in term of hops)
|
Runs a BFS from the given pipe and return the shortest distance (in term of hops)
|
||||||
to all other pipes.
|
to all other pipes.
|
||||||
"""
|
"""
|
||||||
queue = [(0, pipe_1)]
|
queue = [(0, pipe)]
|
||||||
visited = set()
|
visited: set[Pipe] = set()
|
||||||
distances: dict[Pipe, int] = {}
|
distances: dict[Pipe, int] = {}
|
||||||
|
|
||||||
while len(distances) < len(pipes):
|
while len(distances) < len(pipes):
|
||||||
@ -124,37 +123,37 @@ def part_2(
|
|||||||
# === MAIN ===
|
# === MAIN ===
|
||||||
|
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = [line.strip() for line in input.splitlines()]
|
||||||
|
|
||||||
|
pipes: dict[str, Pipe] = {}
|
||||||
|
for line in lines:
|
||||||
|
r = re.match(
|
||||||
|
R"Valve ([A-Z]+) has flow rate=([0-9]+); tunnels? leads? to valves? (.+)",
|
||||||
|
line,
|
||||||
|
)
|
||||||
|
assert r
|
||||||
|
|
||||||
pipes: dict[str, Pipe] = {}
|
g = r.groups()
|
||||||
for line in lines:
|
|
||||||
r = re.match(
|
|
||||||
R"Valve ([A-Z]+) has flow rate=([0-9]+); tunnels? leads? to valves? (.+)",
|
|
||||||
line,
|
|
||||||
)
|
|
||||||
assert r
|
|
||||||
|
|
||||||
g = r.groups()
|
pipes[g[0]] = Pipe(g[0], int(g[1]), g[2].split(", "))
|
||||||
|
|
||||||
pipes[g[0]] = Pipe(g[0], int(g[1]), g[2].split(", "))
|
# compute distances from one valve to any other
|
||||||
|
distances: dict[tuple[Pipe, Pipe], int] = {}
|
||||||
|
for pipe_1 in pipes.values():
|
||||||
|
distances.update(
|
||||||
|
{
|
||||||
|
(pipe_1, pipe_2): distance
|
||||||
|
for pipe_2, distance in breadth_first_search(pipes, pipe_1).items()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
# compute distances from one valve to any other
|
# valves with flow
|
||||||
distances: dict[tuple[Pipe, Pipe], int] = {}
|
relevant_pipes = frozenset(pipe for pipe in pipes.values() if pipe.flow > 0)
|
||||||
for pipe_1 in pipes.values():
|
|
||||||
distances.update(
|
|
||||||
{
|
|
||||||
(pipe_1, pipe_2): distance
|
|
||||||
for pipe_2, distance in breadth_first_search(pipes, pipe_1).items()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# valves with flow
|
# 1651, 1653
|
||||||
relevant_pipes = frozenset(pipe for pipe in pipes.values() if pipe.flow > 0)
|
yield part_1(pipes["AA"], 30, distances, relevant_pipes)
|
||||||
|
|
||||||
|
# 1707, 2223
|
||||||
# 1651, 1653
|
yield part_2(pipes["AA"], 26, distances, relevant_pipes)
|
||||||
print(part_1(pipes["AA"], 30, distances, relevant_pipes))
|
|
||||||
|
|
||||||
# 1707, 2223
|
|
||||||
print(part_2(pipes["AA"], 26, distances, relevant_pipes))
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import sys
|
from typing import Any, Iterator, Sequence, TypeAlias, TypeVar
|
||||||
from typing import Any, Iterator, Sequence, TypeVar
|
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from numpy.typing import NDArray
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
Tower: TypeAlias = NDArray[np.bool]
|
||||||
|
|
||||||
def print_tower(tower: np.ndarray, out: str = "#"):
|
|
||||||
|
def print_tower(tower: Tower, out: str = "#"):
|
||||||
print("-" * (tower.shape[1] + 2))
|
print("-" * (tower.shape[1] + 2))
|
||||||
non_empty = False
|
non_empty = False
|
||||||
for row in reversed(range(1, tower.shape[0])):
|
for row in reversed(range(1, tower.shape[0])):
|
||||||
@ -19,7 +21,7 @@ def print_tower(tower: np.ndarray, out: str = "#"):
|
|||||||
print("+" + "-" * tower.shape[1] + "+")
|
print("+" + "-" * tower.shape[1] + "+")
|
||||||
|
|
||||||
|
|
||||||
def tower_height(tower: np.ndarray) -> int:
|
def tower_height(tower: Tower) -> int:
|
||||||
return int(tower.shape[0] - tower[::-1, :].argmax(axis=0).min() - 1)
|
return int(tower.shape[0] - tower[::-1, :].argmax(axis=0).min() - 1)
|
||||||
|
|
||||||
|
|
||||||
@ -47,8 +49,8 @@ def build_tower(
|
|||||||
n_rocks: int,
|
n_rocks: int,
|
||||||
jets: str,
|
jets: str,
|
||||||
early_stop: bool = False,
|
early_stop: bool = False,
|
||||||
init: np.ndarray = np.ones(WIDTH, dtype=bool),
|
init: Tower = np.ones(WIDTH, dtype=bool),
|
||||||
) -> tuple[np.ndarray, int, int, dict[int, int]]:
|
) -> tuple[Tower, int, int, dict[int, int]]:
|
||||||
tower = EMPTY_BLOCKS.copy()
|
tower = EMPTY_BLOCKS.copy()
|
||||||
tower[0, :] = init
|
tower[0, :] = init
|
||||||
|
|
||||||
@ -97,26 +99,24 @@ def build_tower(
|
|||||||
return tower, rock_count, done_at.get((i_rock, i_jet), -1), heights
|
return tower, rock_count, done_at.get((i_rock, i_jet), -1), heights
|
||||||
|
|
||||||
|
|
||||||
line = sys.stdin.read().strip()
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
tower, *_ = build_tower(2022, input)
|
||||||
|
yield tower_height(tower)
|
||||||
|
|
||||||
tower, *_ = build_tower(2022, line)
|
TOTAL_ROCKS = 1_000_000_000_000
|
||||||
answer_1 = tower_height(tower)
|
_tower_1, n_rocks_1, prev_1, heights_1 = build_tower(TOTAL_ROCKS, input, True)
|
||||||
print(f"answer 1 is {answer_1}")
|
assert prev_1 > 0
|
||||||
|
|
||||||
TOTAL_ROCKS = 1_000_000_000_000
|
# 2767 1513
|
||||||
tower_1, n_rocks_1, prev_1, heights_1 = build_tower(TOTAL_ROCKS, line, True)
|
remaining_rocks = TOTAL_ROCKS - n_rocks_1
|
||||||
assert prev_1 > 0
|
n_repeat_rocks = n_rocks_1 - prev_1
|
||||||
|
n_repeat_towers = remaining_rocks // n_repeat_rocks
|
||||||
|
|
||||||
# 2767 1513
|
base_height = heights_1[prev_1]
|
||||||
remaining_rocks = TOTAL_ROCKS - n_rocks_1
|
repeat_height = heights_1[prev_1 + n_repeat_rocks - 1] - heights_1[prev_1]
|
||||||
n_repeat_rocks = n_rocks_1 - prev_1
|
remaining_height = (
|
||||||
n_repeat_towers = remaining_rocks // n_repeat_rocks
|
heights_1[prev_1 + remaining_rocks % n_repeat_rocks] - heights_1[prev_1]
|
||||||
|
)
|
||||||
|
|
||||||
base_height = heights_1[prev_1]
|
yield base_height + (n_repeat_towers + 1) * repeat_height + remaining_height
|
||||||
repeat_height = heights_1[prev_1 + n_repeat_rocks - 1] - heights_1[prev_1]
|
|
||||||
remaining_height = (
|
|
||||||
heights_1[prev_1 + remaining_rocks % n_repeat_rocks] - heights_1[prev_1]
|
|
||||||
)
|
|
||||||
|
|
||||||
answer_2 = base_height + (n_repeat_towers + 1) * repeat_height + remaining_height
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,53 +1,58 @@
|
|||||||
import sys
|
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
|
||||||
xyz = np.asarray(
|
|
||||||
[
|
|
||||||
tuple(int(x) for x in row.split(",")) # type: ignore
|
|
||||||
for row in sys.stdin.read().splitlines()
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
xyz = xyz - xyz.min(axis=0) + 1
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
xyz = np.asarray(
|
||||||
|
[
|
||||||
|
tuple(int(x) for x in row.split(",")) # type: ignore
|
||||||
|
for row in input.splitlines()
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
cubes = np.zeros(xyz.max(axis=0) + 3, dtype=bool)
|
xyz = xyz - xyz.min(axis=0) + 1
|
||||||
cubes[xyz[:, 0], xyz[:, 1], xyz[:, 2]] = True
|
|
||||||
|
|
||||||
n_dims = len(cubes.shape)
|
cubes = np.zeros(xyz.max(axis=0) + 3, dtype=bool)
|
||||||
|
cubes[xyz[:, 0], xyz[:, 1], xyz[:, 2]] = True
|
||||||
|
|
||||||
faces = [(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)]
|
faces = [(-1, 0, 0), (1, 0, 0), (0, -1, 0), (0, 1, 0), (0, 0, -1), (0, 0, 1)]
|
||||||
|
|
||||||
answer_1 = sum(
|
yield sum(
|
||||||
1 for x, y, z in xyz for dx, dy, dz in faces if not cubes[x + dx, y + dy, z + dz]
|
1
|
||||||
)
|
for x, y, z in xyz
|
||||||
print(f"answer 1 is {answer_1}")
|
for dx, dy, dz in faces
|
||||||
|
if not cubes[x + dx, y + dy, z + dz]
|
||||||
|
)
|
||||||
|
|
||||||
visited = np.zeros_like(cubes, dtype=bool)
|
visited = np.zeros_like(cubes, dtype=bool)
|
||||||
queue = [(0, 0, 0)]
|
queue = [(0, 0, 0)]
|
||||||
|
|
||||||
n_faces = 0
|
n_faces = 0
|
||||||
while queue:
|
while queue:
|
||||||
x, y, z = queue.pop(0)
|
x, y, z = queue.pop(0)
|
||||||
|
|
||||||
if visited[x, y, z]:
|
if visited[x, y, z]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
visited[x, y, z] = True
|
visited[x, y, z] = True
|
||||||
|
|
||||||
for dx, dy, dz in faces:
|
for dx, dy, dz in faces:
|
||||||
nx, ny, nz = x + dx, y + dy, z + dz
|
nx, ny, nz = x + dx, y + dy, z + dz
|
||||||
if not all(n >= 0 and n < cubes.shape[i] for i, n in enumerate((nx, ny, nz))):
|
if not all(
|
||||||
continue
|
n >= 0 and n < cubes.shape[i] for i, n in enumerate((nx, ny, nz))
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
if visited[nx, ny, nz]:
|
if visited[nx, ny, nz]:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if cubes[nx, ny, nz]:
|
if cubes[nx, ny, nz]:
|
||||||
n_faces += 1
|
n_faces += 1
|
||||||
else:
|
else:
|
||||||
queue.append((nx, ny, nz))
|
queue.append((nx, ny, nz))
|
||||||
print(f"answer 2 is {n_faces}")
|
|
||||||
|
yield n_faces
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import sys
|
|
||||||
from typing import Any, Iterator, Literal
|
from typing import Any, Iterator, Literal
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -64,29 +63,6 @@ def dominates(lhs: State, rhs: State):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
blueprints: list[dict[Reagent, IntOfReagent]] = []
|
|
||||||
for line in lines:
|
|
||||||
r: list[int] = parse.parse( # type: ignore
|
|
||||||
"Blueprint {}: "
|
|
||||||
"Each ore robot costs {:d} ore. "
|
|
||||||
"Each clay robot costs {:d} ore. "
|
|
||||||
"Each obsidian robot costs {:d} ore and {:d} clay. "
|
|
||||||
"Each geode robot costs {:d} ore and {:d} obsidian.",
|
|
||||||
line,
|
|
||||||
)
|
|
||||||
|
|
||||||
blueprints.append(
|
|
||||||
{
|
|
||||||
"ore": {"ore": r[1]},
|
|
||||||
"clay": {"ore": r[2]},
|
|
||||||
"obsidian": {"ore": r[3], "clay": r[4]},
|
|
||||||
"geode": {"ore": r[5], "obsidian": r[6]},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run(blueprint: dict[Reagent, dict[Reagent, int]], max_time: int) -> int:
|
def run(blueprint: dict[Reagent, dict[Reagent, int]], max_time: int) -> int:
|
||||||
# since we can only build one robot per time, we do not need more than X robots
|
# since we can only build one robot per time, we do not need more than X robots
|
||||||
# of type K where X is the maximum number of K required among all robots, e.g.,
|
# of type K where X is the maximum number of K required among all robots, e.g.,
|
||||||
@ -175,11 +151,31 @@ def run(blueprint: dict[Reagent, dict[Reagent, int]], max_time: int) -> int:
|
|||||||
return max(state.reagents["geode"] for state in state_after_t[max_time])
|
return max(state.reagents["geode"] for state in state_after_t[max_time])
|
||||||
|
|
||||||
|
|
||||||
answer_1 = sum(
|
class Solver(BaseSolver):
|
||||||
(i_blueprint + 1) * run(blueprint, 24)
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
for i_blueprint, blueprint in enumerate(blueprints)
|
blueprints: list[dict[Reagent, IntOfReagent]] = []
|
||||||
)
|
for line in input.splitlines():
|
||||||
print(f"answer 1 is {answer_1}")
|
r: list[int] = parse.parse( # type: ignore
|
||||||
|
"Blueprint {}: "
|
||||||
|
"Each ore robot costs {:d} ore. "
|
||||||
|
"Each clay robot costs {:d} ore. "
|
||||||
|
"Each obsidian robot costs {:d} ore and {:d} clay. "
|
||||||
|
"Each geode robot costs {:d} ore and {:d} obsidian.",
|
||||||
|
line,
|
||||||
|
)
|
||||||
|
|
||||||
answer_2 = run(blueprints[0], 32) * run(blueprints[1], 32) * run(blueprints[2], 32)
|
blueprints.append(
|
||||||
print(f"answer 2 is {answer_2}")
|
{
|
||||||
|
"ore": {"ore": r[1]},
|
||||||
|
"clay": {"ore": r[2]},
|
||||||
|
"obsidian": {"ore": r[3], "clay": r[4]},
|
||||||
|
"geode": {"ore": r[5], "obsidian": r[6]},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
yield sum(
|
||||||
|
(i_blueprint + 1) * run(blueprint, 24)
|
||||||
|
for i_blueprint, blueprint in enumerate(blueprints)
|
||||||
|
)
|
||||||
|
|
||||||
|
yield (run(blueprints[0], 32) * run(blueprints[1], 32) * run(blueprints[2], 32))
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import sys
|
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
@ -68,10 +67,9 @@ def decrypt(numbers: list[Number], key: int, rounds: int) -> int:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
numbers = [Number(int(x)) for i, x in enumerate(sys.stdin.readlines())]
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
numbers = [Number(int(x)) for x in input.splitlines()]
|
||||||
|
|
||||||
answer_1 = decrypt(numbers, 1, 1)
|
yield decrypt(numbers, 1, 1)
|
||||||
print(f"answer 1 is {answer_1}")
|
yield decrypt(numbers, 811589153, 10)
|
||||||
|
|
||||||
answer_2 = decrypt(numbers, 811589153, 10)
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import operator
|
import operator
|
||||||
import sys
|
|
||||||
from typing import Any, Callable, Iterator
|
from typing import Any, Callable, Iterator
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
@ -79,31 +78,31 @@ def invert(
|
|||||||
return monkeys
|
return monkeys
|
||||||
|
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = [line.strip() for line in input.splitlines()]
|
||||||
|
|
||||||
monkeys: dict[str, int | tuple[str, str, str]] = {}
|
monkeys: dict[str, int | tuple[str, str, str]] = {}
|
||||||
|
|
||||||
op_monkeys: set[str] = set()
|
op_monkeys: set[str] = set()
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
parts = line.split(":")
|
parts = line.split(":")
|
||||||
name = parts[0].strip()
|
name = parts[0].strip()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
value = int(parts[1].strip())
|
value = int(parts[1].strip())
|
||||||
monkeys[name] = value
|
monkeys[name] = value
|
||||||
except ValueError:
|
except ValueError:
|
||||||
op1, ope, op2 = parts[1].strip().split()
|
op1, ope, op2 = parts[1].strip().split()
|
||||||
monkeys[name] = (op1, ope, op2)
|
monkeys[name] = (op1, ope, op2)
|
||||||
|
|
||||||
op_monkeys.add(name)
|
op_monkeys.add(name)
|
||||||
|
|
||||||
|
yield compute(monkeys.copy(), "root")
|
||||||
|
|
||||||
answer_1 = compute(monkeys.copy(), "root")
|
# assume the second operand of 'root' can be computed, and the first one depends on
|
||||||
print(f"answer 1 is {answer_1}")
|
# humn, which is the case is my input and the test input
|
||||||
|
assert isinstance(monkeys["root"], tuple)
|
||||||
# assume the second operand of 'root' can be computed, and the first one depends on
|
p1, _, p2 = monkeys["root"] # type: ignore
|
||||||
# humn, which is the case is my input and the test input
|
yield compute(invert(monkeys, "humn", compute(monkeys.copy(), p2)), "humn")
|
||||||
p1, _, p2 = monkeys["root"] # type: ignore
|
|
||||||
answer_2 = compute(invert(monkeys, "humn", compute(monkeys.copy(), p2)), "humn")
|
|
||||||
print(f"answer 2 is {answer_2}")
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import re
|
import re
|
||||||
import sys
|
|
||||||
from typing import Any, Callable, Iterator
|
from typing import Any, Callable, Iterator
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@ -12,214 +11,233 @@ TILE_FROM_CHAR = {" ": VOID, ".": EMPTY, "#": WALL}
|
|||||||
SCORES = {"E": 0, "S": 1, "W": 2, "N": 3}
|
SCORES = {"E": 0, "S": 1, "W": 2, "N": 3}
|
||||||
|
|
||||||
|
|
||||||
board_map_s, direction_s = sys.stdin.read().split("\n\n")
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
board_map_s, direction_s = input.split("\n\n")
|
||||||
|
|
||||||
# board
|
# board
|
||||||
board_lines = board_map_s.splitlines()
|
board_lines = board_map_s.splitlines()
|
||||||
max_line = max(len(line) for line in board_lines)
|
max_line = max(len(line) for line in board_lines)
|
||||||
board = np.array(
|
board = np.array(
|
||||||
[
|
[
|
||||||
[TILE_FROM_CHAR[c] for c in row] + [VOID] * (max_line - len(row))
|
[TILE_FROM_CHAR[c] for c in row] + [VOID] * (max_line - len(row))
|
||||||
for row in board_map_s.splitlines()
|
for row in board_map_s.splitlines()
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
directions = [
|
directions = [
|
||||||
int(p1) if p2 else p1 for p1, p2 in re.findall(R"(([0-9])+|L|R)", direction_s)
|
int(p1) if p2 else p1
|
||||||
]
|
for p1, p2 in re.findall(R"(([0-9])+|L|R)", direction_s)
|
||||||
|
]
|
||||||
|
|
||||||
|
# find on each row and column the first and last non-void
|
||||||
|
row_first_non_void = np.argmax(board != VOID, axis=1)
|
||||||
|
row_last_non_void = (
|
||||||
|
board.shape[1] - np.argmax(board[:, ::-1] != VOID, axis=1) - 1
|
||||||
|
)
|
||||||
|
col_first_non_void = np.argmax(board != VOID, axis=0)
|
||||||
|
col_last_non_void = (
|
||||||
|
board.shape[0] - np.argmax(board[::-1, :] != VOID, axis=0) - 1
|
||||||
|
)
|
||||||
|
|
||||||
# find on each row and column the first and last non-void
|
faces = np.zeros_like(board)
|
||||||
row_first_non_void = np.argmax(board != VOID, axis=1)
|
size = np.gcd(board.shape[0], board.shape[1])
|
||||||
row_last_non_void = board.shape[1] - np.argmax(board[:, ::-1] != VOID, axis=1) - 1
|
for row in range(0, board.shape[0], size):
|
||||||
col_first_non_void = np.argmax(board != VOID, axis=0)
|
for col in range(row_first_non_void[row], row_last_non_void[row], size):
|
||||||
col_last_non_void = board.shape[0] - np.argmax(board[::-1, :] != VOID, axis=0) - 1
|
faces[row : row + size, col : col + size] = faces.max() + 1
|
||||||
|
|
||||||
|
SIZE = np.gcd(*board.shape)
|
||||||
|
|
||||||
faces = np.zeros_like(board)
|
# TODO: deduce this from the actual cube...
|
||||||
size = np.gcd(board.shape[0], board.shape[1])
|
faces_wrap: dict[int, dict[str, Callable[[int, int], tuple[int, int, str]]]]
|
||||||
for row in range(0, board.shape[0], size):
|
|
||||||
for col in range(row_first_non_void[row], row_last_non_void[row], size):
|
|
||||||
faces[row : row + size, col : col + size] = faces.max() + 1
|
|
||||||
|
|
||||||
SIZE = np.gcd(*board.shape)
|
if board.shape == (12, 16): # example
|
||||||
|
faces_wrap = {
|
||||||
|
1: {
|
||||||
|
"W": lambda y, x: (4, 4 + y, "S"), # 3N
|
||||||
|
"N": lambda y, x: (4, 11 - x, "S"), # 2N
|
||||||
|
"E": lambda y, x: (11 - y, 15, "W"), # 6E
|
||||||
|
},
|
||||||
|
2: {
|
||||||
|
"W": lambda y, x: (11, 19 - y, "N"), # 6S
|
||||||
|
"N": lambda y, x: (0, 11 - y, "S"), # 1N
|
||||||
|
"S": lambda y, x: (11, 11 - x, "N"), # 5S
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
"N": lambda y, x: (x - 4, 8, "E"), # 1W
|
||||||
|
"S": lambda y, x: (15 - x, 8, "E"), # 5W
|
||||||
|
},
|
||||||
|
4: {"E": lambda y, x: (8, 19 - y, "S")}, # 6N
|
||||||
|
5: {
|
||||||
|
"W": lambda y, x: (7, 15 - y, "N"), # 3S
|
||||||
|
"S": lambda y, x: (7, 11 - x, "N"), # 2S
|
||||||
|
},
|
||||||
|
6: {
|
||||||
|
"N": lambda y, x: (19 - x, 11, "W"), # 4E
|
||||||
|
"E": lambda y, x: (11 - y, 11, "W"), # 1E
|
||||||
|
"S": lambda y, x: (19 - x, 0, "E"), # 2W
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# TODO: deduce this from the actual cube...
|
|
||||||
faces_wrap: dict[int, dict[str, Callable[[int, int], tuple[int, int, str]]]]
|
|
||||||
|
|
||||||
if board.shape == (12, 16): # example
|
|
||||||
faces_wrap = {
|
|
||||||
1: {
|
|
||||||
"W": lambda y, x: (4, 4 + y, "S"), # 3N
|
|
||||||
"N": lambda y, x: (4, 11 - x, "S"), # 2N
|
|
||||||
"E": lambda y, x: (11 - y, 15, "W"), # 6E
|
|
||||||
},
|
|
||||||
2: {
|
|
||||||
"W": lambda y, x: (11, 19 - y, "N"), # 6S
|
|
||||||
"N": lambda y, x: (0, 11 - y, "S"), # 1N
|
|
||||||
"S": lambda y, x: (11, 11 - x, "N"), # 5S
|
|
||||||
},
|
|
||||||
3: {
|
|
||||||
"N": lambda y, x: (x - 4, 8, "E"), # 1W
|
|
||||||
"S": lambda y, x: (15 - x, 8, "E"), # 5W
|
|
||||||
},
|
|
||||||
4: {"E": lambda y, x: (8, 19 - y, "S")}, # 6N
|
|
||||||
5: {
|
|
||||||
"W": lambda y, x: (7, 15 - y, "N"), # 3S
|
|
||||||
"S": lambda y, x: (7, 11 - x, "N"), # 2S
|
|
||||||
},
|
|
||||||
6: {
|
|
||||||
"N": lambda y, x: (19 - x, 11, "W"), # 4E
|
|
||||||
"E": lambda y, x: (11 - y, 11, "W"), # 1E
|
|
||||||
"S": lambda y, x: (19 - x, 0, "E"), # 2W
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
else:
|
|
||||||
faces_wrap = {
|
|
||||||
1: {
|
|
||||||
"W": lambda y, x: (3 * SIZE - y - 1, 0, "E"), # 4W
|
|
||||||
"N": lambda y, x: (2 * SIZE + x, 0, "E"), # 6W
|
|
||||||
},
|
|
||||||
2: {
|
|
||||||
"N": lambda y, x: (4 * SIZE - 1, x - 2 * SIZE, "N"), # 6S
|
|
||||||
"E": lambda y, x: (3 * SIZE - y - 1, 2 * SIZE - 1, "W"), # 5E
|
|
||||||
"S": lambda y, x: (x - SIZE, 2 * SIZE - 1, "W"), # 3E
|
|
||||||
},
|
|
||||||
3: {
|
|
||||||
"W": lambda y, x: (2 * SIZE, y - SIZE, "S"), # 4N
|
|
||||||
"E": lambda y, x: (SIZE - 1, SIZE + y, "N"), # 2S
|
|
||||||
},
|
|
||||||
4: {
|
|
||||||
"W": lambda y, x: (3 * SIZE - y - 1, SIZE, "E"), # 1W
|
|
||||||
"N": lambda y, x: (SIZE + x, SIZE, "E"), # 3W
|
|
||||||
},
|
|
||||||
5: {
|
|
||||||
"E": lambda y, x: (3 * SIZE - y - 1, 3 * SIZE - 1, "W"), # 2E
|
|
||||||
"S": lambda y, x: (2 * SIZE + x, SIZE - 1, "W"), # 6E
|
|
||||||
},
|
|
||||||
6: {
|
|
||||||
"W": lambda y, x: (0, y - 2 * SIZE, "S"), # 1N
|
|
||||||
"E": lambda y, x: (3 * SIZE - 1, y - 2 * SIZE, "N"), # 5S
|
|
||||||
"S": lambda y, x: (0, x + 2 * SIZE, "S"), # 2N
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_part_1(y0: int, x0: int, r0: str) -> tuple[int, int, str]:
|
|
||||||
if r0 == "E":
|
|
||||||
return y0, row_first_non_void[y0], r0
|
|
||||||
elif r0 == "S":
|
|
||||||
return col_first_non_void[x0], x0, r0
|
|
||||||
elif r0 == "W":
|
|
||||||
return y0, row_last_non_void[y0], r0
|
|
||||||
elif r0 == "N":
|
|
||||||
return col_last_non_void[x0], x0, r0
|
|
||||||
|
|
||||||
assert False
|
|
||||||
|
|
||||||
|
|
||||||
def wrap_part_2(y0: int, x0: int, r0: str) -> tuple[int, int, str]:
|
|
||||||
cube = faces[y0, x0]
|
|
||||||
assert r0 in faces_wrap[cube]
|
|
||||||
return faces_wrap[cube][r0](y0, x0)
|
|
||||||
|
|
||||||
|
|
||||||
def run(wrap: Callable[[int, int, str], tuple[int, int, str]]) -> tuple[int, int, str]:
|
|
||||||
y0 = 0
|
|
||||||
x0 = np.where(board[0] == EMPTY)[0][0]
|
|
||||||
r0 = "E"
|
|
||||||
|
|
||||||
for direction in directions:
|
|
||||||
if isinstance(direction, int):
|
|
||||||
while direction > 0:
|
|
||||||
if r0 == "E":
|
|
||||||
xi = np.where(board[y0, x0 + 1 : x0 + direction + 1] == WALL)[0]
|
|
||||||
if len(xi):
|
|
||||||
x0 = x0 + xi[0]
|
|
||||||
direction = 0
|
|
||||||
elif (
|
|
||||||
x0 + direction < board.shape[1]
|
|
||||||
and board[y0, x0 + direction] == EMPTY
|
|
||||||
):
|
|
||||||
x0 = x0 + direction
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
|
||||||
if board[y0_t, x0_t] == WALL:
|
|
||||||
x0 = row_last_non_void[y0]
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
direction = direction - (row_last_non_void[y0] - x0) - 1
|
|
||||||
y0, x0, r0 = y0_t, x0_t, r0_t
|
|
||||||
elif r0 == "S":
|
|
||||||
yi = np.where(board[y0 + 1 : y0 + direction + 1, x0] == WALL)[0]
|
|
||||||
if len(yi):
|
|
||||||
y0 = y0 + yi[0]
|
|
||||||
direction = 0
|
|
||||||
elif (
|
|
||||||
y0 + direction < board.shape[0]
|
|
||||||
and board[y0 + direction, x0] == EMPTY
|
|
||||||
):
|
|
||||||
y0 = y0 + direction
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
|
||||||
if board[y0_t, x0_t] == WALL:
|
|
||||||
y0 = col_last_non_void[x0]
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
direction = direction - (col_last_non_void[x0] - y0) - 1
|
|
||||||
y0, x0, r0 = y0_t, x0_t, r0_t
|
|
||||||
elif r0 == "W":
|
|
||||||
left = max(x0 - direction - 1, 0)
|
|
||||||
xi = np.where(board[y0, left:x0] == WALL)[0]
|
|
||||||
if len(xi):
|
|
||||||
x0 = left + xi[-1] + 1
|
|
||||||
direction = 0
|
|
||||||
elif x0 - direction >= 0 and board[y0, x0 - direction] == EMPTY:
|
|
||||||
x0 = x0 - direction
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
|
||||||
if board[y0_t, x0_t] == WALL:
|
|
||||||
x0 = row_first_non_void[y0]
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
direction = direction - (x0 - row_first_non_void[y0]) - 1
|
|
||||||
y0, x0, r0 = y0_t, x0_t, r0_t
|
|
||||||
elif r0 == "N":
|
|
||||||
top = max(y0 - direction - 1, 0)
|
|
||||||
yi = np.where(board[top:y0, x0] == WALL)[0]
|
|
||||||
if len(yi):
|
|
||||||
y0 = top + yi[-1] + 1
|
|
||||||
direction = 0
|
|
||||||
elif y0 - direction >= 0 and board[y0 - direction, x0] == EMPTY:
|
|
||||||
y0 = y0 - direction
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
|
||||||
if board[y0_t, x0_t] == WALL:
|
|
||||||
y0 = col_first_non_void[x0]
|
|
||||||
direction = 0
|
|
||||||
else:
|
|
||||||
direction = direction - (y0 - col_first_non_void[x0]) - 1
|
|
||||||
y0, x0, r0 = y0_t, x0_t, r0_t
|
|
||||||
else:
|
else:
|
||||||
r0 = {
|
faces_wrap = {
|
||||||
"E": {"L": "N", "R": "S"},
|
1: {
|
||||||
"N": {"L": "W", "R": "E"},
|
"W": lambda y, x: (3 * SIZE - y - 1, 0, "E"), # 4W
|
||||||
"W": {"L": "S", "R": "N"},
|
"N": lambda y, x: (2 * SIZE + x, 0, "E"), # 6W
|
||||||
"S": {"L": "E", "R": "W"},
|
},
|
||||||
}[r0][direction]
|
2: {
|
||||||
|
"N": lambda y, x: (4 * SIZE - 1, x - 2 * SIZE, "N"), # 6S
|
||||||
|
"E": lambda y, x: (3 * SIZE - y - 1, 2 * SIZE - 1, "W"), # 5E
|
||||||
|
"S": lambda y, x: (x - SIZE, 2 * SIZE - 1, "W"), # 3E
|
||||||
|
},
|
||||||
|
3: {
|
||||||
|
"W": lambda y, x: (2 * SIZE, y - SIZE, "S"), # 4N
|
||||||
|
"E": lambda y, x: (SIZE - 1, SIZE + y, "N"), # 2S
|
||||||
|
},
|
||||||
|
4: {
|
||||||
|
"W": lambda y, x: (3 * SIZE - y - 1, SIZE, "E"), # 1W
|
||||||
|
"N": lambda y, x: (SIZE + x, SIZE, "E"), # 3W
|
||||||
|
},
|
||||||
|
5: {
|
||||||
|
"E": lambda y, x: (3 * SIZE - y - 1, 3 * SIZE - 1, "W"), # 2E
|
||||||
|
"S": lambda y, x: (2 * SIZE + x, SIZE - 1, "W"), # 6E
|
||||||
|
},
|
||||||
|
6: {
|
||||||
|
"W": lambda y, x: (0, y - 2 * SIZE, "S"), # 1N
|
||||||
|
"E": lambda y, x: (3 * SIZE - 1, y - 2 * SIZE, "N"), # 5S
|
||||||
|
"S": lambda y, x: (0, x + 2 * SIZE, "S"), # 2N
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
return y0, x0, r0
|
def wrap_part_1(y0: int, x0: int, r0: str) -> tuple[int, int, str]:
|
||||||
|
if r0 == "E":
|
||||||
|
return y0, row_first_non_void[y0], r0
|
||||||
|
elif r0 == "S":
|
||||||
|
return col_first_non_void[x0], x0, r0
|
||||||
|
elif r0 == "W":
|
||||||
|
return y0, row_last_non_void[y0], r0
|
||||||
|
elif r0 == "N":
|
||||||
|
return col_last_non_void[x0], x0, r0
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
||||||
y1, x1, r1 = run(wrap_part_1)
|
def wrap_part_2(y0: int, x0: int, r0: str) -> tuple[int, int, str]:
|
||||||
answer_1 = 1000 * (1 + y1) + 4 * (1 + x1) + SCORES[r1]
|
cube = faces[y0, x0]
|
||||||
print(f"answer 1 is {answer_1}")
|
assert r0 in faces_wrap[cube]
|
||||||
|
return faces_wrap[cube][r0](y0, x0)
|
||||||
|
|
||||||
y2, x2, r2 = run(wrap_part_2)
|
def run(
|
||||||
answer_2 = 1000 * (1 + y2) + 4 * (1 + x2) + SCORES[r2]
|
wrap: Callable[[int, int, str], tuple[int, int, str]],
|
||||||
print(f"answer 2 is {answer_2}")
|
) -> tuple[int, int, str]:
|
||||||
|
y0 = 0
|
||||||
|
x0 = np.where(board[0] == EMPTY)[0][0]
|
||||||
|
r0 = "E"
|
||||||
|
|
||||||
|
for direction in directions:
|
||||||
|
if isinstance(direction, int):
|
||||||
|
while direction > 0:
|
||||||
|
if r0 == "E":
|
||||||
|
xi = np.where(
|
||||||
|
board[y0, x0 + 1 : x0 + direction + 1] == WALL
|
||||||
|
)[0]
|
||||||
|
if len(xi):
|
||||||
|
x0 = x0 + xi[0]
|
||||||
|
direction = 0
|
||||||
|
elif (
|
||||||
|
x0 + direction < board.shape[1]
|
||||||
|
and board[y0, x0 + direction] == EMPTY
|
||||||
|
):
|
||||||
|
x0 = x0 + direction
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
||||||
|
if board[y0_t, x0_t] == WALL:
|
||||||
|
x0 = row_last_non_void[y0]
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
direction = (
|
||||||
|
direction - (row_last_non_void[y0] - x0) - 1
|
||||||
|
)
|
||||||
|
y0, x0, r0 = y0_t, x0_t, r0_t
|
||||||
|
elif r0 == "S":
|
||||||
|
yi = np.where(
|
||||||
|
board[y0 + 1 : y0 + direction + 1, x0] == WALL
|
||||||
|
)[0]
|
||||||
|
if len(yi):
|
||||||
|
y0 = y0 + yi[0]
|
||||||
|
direction = 0
|
||||||
|
elif (
|
||||||
|
y0 + direction < board.shape[0]
|
||||||
|
and board[y0 + direction, x0] == EMPTY
|
||||||
|
):
|
||||||
|
y0 = y0 + direction
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
||||||
|
if board[y0_t, x0_t] == WALL:
|
||||||
|
y0 = col_last_non_void[x0]
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
direction = (
|
||||||
|
direction - (col_last_non_void[x0] - y0) - 1
|
||||||
|
)
|
||||||
|
y0, x0, r0 = y0_t, x0_t, r0_t
|
||||||
|
elif r0 == "W":
|
||||||
|
left = max(x0 - direction - 1, 0)
|
||||||
|
xi = np.where(board[y0, left:x0] == WALL)[0]
|
||||||
|
if len(xi):
|
||||||
|
x0 = left + xi[-1] + 1
|
||||||
|
direction = 0
|
||||||
|
elif (
|
||||||
|
x0 - direction >= 0
|
||||||
|
and board[y0, x0 - direction] == EMPTY
|
||||||
|
):
|
||||||
|
x0 = x0 - direction
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
||||||
|
if board[y0_t, x0_t] == WALL:
|
||||||
|
x0 = row_first_non_void[y0]
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
direction = (
|
||||||
|
direction - (x0 - row_first_non_void[y0]) - 1
|
||||||
|
)
|
||||||
|
y0, x0, r0 = y0_t, x0_t, r0_t
|
||||||
|
elif r0 == "N":
|
||||||
|
top = max(y0 - direction - 1, 0)
|
||||||
|
yi = np.where(board[top:y0, x0] == WALL)[0]
|
||||||
|
if len(yi):
|
||||||
|
y0 = top + yi[-1] + 1
|
||||||
|
direction = 0
|
||||||
|
elif (
|
||||||
|
y0 - direction >= 0
|
||||||
|
and board[y0 - direction, x0] == EMPTY
|
||||||
|
):
|
||||||
|
y0 = y0 - direction
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
y0_t, x0_t, r0_t = wrap(y0, x0, r0)
|
||||||
|
if board[y0_t, x0_t] == WALL:
|
||||||
|
y0 = col_first_non_void[x0]
|
||||||
|
direction = 0
|
||||||
|
else:
|
||||||
|
direction = (
|
||||||
|
direction - (y0 - col_first_non_void[x0]) - 1
|
||||||
|
)
|
||||||
|
y0, x0, r0 = y0_t, x0_t, r0_t
|
||||||
|
else:
|
||||||
|
r0 = {
|
||||||
|
"E": {"L": "N", "R": "S"},
|
||||||
|
"N": {"L": "W", "R": "E"},
|
||||||
|
"W": {"L": "S", "R": "N"},
|
||||||
|
"S": {"L": "E", "R": "W"},
|
||||||
|
}[r0][direction]
|
||||||
|
|
||||||
|
return y0, x0, r0
|
||||||
|
|
||||||
|
y1, x1, r1 = run(wrap_part_1)
|
||||||
|
yield 1000 * (1 + y1) + 4 * (1 + x1) + SCORES[r1]
|
||||||
|
|
||||||
|
y2, x2, r2 = run(wrap_part_2)
|
||||||
|
yield 1000 * (1 + y2) + 4 * (1 + x2) + SCORES[r2]
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import itertools
|
import itertools
|
||||||
import sys
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
@ -21,7 +20,7 @@ DIRECTIONS: Directions = [
|
|||||||
|
|
||||||
|
|
||||||
def min_max_yx(positions: set[tuple[int, int]]) -> tuple[int, int, int, int]:
|
def min_max_yx(positions: set[tuple[int, int]]) -> tuple[int, int, int, int]:
|
||||||
ys, xs = {y for y, x in positions}, {x for y, x in positions}
|
ys, xs = {y for y, _x in positions}, {x for _y, x in positions}
|
||||||
return min(ys), min(xs), max(ys), max(xs)
|
return min(ys), min(xs), max(ys), max(xs)
|
||||||
|
|
||||||
|
|
||||||
@ -72,35 +71,38 @@ def round(
|
|||||||
directions.append(directions.pop(0))
|
directions.append(directions.pop(0))
|
||||||
|
|
||||||
|
|
||||||
POSITIONS = {
|
class Solver(BaseSolver):
|
||||||
(i, j)
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
for i, row in enumerate(sys.stdin.read().splitlines())
|
POSITIONS = {
|
||||||
for j, col in enumerate(row)
|
(i, j)
|
||||||
if col == "#"
|
for i, row in enumerate(input.splitlines())
|
||||||
}
|
for j, col in enumerate(row)
|
||||||
|
if col == "#"
|
||||||
|
}
|
||||||
|
|
||||||
# === part 1 ===
|
# === part 1 ===
|
||||||
|
|
||||||
p1, d1 = POSITIONS.copy(), DIRECTIONS.copy()
|
p1, d1 = POSITIONS.copy(), DIRECTIONS.copy()
|
||||||
for r in range(10):
|
for _ in range(10):
|
||||||
round(p1, d1)
|
round(p1, d1)
|
||||||
|
|
||||||
min_y, min_x, max_y, max_x = min_max_yx(p1)
|
min_y, min_x, max_y, max_x = min_max_yx(p1)
|
||||||
answer_1 = sum(
|
yield sum(
|
||||||
(y, x) not in p1 for y in range(min_y, max_y + 1) for x in range(min_x, max_x + 1)
|
(y, x) not in p1
|
||||||
)
|
for y in range(min_y, max_y + 1)
|
||||||
print(f"answer 1 is {answer_1}")
|
for x in range(min_x, max_x + 1)
|
||||||
|
)
|
||||||
|
|
||||||
# === part 2 ===
|
# === part 2 ===
|
||||||
|
|
||||||
p2, d2 = POSITIONS.copy(), DIRECTIONS.copy()
|
p2, d2 = POSITIONS.copy(), DIRECTIONS.copy()
|
||||||
answer_2 = 0
|
answer_2 = 0
|
||||||
while True:
|
while True:
|
||||||
answer_2 += 1
|
answer_2 += 1
|
||||||
backup = p2.copy()
|
backup = p2.copy()
|
||||||
round(p2, d2)
|
round(p2, d2)
|
||||||
|
|
||||||
if backup == p2:
|
if backup == p2:
|
||||||
break
|
break
|
||||||
|
|
||||||
print(f"answer 2 is {answer_2}")
|
yield answer_2
|
||||||
|
@ -1,101 +1,117 @@
|
|||||||
import heapq
|
import heapq
|
||||||
import math
|
import math
|
||||||
import sys
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
winds = {
|
class Solver(BaseSolver):
|
||||||
(i - 1, j - 1, lines[i][j])
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
for i in range(1, len(lines) - 1)
|
lines = [line.strip() for line in input.splitlines()]
|
||||||
for j in range(1, len(lines[i]) - 1)
|
|
||||||
if lines[i][j] != "."
|
|
||||||
}
|
|
||||||
|
|
||||||
n_rows, n_cols = len(lines) - 2, len(lines[0]) - 2
|
winds = {
|
||||||
CYCLE = math.lcm(n_rows, n_cols)
|
(i - 1, j - 1, lines[i][j])
|
||||||
|
for i in range(1, len(lines) - 1)
|
||||||
|
for j in range(1, len(lines[i]) - 1)
|
||||||
|
if lines[i][j] != "."
|
||||||
|
}
|
||||||
|
|
||||||
east_winds = [{j for j in range(n_cols) if (i, j, ">") in winds} for i in range(n_rows)]
|
n_rows, n_cols = len(lines) - 2, len(lines[0]) - 2
|
||||||
west_winds = [{j for j in range(n_cols) if (i, j, "<") in winds} for i in range(n_rows)]
|
CYCLE = math.lcm(n_rows, n_cols)
|
||||||
north_winds = [
|
|
||||||
{i for i in range(n_rows) if (i, j, "^") in winds} for j in range(n_cols)
|
|
||||||
]
|
|
||||||
south_winds = [
|
|
||||||
{i for i in range(n_rows) if (i, j, "v") in winds} for j in range(n_cols)
|
|
||||||
]
|
|
||||||
|
|
||||||
|
east_winds = [
|
||||||
|
{j for j in range(n_cols) if (i, j, ">") in winds} for i in range(n_rows)
|
||||||
|
]
|
||||||
|
west_winds = [
|
||||||
|
{j for j in range(n_cols) if (i, j, "<") in winds} for i in range(n_rows)
|
||||||
|
]
|
||||||
|
north_winds = [
|
||||||
|
{i for i in range(n_rows) if (i, j, "^") in winds} for j in range(n_cols)
|
||||||
|
]
|
||||||
|
south_winds = [
|
||||||
|
{i for i in range(n_rows) if (i, j, "v") in winds} for j in range(n_cols)
|
||||||
|
]
|
||||||
|
|
||||||
def run(start: tuple[int, int], start_cycle: int, end: tuple[int, int]):
|
def run(start: tuple[int, int], start_cycle: int, end: tuple[int, int]):
|
||||||
def heuristic(y: int, x: int) -> int:
|
def heuristic(y: int, x: int) -> int:
|
||||||
return abs(end[0] - y) + abs(end[1] - x)
|
return abs(end[0] - y) + abs(end[1] - x)
|
||||||
|
|
||||||
# (distance + heuristic, distance, (start_pos, cycle))
|
# (distance + heuristic, distance, (start_pos, cycle))
|
||||||
queue = [(heuristic(start[0], start[1]), 0, ((start[0], start[1]), start_cycle))]
|
queue = [
|
||||||
visited: set[tuple[tuple[int, int], int]] = set()
|
(heuristic(start[0], start[1]), 0, ((start[0], start[1]), start_cycle))
|
||||||
distances: dict[tuple[int, int], dict[int, int]] = defaultdict(lambda: {})
|
]
|
||||||
|
visited: set[tuple[tuple[int, int], int]] = set()
|
||||||
|
distances: dict[tuple[int, int], dict[int, int]] = defaultdict(lambda: {})
|
||||||
|
|
||||||
while queue:
|
while queue:
|
||||||
_, distance, ((y, x), cycle) = heapq.heappop(queue)
|
_, distance, ((y, x), cycle) = heapq.heappop(queue)
|
||||||
|
|
||||||
if ((y, x), cycle) in visited:
|
if ((y, x), cycle) in visited:
|
||||||
continue
|
|
||||||
|
|
||||||
distances[y, x][cycle] = distance
|
|
||||||
|
|
||||||
visited.add(((y, x), cycle))
|
|
||||||
|
|
||||||
if (y, x) == (end[0], end[1]):
|
|
||||||
break
|
|
||||||
|
|
||||||
for dy, dx in (0, 0), (-1, 0), (1, 0), (0, -1), (0, 1):
|
|
||||||
ty = y + dy
|
|
||||||
tx = x + dx
|
|
||||||
|
|
||||||
n_cycle = (cycle + 1) % CYCLE
|
|
||||||
|
|
||||||
if (ty, tx) == end:
|
|
||||||
heapq.heappush(queue, (distance + 1, distance + 1, ((ty, tx), n_cycle)))
|
|
||||||
break
|
|
||||||
|
|
||||||
if ((ty, tx), n_cycle) in visited:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if (ty, tx) != start and (ty < 0 or tx < 0 or ty >= n_rows or tx >= n_cols):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if (ty, tx) != start:
|
|
||||||
if (ty - n_cycle) % n_rows in south_winds[tx]:
|
|
||||||
continue
|
|
||||||
if (ty + n_cycle) % n_rows in north_winds[tx]:
|
|
||||||
continue
|
|
||||||
if (tx + n_cycle) % n_cols in west_winds[ty]:
|
|
||||||
continue
|
|
||||||
if (tx - n_cycle) % n_cols in east_winds[ty]:
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
heapq.heappush(
|
distances[y, x][cycle] = distance
|
||||||
queue,
|
|
||||||
((heuristic(ty, tx) + distance + 1, distance + 1, ((ty, tx), n_cycle))),
|
|
||||||
)
|
|
||||||
|
|
||||||
return distances, next(iter(distances[end].values()))
|
visited.add(((y, x), cycle))
|
||||||
|
|
||||||
|
if (y, x) == (end[0], end[1]):
|
||||||
|
break
|
||||||
|
|
||||||
start = (
|
for dy, dx in (0, 0), (-1, 0), (1, 0), (0, -1), (0, 1):
|
||||||
-1,
|
ty = y + dy
|
||||||
next(j for j in range(1, len(lines[0]) - 1) if lines[0][j] == ".") - 1,
|
tx = x + dx
|
||||||
)
|
|
||||||
end = (
|
|
||||||
n_rows,
|
|
||||||
next(j for j in range(1, len(lines[-1]) - 1) if lines[-1][j] == ".") - 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
distances_1, forward_1 = run(start, 0, end)
|
n_cycle = (cycle + 1) % CYCLE
|
||||||
print(f"answer 1 is {forward_1}")
|
|
||||||
|
|
||||||
distances_2, return_1 = run(end, next(iter(distances_1[end].keys())), start)
|
if (ty, tx) == end:
|
||||||
distances_3, forward_2 = run(start, next(iter(distances_2[start].keys())), end)
|
heapq.heappush(
|
||||||
print(f"answer 2 is {forward_1 + return_1 + forward_2}")
|
queue, (distance + 1, distance + 1, ((ty, tx), n_cycle))
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
if ((ty, tx), n_cycle) in visited:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (ty, tx) != start and (
|
||||||
|
ty < 0 or tx < 0 or ty >= n_rows or tx >= n_cols
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (ty, tx) != start:
|
||||||
|
if (ty - n_cycle) % n_rows in south_winds[tx]:
|
||||||
|
continue
|
||||||
|
if (ty + n_cycle) % n_rows in north_winds[tx]:
|
||||||
|
continue
|
||||||
|
if (tx + n_cycle) % n_cols in west_winds[ty]:
|
||||||
|
continue
|
||||||
|
if (tx - n_cycle) % n_cols in east_winds[ty]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
heapq.heappush(
|
||||||
|
queue,
|
||||||
|
(
|
||||||
|
(
|
||||||
|
heuristic(ty, tx) + distance + 1,
|
||||||
|
distance + 1,
|
||||||
|
((ty, tx), n_cycle),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return distances, next(iter(distances[end].values()))
|
||||||
|
|
||||||
|
start = (
|
||||||
|
-1,
|
||||||
|
next(j for j in range(1, len(lines[0]) - 1) if lines[0][j] == ".") - 1,
|
||||||
|
)
|
||||||
|
end = (
|
||||||
|
n_rows,
|
||||||
|
next(j for j in range(1, len(lines[-1]) - 1) if lines[-1][j] == ".") - 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
distances_1, forward_1 = run(start, 0, end)
|
||||||
|
yield forward_1
|
||||||
|
|
||||||
|
distances_2, return_1 = run(end, next(iter(distances_1[end].keys())), start)
|
||||||
|
_distances_3, forward_2 = run(start, next(iter(distances_2[start].keys())), end)
|
||||||
|
yield forward_1 + return_1 + forward_2
|
||||||
|
@ -1,30 +1,28 @@
|
|||||||
import sys
|
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
|
||||||
from ..base import BaseSolver
|
from ..base import BaseSolver
|
||||||
|
|
||||||
lines = sys.stdin.read().splitlines()
|
|
||||||
|
|
||||||
coeffs = {"2": 2, "1": 1, "0": 0, "-": -1, "=": -2}
|
class Solver(BaseSolver):
|
||||||
|
def solve(self, input: str) -> Iterator[Any]:
|
||||||
|
lines = [line.strip() for line in input.splitlines()]
|
||||||
|
|
||||||
|
coeffs = {"2": 2, "1": 1, "0": 0, "-": -1, "=": -2}
|
||||||
|
|
||||||
def snafu2number(number: str) -> int:
|
def snafu2number(number: str) -> int:
|
||||||
value = 0
|
value = 0
|
||||||
for c in number:
|
for c in number:
|
||||||
value *= 5
|
value *= 5
|
||||||
value += coeffs[c]
|
value += coeffs[c]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def number2snafu(number: int) -> str:
|
||||||
|
values = ["0", "1", "2", "=", "-"]
|
||||||
|
res = ""
|
||||||
|
while number > 0:
|
||||||
|
mod = number % 5
|
||||||
|
res = res + values[mod]
|
||||||
|
number = number // 5 + int(mod >= 3)
|
||||||
|
return "".join(reversed(res))
|
||||||
|
|
||||||
def number2snafu(number: int) -> str:
|
yield number2snafu(sum(map(snafu2number, lines)))
|
||||||
values = ["0", "1", "2", "=", "-"]
|
|
||||||
res = ""
|
|
||||||
while number > 0:
|
|
||||||
mod = number % 5
|
|
||||||
res = res + values[mod]
|
|
||||||
number = number // 5 + int(mod >= 3)
|
|
||||||
return "".join(reversed(res))
|
|
||||||
|
|
||||||
|
|
||||||
answer_1 = number2snafu(sum(map(snafu2number, lines)))
|
|
||||||
print(f"answer 1 is {answer_1}")
|
|
||||||
|
@ -179,7 +179,7 @@ def main():
|
|||||||
start = datetime.now()
|
start = datetime.now()
|
||||||
last = start
|
last = start
|
||||||
|
|
||||||
it = solver.solve(data.strip())
|
it = solver.solve(data.rstrip())
|
||||||
|
|
||||||
if it is None:
|
if it is None:
|
||||||
solver.logger.error(f"no implementation for {year} day {day}")
|
solver.logger.error(f"no implementation for {year} day {day}")
|
||||||
|
Loading…
Reference in New Issue
Block a user