Compare commits

...

4 Commits

Author SHA1 Message Date
2e64eef9a2 Refactoring 2026-06-23 17:47:18 +02:00
4681a782b5 Optimized solution 2026-06-21 20:32:51 +02:00
d78e9d6c63 Optimized solution 2026-06-21 19:46:20 +02:00
f4aa799bac Remove redundancies 2026-06-07 19:54:54 +02:00
4 changed files with 82 additions and 107 deletions

View File

@@ -32,12 +32,12 @@
# To what floor do the instructions take Santa? # To what floor do the instructions take Santa?
with open("files/P1.txt") as f: with open("files/P1.txt") as f:
directions = [line for line in f.read().strip().split()] directions = f.read().strip()
def part_1() -> None: def part_1() -> None:
up = int(directions[0].count("(")) up = directions.count("(")
down = int(directions[0].count(")")) down = directions.count(")")
print(f"The floor is {up - down}") print(f"The floor is {up - down}")
@@ -58,14 +58,15 @@ def part_1() -> None:
def part_2() -> None: def part_2() -> None:
floor = 0 floor = 0
for idx, char in enumerate(directions[0], start=1): for idx, char in enumerate(directions, start=1):
if char == "(": if char == "(":
floor += 1 floor += 1
elif char == ")": elif char == ")":
floor -= 1 floor -= 1
if floor == -1: if floor == -1:
print(f"The position is {idx}") print(f"The position is {idx}")
break return
print("Basement was never reached!")
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -21,41 +21,29 @@
# ^v^v^v^v^v delivers a bunch of presents to some very lucky children at # ^v^v^v^v^v delivers a bunch of presents to some very lucky children at
# only 2 houses. # only 2 houses.
from typing import Tuple
with open("files/P3.txt") as f: with open("files/P3.txt") as f:
moves = [line for line in f.read().strip().split()][0] moves = [line for line in f.read().strip()]
def move_up(pos: Tuple[int, int]) -> Tuple[int, int]: Position = tuple[int, int]
return pos[0], pos[1] + 1 DIRECTIONS: dict[str, Position] = {
"^": (0, 1),
"v": (0, -1),
def move_down(pos: Tuple[int, int]) -> Tuple[int, int]: "<": (-1, 0),
return pos[0], pos[1] - 1 ">": (1, 0),
}
def move_left(pos: Tuple[int, int]) -> Tuple[int, int]:
return pos[0] - 1, pos[1]
def move_right(pos: Tuple[int, int]) -> Tuple[int, int]:
return pos[0] + 1, pos[1]
def part_1() -> None: def part_1() -> None:
pos = [(0, 0)] x, y = 0, 0
visited: set[Position] = {(x, y)}
for move in moves: for move in moves:
if move == "^": delta_x, delta_y = DIRECTIONS[move]
pos.append(move_up(pos[-1])) x += delta_x
elif move == "v": y += delta_y
pos.append(move_down(pos[-1])) visited.add((x, y))
elif move == "<":
pos.append(move_left(pos[-1]))
elif move == ">":
pos.append(move_right(pos[-1]))
print(f"{len(set(pos))} houses receive at least one present") print(f"{len(visited)} houses receive at least one present")
# --- Part Two --- # --- Part Two ---
@@ -81,33 +69,23 @@ def part_1() -> None:
def part_2(): def part_2():
santa = [(0, 0)] x_santa, y_santa = 0, 0
robo_santa = [(0, 0)] x_robo, y_robo = 0, 0
for idx, move in enumerate(moves): visited: set[Position] = {(0, 0)}
if move == "^":
if idx % 2 == 0:
santa.append(move_up(santa[-1]))
else:
robo_santa.append(move_up(robo_santa[-1]))
elif move == "v":
if idx % 2 == 0:
santa.append(move_down(santa[-1]))
else:
robo_santa.append(move_down(robo_santa[-1]))
elif move == "<":
if idx % 2 == 0:
santa.append(move_left(santa[-1]))
else:
robo_santa.append(move_left(robo_santa[-1]))
elif move == ">":
if idx % 2 == 0:
santa.append(move_right(santa[-1]))
else:
robo_santa.append(move_right(robo_santa[-1]))
print( for idx, move in enumerate(moves):
f"{len(set(santa + robo_santa))} houses receive at least one present" delta_x, delta_y = DIRECTIONS[move]
) # santa's turn
if idx % 2:
x_santa += delta_x
y_santa += delta_y
visited.add((x_santa, y_santa))
else:
x_robo += delta_x
y_robo += delta_y
visited.add((x_robo, y_robo))
print(f"{len(visited)} houses receive at least one present")
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -18,21 +18,30 @@
# an MD5 hash starting with five zeroes is 1048970; that is, the MD5 hash of # an MD5 hash starting with five zeroes is 1048970; that is, the MD5 hash of
# pqrstuv1048970 looks like 000006136ef.... # pqrstuv1048970 looks like 000006136ef....
# Your puzzle input is yzbqklnj.
from hashlib import md5 from hashlib import md5
from itertools import count
_input = "yzbqklnj" with open("files/P4.txt") as f:
secret_key = f.read().strip()
key_bytes = secret_key.encode()
def part_1() -> None: def part_1() -> None:
end = "9" * len(_input) padding = 5
for num in range(int(end)): prefix = "0" * padding
testing = _input + str(num) base_hash = md5(key_bytes)
result = md5(testing.encode()).hexdigest()
if result.startswith("0" * 5): for num in count(1):
print(f"The lowest positive number is {num}") digest_ctx = base_hash.copy()
break digest_ctx.update(str(num).encode())
digest = digest_ctx.hexdigest()
if digest.startswith(prefix):
print(f"The lowest positive number starting with {padding} zeroes is {num}")
return
raise RuntimeError("No valid number found")
# --- Part Two --- # --- Part Two ---
@@ -41,13 +50,19 @@ def part_1() -> None:
def part_2() -> None: def part_2() -> None:
end = "9" * len(_input) padding = 6
for num in range(int(end)): prefix = "0" * padding
testing = _input + str(num) base_hash = md5(key_bytes)
result = md5(testing.encode()).hexdigest()
if result.startswith("0" * 6): for num in count(1):
print(f"The lowest positive number is {num}") digest_ctx = base_hash.copy()
break digest_ctx.update(str(num).encode())
digest = digest_ctx.hexdigest()
if digest.startswith(prefix):
print(f"The lowest positive number starting with {padding} zeroes is {num}")
return
raise RuntimeError("No valid number found")
if __name__ == "__main__": if __name__ == "__main__":

