Clean 2022.

This commit is contained in:
Mikaël Capelle 2023-12-09 09:54:53 +01:00
parent 855efeb0aa
commit 8a0412f926
25 changed files with 27 additions and 94 deletions

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
blocks = sys.stdin.read().split("\n\n") blocks = sys.stdin.read().split("\n\n")

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
lines = sys.stdin.read().splitlines() lines = sys.stdin.read().splitlines()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import copy import copy
import sys import sys
from functools import reduce from functools import reduce
@ -7,7 +5,6 @@ from typing import Callable, Final, Mapping, Sequence
class Monkey: class Monkey:
id: Final[int] id: Final[int]
items: Final[Sequence[int]] items: Final[Sequence[int]]
worry_fn: Final[Callable[[int], int]] worry_fn: Final[Callable[[int], int]]
@ -97,8 +94,7 @@ def run(
# number of inspects # number of inspects
inspects = {monkey: 0 for monkey in monkeys} inspects = {monkey: 0 for monkey in monkeys}
for round in range(n_rounds): for _ in range(n_rounds):
for monkey in monkeys: for monkey in monkeys:
for item in items[monkey]: for item in items[monkey]:
inspects[monkey] += 1 inspects[monkey] += 1

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import heapq import heapq
import sys import sys
from typing import Callable, Iterator, TypeVar from typing import Callable, Iterator, TypeVar
@ -44,7 +42,6 @@ def dijkstra(
visited.add(current) visited.add(current)
for neighbor in neighbors(current): for neighbor in neighbors(current):
if neighbor in visited: if neighbor in visited:
continue continue
@ -60,7 +57,6 @@ def dijkstra(
def make_path(parents: dict[Node, Node], start: Node, end: Node) -> list[Node] | None: def make_path(parents: dict[Node, Node], start: Node, end: Node) -> list[Node] | None:
if end not in parents: if end not in parents:
return None return None
@ -109,7 +105,6 @@ def neighbors(
(c_row, c_col - 1), (c_row, c_col - 1),
(c_row, c_col + 1), (c_row, c_col + 1),
): ):
if not (n_row >= 0 and n_row < n_rows and n_col >= 0 and n_col < n_cols): if not (n_row >= 0 and n_row < n_rows and n_col >= 0 and n_col < n_cols):
continue continue

View File

@ -1,27 +1,27 @@
# -*- encoding: utf-8 -*-
import json import json
import sys import sys
from functools import cmp_to_key from functools import cmp_to_key
from typing import TypeAlias, cast
blocks = sys.stdin.read().strip().split("\n\n") blocks = sys.stdin.read().strip().split("\n\n")
pairs = [tuple(json.loads(p) for p in block.split("\n")) for block in blocks] pairs = [tuple(json.loads(p) for p in block.split("\n")) for block in blocks]
Packet: TypeAlias = list[int | list["Packet"]]
def compare(lhs: list[int | list], rhs: list[int | list]) -> int:
def compare(lhs: Packet, rhs: Packet) -> int:
for lhs_a, rhs_a in zip(lhs, rhs): for lhs_a, rhs_a in zip(lhs, rhs):
if isinstance(lhs_a, int) and isinstance(rhs_a, int): if isinstance(lhs_a, int) and isinstance(rhs_a, int):
if lhs_a != rhs_a: if lhs_a != rhs_a:
return rhs_a - lhs_a return rhs_a - lhs_a
else: else:
if not isinstance(lhs_a, list): if not isinstance(lhs_a, list):
lhs_a = [lhs_a] lhs_a = [lhs_a] # type: ignore
elif not isinstance(rhs_a, list): elif not isinstance(rhs_a, list):
rhs_a = [rhs_a] rhs_a = [rhs_a] # type: ignore
assert isinstance(rhs_a, list) and isinstance(lhs_a, list) assert isinstance(rhs_a, list) and isinstance(lhs_a, list)
r = compare(lhs_a, rhs_a) r = compare(cast(Packet, lhs_a), cast(Packet, rhs_a))
if r != 0: if r != 0:
return r return r

View File

@ -1,7 +1,4 @@
# -*- encoding: utf-8 -*-
import sys import sys
from collections import defaultdict
from enum import Enum, auto from enum import Enum, auto
from typing import Callable, cast from typing import Callable, cast
@ -23,10 +20,10 @@ def print_blocks(blocks: dict[tuple[int, int], Cell]):
blocks: Set of blocks to print. blocks: Set of blocks to print.
""" """
x_min, y_min, x_max, y_max = ( x_min, y_min, x_max, y_max = (
min(x for x, y in blocks), min(x for x, _ in blocks),
0, 0,
max(x for x, y in blocks), max(x for x, _ in blocks),
max(y for x, y in blocks), max(y for _, y in blocks),
) )
for y in range(y_min, y_max + 1): for y in range(y_min, y_max + 1):
@ -56,13 +53,12 @@ def flow(
The input blocks. The input blocks.
""" """
y_max = max(y for x, y in blocks) y_max = max(y for _, y in blocks)
while True: while True:
x, y = 500, 0 x, y = 500, 0
while y <= y_max: while y <= y_max:
moved = False moved = False
for cx, cy in ((x, y + 1), (x - 1, y + 1), (x + 1, y + 1)): for cx, cy in ((x, y + 1), (x - 1, y + 1), (x + 1, y + 1)):
if (cx, cy) not in blocks and fill_fn(cx, cy) == Cell.AIR: if (cx, cy) not in blocks and fill_fn(cx, cy) == Cell.AIR:
@ -117,10 +113,10 @@ print_blocks(blocks)
print() print()
x_min, y_min, x_max, y_max = ( x_min, y_min, x_max, y_max = (
min(x for x, y in blocks), min(x for x, _ in blocks),
0, 0,
max(x for x, y in blocks), max(x for x, _ in blocks),
max(y for x, y in blocks), max(y for _, y in blocks),
) )
# === part 1 === # === part 1 ===

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
import numpy as np import numpy as np
@ -7,7 +5,6 @@ import parse
def part1(sensor_to_beacon: dict[tuple[int, int], tuple[int, int]], row: int) -> int: def part1(sensor_to_beacon: dict[tuple[int, int], tuple[int, int]], row: int) -> int:
no_beacons_row_l: list[np.ndarray] = [] no_beacons_row_l: list[np.ndarray] = []
for (sx, sy), (bx, by) in sensor_to_beacon.items(): for (sx, sy), (bx, by) in sensor_to_beacon.items():
@ -37,7 +34,7 @@ def part2_intervals(
its.append((max(0, sx - dx), min(sx + dx, xy_max))) its.append((max(0, sx - dx), min(sx + dx, xy_max)))
its = sorted(its) its = sorted(its)
s, e = its[0] _, e = its[0]
for si, ei in its[1:]: for si, ei in its[1:]:
if si > e + 1: if si > e + 1:

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
from __future__ import annotations from __future__ import annotations
import heapq import heapq
@ -69,7 +67,6 @@ def part_1(
distances: dict[tuple[Pipe, Pipe], int], distances: dict[tuple[Pipe, Pipe], int],
relevant_pipes: FrozenSet[Pipe], relevant_pipes: FrozenSet[Pipe],
): ):
node_at_times: dict[int, dict[Pipe, dict[FrozenSet[Pipe], int]]] = defaultdict( node_at_times: dict[int, dict[Pipe, dict[FrozenSet[Pipe], int]]] = defaultdict(
lambda: defaultdict(lambda: defaultdict(lambda: 0)) lambda: defaultdict(lambda: defaultdict(lambda: 0))
) )
@ -79,7 +76,6 @@ def part_1(
for c_pipe, nodes in node_at_times[time].items(): for c_pipe, nodes in node_at_times[time].items():
for flowing, flow in nodes.items(): for flowing, flow in nodes.items():
for target in relevant_pipes: for target in relevant_pipes:
distance = distances[c_pipe, target] + 1 distance = distances[c_pipe, target] + 1
if time + distance >= max_time or target in flowing: if time + distance >= max_time or target in flowing:
continue continue

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
from typing import Sequence, TypeVar from typing import Sequence, TypeVar
@ -49,7 +47,6 @@ def build_tower(
early_stop: bool = False, early_stop: bool = False,
init: np.ndarray = np.ones(WIDTH, dtype=bool), init: np.ndarray = np.ones(WIDTH, dtype=bool),
) -> tuple[np.ndarray, int, int, dict[int, int]]: ) -> tuple[np.ndarray, int, int, dict[int, int]]:
tower = EMPTY_BLOCKS.copy() tower = EMPTY_BLOCKS.copy()
tower[0, :] = init tower[0, :] = init
@ -59,7 +56,6 @@ def build_tower(
rock_count = 0 rock_count = 0
for rock_count in range(n_rocks): for rock_count in range(n_rocks):
if early_stop: if early_stop:
if i_rock == 0 and (i_rock, i_jet) in done_at: if i_rock == 0 and (i_rock, i_jet) in done_at:
break break
@ -75,7 +71,6 @@ def build_tower(
tower = np.concatenate([tower, EMPTY_BLOCKS], axis=0) tower = np.concatenate([tower, EMPTY_BLOCKS], axis=0)
while True: while True:
jet, i_jet = next_cycle(jets, i_jet) jet, i_jet = next_cycle(jets, i_jet)
dx = 0 dx = 0

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
from typing import FrozenSet from typing import FrozenSet

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
from typing import Literal from typing import Literal
@ -88,7 +86,6 @@ for line in lines:
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.,
# in the first toy blueprint, we need at most 4 ore robots, 14 clay ones and 7 # in the first toy blueprint, we need at most 4 ore robots, 14 clay ones and 7
@ -100,7 +97,6 @@ def run(blueprint: dict[Reagent, dict[Reagent, int]], max_time: int) -> int:
state_after_t: dict[int, set[State]] = {0: [State()]} state_after_t: dict[int, set[State]] = {0: [State()]}
for t in range(1, max_time + 1): for t in range(1, max_time + 1):
# list of new states at the end of step t that we are going to prune later # list of new states at the end of step t that we are going to prune later
states_for_t: set[State] = set() states_for_t: set[State] = set()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
@ -49,7 +47,7 @@ lines = sys.stdin.readlines()
values = [(ord(row[0]) - ord("A"), ord(row[2]) - ord("X")) for row in lines] values = [(ord(row[0]) - ord("A"), ord(row[2]) - ord("X")) for row in lines]
# part 1 - 13526 # part 1 - 13526
print(f"score 1 is {sum(score_1(*v) for v in values)}") print(f"answer 1 is {sum(score_1(*v) for v in values)}")
# part 2 - 14204 # part 2 - 14204
print(f"score 2 is {sum(score_2(*v) for v in values)}") print(f"answer 2 is {sum(score_2(*v) for v in values)}")

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
from __future__ import annotations from __future__ import annotations
import sys import sys
@ -21,7 +19,6 @@ class Number:
def decrypt(numbers: list[Number], key: int, rounds: int) -> int: def decrypt(numbers: list[Number], key: int, rounds: int) -> int:
numbers = numbers.copy() numbers = numbers.copy()
original = numbers.copy() original = numbers.copy()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import operator import operator
import sys import sys
from typing import Callable from typing import Callable

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import re import re
import sys import sys
from typing import Callable from typing import Callable
@ -126,7 +124,6 @@ def wrap_part_2(y0: int, x0: int, r0: str) -> tuple[int, int, str]:
def run(wrap: Callable[[int, int, str], tuple[int, int, str]]) -> tuple[int, int, str]: def run(wrap: Callable[[int, int, str], tuple[int, int, str]]) -> tuple[int, int, str]:
y0 = 0 y0 = 0
x0 = np.where(board[0] == EMPTY)[0][0] x0 = np.where(board[0] == EMPTY)[0][0]
r0 = "E" r0 = "E"

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import itertools import itertools
import sys import sys
from collections import defaultdict from collections import defaultdict
@ -41,7 +39,7 @@ def round(
directions: Directions, directions: Directions,
): ):
to_move: dict[tuple[int, int], list[tuple[int, int]]] = defaultdict(lambda: []) to_move: dict[tuple[int, int], list[tuple[int, int]]] = defaultdict(lambda: [])
for (y, x) in positions: for y, x in positions:
elves = { elves = {
(dy, dx): (y + dy, x + dx) in positions (dy, dx): (y + dy, x + dx) in positions
for dy, dx in itertools.product((-1, 0, 1), (-1, 0, 1)) for dy, dx in itertools.product((-1, 0, 1), (-1, 0, 1))

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import heapq import heapq
import math import math
import sys import sys

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
lines = sys.stdin.read().splitlines() lines = sys.stdin.read().splitlines()

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import string import string
import sys import sys
@ -13,7 +11,7 @@ priorities = {c: i + 1 for i, c in enumerate(string.ascii_letters)}
# part 1 # part 1
part1 = sum(priorities[c] for p1, p2 in parts for c in p1.intersection(p2)) part1 = sum(priorities[c] for p1, p2 in parts for c in p1.intersection(p2))
print(f"score 1 is {part1}") print(f"answer 1 is {part1}")
# part 2 # part 2
n_per_group = 3 n_per_group = 3
@ -22,4 +20,4 @@ part2 = sum(
for i in range(0, len(lines), n_per_group) for i in range(0, len(lines), n_per_group)
for c in set(lines[i]).intersection(*lines[i + 1 : i + n_per_group]) for c in set(lines[i]).intersection(*lines[i + 1 : i + n_per_group])
) )
print(f"score 2 is {part2}") print(f"answer 2 is {part2}")

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
lines = [line.strip() for line in sys.stdin.readlines()] lines = [line.strip() for line in sys.stdin.readlines()]
@ -12,8 +10,8 @@ def make_range(value: str) -> set[int]:
sections = [tuple(make_range(part) for part in line.split(",")) for line in lines] sections = [tuple(make_range(part) for part in line.split(",")) for line in lines]
score_1 = sum(s1.issubset(s2) or s2.issubset(s1) for s1, s2 in sections) answer_1 = sum(s1.issubset(s2) or s2.issubset(s1) for s1, s2 in sections)
print(f"score 1 is {score_1}") print(f"answer 1 is {answer_1}")
score_2 = sum(bool(s1.intersection(s2)) for s1, s2 in sections) answer_2 = sum(bool(s1.intersection(s2)) for s1, s2 in sections)
print(f"score 1 is {score_2}") print(f"answer 1 is {answer_2}")

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import copy import copy
import sys import sys

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
import sys import sys
from pathlib import Path from pathlib import Path

View File

@ -1,8 +1,7 @@
# -*- encoding: utf-8 -*-
import sys import sys
import numpy as np import numpy as np
from numpy.typing import NDArray
lines = sys.stdin.read().splitlines() lines = sys.stdin.read().splitlines()
@ -27,7 +26,7 @@ answer_1 = (highest_trees.min(axis=2) < trees).sum()
print(f"answer 1 is {answer_1}") print(f"answer 1 is {answer_1}")
def viewing_distance(row_of_trees: np.ndarray, value: int) -> int: def viewing_distance(row_of_trees: NDArray[np.int_], value: int) -> int:
w = np.where(row_of_trees >= value)[0] w = np.where(row_of_trees >= value)[0]
if not w.size: if not w.size:

View File

@ -1,12 +1,9 @@
# -*- encoding: utf-8 -*-
import sys import sys
import numpy as np import numpy as np
def move(head: tuple[int, int], command: str) -> tuple[int, int]: def move(head: tuple[int, int], command: str) -> tuple[int, int]:
h_col, h_row = head h_col, h_row = head
if command == "L": if command == "L":
@ -22,7 +19,6 @@ def move(head: tuple[int, int], command: str) -> tuple[int, int]:
def follow(head: tuple[int, int], tail: tuple[int, int]) -> tuple[int, int]: def follow(head: tuple[int, int], tail: tuple[int, int]) -> tuple[int, int]:
h_col, h_row = head h_col, h_row = head
t_col, t_row = tail t_col, t_row = tail
@ -33,8 +29,7 @@ def follow(head: tuple[int, int], tail: tuple[int, int]) -> tuple[int, int]:
def run(commands: list[str], n_blocks: int) -> list[tuple[int, int]]: def run(commands: list[str], n_blocks: int) -> list[tuple[int, int]]:
blocks: list[tuple[int, int]] = [(0, 0) for _ in range(n_blocks)]
blocks = [(0, 0) for _ in range(n_blocks)]
visited = [blocks[-1]] visited = [blocks[-1]]
for command in commands: for command in commands: