Poetry stuff.
This commit is contained in:
0
src/holt59/aoc/2021/__init__.py
Normal file
0
src/holt59/aoc/2021/__init__.py
Normal file
14
src/holt59/aoc/2021/day1.py
Normal file
14
src/holt59/aoc/2021/day1.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import sys
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
values = [int(line) for line in lines]
|
||||
|
||||
# part 1
|
||||
answer_1 = sum(v2 > v1 for v1, v2 in zip(values[:-1], values[1:]))
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
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:]))
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day10.py
Normal file
13
src/holt59/aoc/2021/day10.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day11.py
Normal file
13
src/holt59/aoc/2021/day11.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day12.py
Normal file
13
src/holt59/aoc/2021/day12.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day13.py
Normal file
13
src/holt59/aoc/2021/day13.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day14.py
Normal file
13
src/holt59/aoc/2021/day14.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day15.py
Normal file
13
src/holt59/aoc/2021/day15.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day16.py
Normal file
13
src/holt59/aoc/2021/day16.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day17.py
Normal file
13
src/holt59/aoc/2021/day17.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day18.py
Normal file
13
src/holt59/aoc/2021/day18.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day19.py
Normal file
13
src/holt59/aoc/2021/day19.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
40
src/holt59/aoc/2021/day2.py
Normal file
40
src/holt59/aoc/2021/day2.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import sys
|
||||
from math import prod
|
||||
from typing import Literal, cast
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
commands = [
|
||||
(cast(Literal["forward", "up", "down"], (p := line.split())[0]), int(p[1]))
|
||||
for line in lines
|
||||
]
|
||||
|
||||
|
||||
def depth_and_position(use_aim: bool):
|
||||
aim, pos, depth = 0, 0, 0
|
||||
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:
|
||||
aim += d_depth
|
||||
else:
|
||||
depth += value
|
||||
|
||||
return depth, pos
|
||||
|
||||
|
||||
# part 1
|
||||
answer_1 = prod(depth_and_position(False))
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = prod(depth_and_position(True))
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day20.py
Normal file
13
src/holt59/aoc/2021/day20.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day21.py
Normal file
13
src/holt59/aoc/2021/day21.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day22.py
Normal file
13
src/holt59/aoc/2021/day22.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day23.py
Normal file
13
src/holt59/aoc/2021/day23.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day24.py
Normal file
13
src/holt59/aoc/2021/day24.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day25.py
Normal file
13
src/holt59/aoc/2021/day25.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
39
src/holt59/aoc/2021/day3.py
Normal file
39
src/holt59/aoc/2021/day3.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import sys
|
||||
from collections import Counter
|
||||
from typing import Literal
|
||||
|
||||
|
||||
def generator_rating(
|
||||
values: list[str], most_common: bool, default: Literal["0", "1"]
|
||||
) -> str:
|
||||
index = 0
|
||||
most_common_idx = 0 if most_common else 1
|
||||
|
||||
while len(values) > 1:
|
||||
cnt = Counter(value[index] for value in values)
|
||||
bit = cnt.most_common(2)[most_common_idx][0]
|
||||
if cnt["0"] == cnt["1"]:
|
||||
bit = default
|
||||
values = [value for value in values if value[index] == bit]
|
||||
index += 1
|
||||
|
||||
return values[0]
|
||||
|
||||
|
||||
lines = sys.stdin.read().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)
|
||||
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}")
|
45
src/holt59/aoc/2021/day4.py
Normal file
45
src/holt59/aoc/2021/day4.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
numbers = [int(c) for c in lines[0].split(",")]
|
||||
|
||||
boards = np.asarray(
|
||||
[
|
||||
[[int(c) for c in line.split()] for line in lines[start : start + 5]]
|
||||
for start in range(2, len(lines), 6)
|
||||
]
|
||||
)
|
||||
|
||||
# (round, score) for each board (-1 when not found)
|
||||
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):
|
||||
# mark boards
|
||||
marked[boards == number] = True
|
||||
|
||||
# check each board for winning
|
||||
for index in range(len(boards)):
|
||||
if winning_rounds[index][0] > 0:
|
||||
continue
|
||||
|
||||
if np.any(np.all(marked[index], axis=0) | np.all(marked[index], axis=1)):
|
||||
winning_rounds[index] = (
|
||||
round,
|
||||
number * int(np.sum(boards[index][~marked[index]])),
|
||||
)
|
||||
|
||||
# all boards are winning - break
|
||||
if np.all(marked.all(axis=1) | marked.all(axis=2)):
|
||||
break
|
||||
|
||||
# part 1
|
||||
(_, score) = min(winning_rounds, key=lambda w: w[0])
|
||||
print(f"answer 1 is {score}")
|
||||
|
||||
# part 2
|
||||
(_, score) = max(winning_rounds, key=lambda w: w[0])
|
||||
print(f"answer 2 is {score}")
|
48
src/holt59/aoc/2021/day5.py
Normal file
48
src/holt59/aoc/2021/day5.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
lines: list[str] = sys.stdin.read().splitlines()
|
||||
|
||||
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)
|
||||
|
||||
x_min, x_max, y_min, y_max = (
|
||||
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()),
|
||||
max(np_sections[:, 1].max(), np_sections[:, 3].max()),
|
||||
)
|
||||
|
||||
counts_1 = np.zeros((y_max + 1, x_max + 1), dtype=int)
|
||||
counts_2 = counts_1.copy()
|
||||
|
||||
for (x1, y1), (x2, y2) in sections:
|
||||
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)
|
||||
|
||||
if x1 == x2 or y1 == y2:
|
||||
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
|
||||
|
||||
answer_1 = (counts_1 >= 2).sum()
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
answer_2 = (counts_2 >= 2).sum()
|
||||
print(f"answer 2 is {answer_2}")
|
21
src/holt59/aoc/2021/day6.py
Normal file
21
src/holt59/aoc/2021/day6.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import sys
|
||||
|
||||
values = [int(c) for c in sys.stdin.read().strip().split(",")]
|
||||
|
||||
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):
|
||||
for day2 in range(day + 9, days, 7):
|
||||
lanterns[day2] += lanterns[day]
|
||||
|
||||
# part 1
|
||||
answer_1 = sum(v for k, v in lanterns.items() if k < 80) + len(values)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = sum(lanterns.values()) + len(values)
|
||||
print(f"answer 2 is {answer_2}")
|
21
src/holt59/aoc/2021/day7.py
Normal file
21
src/holt59/aoc/2021/day7.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
positions = np.asarray([int(c) for c in sys.stdin.read().strip().split(",")])
|
||||
|
||||
min_position, max_position = positions.min(), positions.max()
|
||||
|
||||
# part 1
|
||||
answer_1 = min(
|
||||
np.sum(np.abs(positions - position))
|
||||
for position in range(min_position, max_position + 1)
|
||||
)
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = min(
|
||||
np.sum(abs(positions - position) * (abs(positions - position) + 1) // 2)
|
||||
for position in range(min_position, max_position + 1)
|
||||
)
|
||||
print(f"answer 2 is {answer_2}")
|
87
src/holt59/aoc/2021/day8.py
Normal file
87
src/holt59/aoc/2021/day8.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import itertools
|
||||
import os
|
||||
import sys
|
||||
|
||||
VERBOSE = os.getenv("AOC_VERBOSE") == "True"
|
||||
|
||||
digits = {
|
||||
"abcefg": 0,
|
||||
"cf": 1,
|
||||
"acdeg": 2,
|
||||
"acdfg": 3,
|
||||
"bcdf": 4,
|
||||
"abdfg": 5,
|
||||
"abdefg": 6,
|
||||
"acf": 7,
|
||||
"abcdefg": 8,
|
||||
"abcdfg": 9,
|
||||
}
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
lengths = {len(k) for k, v in digits.items() if v in (1, 4, 7, 8)}
|
||||
answer_1 = sum(
|
||||
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
|
||||
values: list[int] = []
|
||||
|
||||
for line in lines:
|
||||
parts = line.split("|")
|
||||
broken_digits = sorted(parts[0].strip().split(), key=len)
|
||||
|
||||
per_length = {
|
||||
k: list(v)
|
||||
for k, v in itertools.groupby(sorted(broken_digits, key=len), key=len)
|
||||
}
|
||||
|
||||
# a can be found immediately
|
||||
a = next(u for u in per_length[3][0] if u not in per_length[2][0])
|
||||
|
||||
# c and f have only two possible values corresponding to the single entry of
|
||||
# length 2
|
||||
cf = list(per_length[2][0])
|
||||
|
||||
# the only digit of length 4 contains bcdf, so we can deduce bd by removing cf
|
||||
bd = [u for u in per_length[4][0] if u not in cf]
|
||||
|
||||
# the 3 digits of length 5 have a, d and g in common
|
||||
adg = [u for u in per_length[5][0] if all(u in pe for pe in per_length[5][1:])]
|
||||
|
||||
# we can remove a
|
||||
dg = [u for u in adg if u != a]
|
||||
|
||||
# we can deduce d and g
|
||||
d = next(u for u in dg if u in bd)
|
||||
g = next(u for u in dg if u != d)
|
||||
|
||||
# then b
|
||||
b = next(u for u in bd if u != d)
|
||||
|
||||
# f is in the three 6-length digits, while c is only in 2
|
||||
f = next(u for u in cf if all(u in p for p in per_length[6]))
|
||||
|
||||
# c is not f
|
||||
c = next(u for u in cf if u != f)
|
||||
|
||||
# e is the last one
|
||||
e = next(u for u in "abcdefg" if u not in {a, b, c, d, f, g})
|
||||
|
||||
mapping = dict(zip((a, b, c, d, e, f, g), "abcdefg"))
|
||||
|
||||
value = 0
|
||||
for number in parts[1].strip().split():
|
||||
digit = "".join(sorted(mapping[c] for c in number))
|
||||
value = 10 * value + digits[digit]
|
||||
|
||||
if VERBOSE:
|
||||
print(value)
|
||||
|
||||
values.append(value)
|
||||
|
||||
|
||||
answer_2 = sum(values)
|
||||
print(f"answer 2 is {answer_2}")
|
13
src/holt59/aoc/2021/day9.py
Normal file
13
src/holt59/aoc/2021/day9.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
lines = sys.stdin.read().splitlines()
|
||||
|
||||
# part 1
|
||||
answer_1 = ...
|
||||
print(f"answer 1 is {answer_1}")
|
||||
|
||||
# part 2
|
||||
answer_2 = ...
|
||||
print(f"answer 2 is {answer_2}")
|
Reference in New Issue
Block a user