View File

@@ -25,44 +25,32 @@
# How many strings are nice? # How many strings are nice?
from collections import Counter
with open("files/P5.txt") as f: with open("files/P5.txt") as f:
strings = [line for line in f.read().strip().split()] strings = [line for line in f.read().strip().split()]
VOWELS = set("aeiou")
FORBIDDEN = ("ab", "cd", "pq", "xy")
def has_enough_vowels(s: str) -> bool: def has_enough_vowels(s: str) -> bool:
num_vowels = sum(s.lower().count(v) for v in "aeiou") return sum(char in VOWELS for char in s) >= 3
if num_vowels >= 3:
return True
return False
def has_double_letter(s: str) -> bool: def has_double_letter(s: str) -> bool:
double_letters = sum(1 for i, j in zip(s, s[1:]) if i == j) return any(left == right for left, right in zip(s, s[1:]))
if double_letters >= 1:
return True
return False
def has_substring(s: str) -> bool: def has_substring(s: str) -> bool:
substrings = ["ab", "cd", "pq", "xy"] return any(substring in s for substring in FORBIDDEN)
for substring in substrings:
if substring in s:
return True
return False
def part_1() -> None: def part_1() -> None:
nice = 0 nice = sum(
for string in strings:
if (
has_enough_vowels(string) has_enough_vowels(string)
and has_double_letter(string) and has_double_letter(string)
and not has_substring(string) and not has_substring(string)
): for string in strings
nice += 1 )
print(f"There are {nice} nice strings") print(f"There are {nice} nice strings")
@@ -103,18 +91,11 @@ def has_pairs(s: str) -> bool:
def has_letter_between(s: str) -> bool: def has_letter_between(s: str) -> bool:
_my_str = zip(s, s[1:], s[2:]) return any(a == c for a, _, c in zip(s, s[1:], s[2:]))
for triple in _my_str:
if triple[0] == triple[-1]:
return True
return False
def part_2() -> None: def part_2() -> None:
nice = 0 nice = sum(has_pairs(string) and has_letter_between(string) for string in strings)
for string in strings:
if has_pairs(string) and has_letter_between(string):
nice += 1
print(f"There are {nice} nicer strings") print(f"There are {nice} nicer strings")