Skip to content

Commit 7659e14

Browse files
committed
* Add solutions for day 2-7, 2025
* pre-commit config update
1 parent 7266a2e commit 7659e14

14 files changed

Lines changed: 458 additions & 44 deletions

.pre-commit-config.yaml

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,113 @@
11
repos:
2-
- repo: https://gitlab.com/vojko.pribudic.foss/pre-commit-update
2+
- repo: https://gitlab.com/vojko.pribudic.foss/pre-commit-update
33
rev: v0.9.0
44
hooks:
55
# Update pre-commit scripts
6-
- id: pre-commit-update
6+
- id: pre-commit-update
77

8-
- repo: https://github.com/astral-sh/uv-pre-commit
9-
rev: 0.9.13
8+
- repo: https://github.com/astral-sh/uv-pre-commit
9+
rev: 0.9.16
1010
hooks:
1111
# Update the uv lockfile
12-
- id: uv-lock
12+
- id: uv-lock
1313

14-
- repo: https://github.com/asottile/pyupgrade
14+
- repo: https://github.com/asottile/pyupgrade
1515
rev: v3.21.2
1616
hooks:
1717
# Upgrade syntax for newer versions of the language
18-
- id: pyupgrade
18+
- id: pyupgrade
1919
args: [--py312-plus]
2020

21-
- repo: https://github.com/pre-commit/pre-commit-hooks
21+
- repo: https://github.com/pre-commit/pre-commit-hooks
2222
rev: v6.0.0
2323
hooks:
2424
# Prevent giant files from being committed
25-
- id: check-added-large-files
25+
- id: check-added-large-files
2626
# Check whether files parse as valid python
27-
- id: check-ast
27+
- id: check-ast
2828
# Require literal syntax for empty or zero Python builtin types
29-
- id: check-builtin-literals
29+
- id: check-builtin-literals
3030
# Check for files with conflict on a case-insensitive filesystem
31-
- id: check-case-conflict
31+
- id: check-case-conflict
3232
# Checks that non-binary executables have a proper shebang
33-
- id: check-executables-have-shebangs
33+
- id: check-executables-have-shebangs
3434
# Check for files that cannot be created on Windows
35-
- id: check-illegal-windows-names
35+
- id: check-illegal-windows-names
3636
# Attempts to load all json files to verify syntax
37-
- id: check-json
37+
- id: check-json
3838
# Checks that scripts with shebangs are executable
39-
- id: check-shebang-scripts-are-executable
39+
- id: check-shebang-scripts-are-executable
4040
# Checks for symlinks which do not point to anything
41-
- id: check-symlinks
41+
- id: check-symlinks
4242
# Attempts to load all TOML files to verify syntax
43-
- id: check-toml
43+
- id: check-toml
4444
# Attempts to load all yaml files to verify syntax
45-
- id: check-yaml
45+
- id: check-yaml
4646
# Makes sure files end in a newline and only a newline
47-
- id: end-of-file-fixer
47+
- id: end-of-file-fixer
4848
# Removes UTF-8 byte order marker
49-
- id: fix-byte-order-marker
49+
- id: fix-byte-order-marker
5050
# Replaces or checks mixed line ending
51-
- id: mixed-line-ending
51+
- id: mixed-line-ending
5252
# Verifies that test files are named correctly
53-
- id: name-tests-test
53+
- id: name-tests-test
5454
args: [--pytest-test-first]
5555
# Protect specific branches from direct checkins
56-
- id: no-commit-to-branch
56+
- id: no-commit-to-branch
5757
args: [-b, dev]
5858
# Trims trailing whitespace
59-
- id: trailing-whitespace
59+
- id: trailing-whitespace
6060

61-
- repo: https://github.com/adrienverge/yamllint.git
61+
- repo: https://github.com/adrienverge/yamllint.git
6262
rev: v1.37.1
6363
hooks:
6464
# Lint YAML files
65-
- id: yamllint
65+
- id: yamllint
6666

67-
- repo: https://github.com/astral-sh/ruff-pre-commit
68-
rev: v0.14.7
67+
- repo: https://github.com/astral-sh/ruff-pre-commit
68+
rev: v0.14.8
6969
hooks:
7070
# Run the linter
71-
- id: ruff-check
71+
- id: ruff-check
7272
args: [--fix, --show-fixes, --exit-non-zero-on-fix]
7373
# Run the formatter
74-
- id: ruff-format
74+
- id: ruff-format
7575

7676
# local hook used to avoid repeating dependencies list
77-
- repo: local
77+
- repo: local
7878
hooks:
7979
# Check type annotations
80-
- id: mypy
80+
- id: mypy
8181
name: mypy
8282
entry: mypy
8383
require_serial: true
8484
language: system
8585
'types_or': [python, pyi]
8686

87-
- repo: https://github.com/fpgmaas/deptry.git
87+
- repo: https://github.com/fpgmaas/deptry.git
8888
rev: 0.24.0
8989
hooks:
9090
# Check for problems in dependency declarations
91-
- id: deptry
91+
- id: deptry
9292
args: ["src"]
9393

94-
- repo: https://github.com/codespell-project/codespell
94+
- repo: https://github.com/codespell-project/codespell
9595
rev: v2.4.1
9696
hooks:
9797
# Fix common misspellings in text files
98-
- id: codespell
98+
- id: codespell
9999
additional_dependencies:
100-
- tomli
100+
- tomli
101101

102-
- repo: https://github.com/jendrikseipp/vulture
102+
- repo: https://github.com/jendrikseipp/vulture
103103
rev: v2.14
104104
hooks:
105105
# Finds unused code
106-
- id: vulture
106+
- id: vulture
107107

108-
- repo: https://github.com/pappasam/toml-sort
108+
- repo: https://github.com/pappasam/toml-sort
109109
rev: v0.24.3
110110
hooks:
111111
# Sort and format toml files
112-
- id: toml-sort
112+
- id: toml-sort
113113
args: ["pyproject.toml"]

src/2025/01/2025_01.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ def parse_input(input_data: str) -> list[Rotation]:
4444
def solve(
4545
init_pos: int, limit: int, commands: list[Rotation], part2: bool = False
4646
) -> int:
47-
print()
4847
result = 0
4948

5049
current_pos = init_pos
@@ -76,5 +75,5 @@ def solve(
7675

7776
if __name__ == "__main__":
7877
debug_mode = True
79-
debug_mode = False
78+
# debug_mode = False
8079
main(debug_mode)

src/2025/02/2025_02.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import math
2+
3+
from src.utils.data import load_data
4+
from src.utils.submission import submit_or_print
5+
6+
7+
def main(debug: bool) -> None:
8+
input_data = load_data(debug)
9+
10+
ranges = parse_input(input_data)
11+
12+
result_part1 = solve_part1(ranges)
13+
result_part2 = solve_part2(ranges)
14+
15+
submit_or_print(result_part1, result_part2, debug)
16+
17+
18+
def parse_input(input_data: str) -> set[tuple[int, int]]:
19+
splits = input_data.split(",")
20+
ranges = set()
21+
for s in splits:
22+
s = s.split("-")
23+
ranges.add((int(s[0]), int(s[1])))
24+
return ranges
25+
26+
27+
def solve_part1(ranges: set[tuple[int, int]]) -> int:
28+
result = 0
29+
for start, end in ranges:
30+
for i in range(start, end + 1):
31+
i_str = str(i)
32+
if len(i_str) % 2 != 0:
33+
continue
34+
half_len = len(i_str) // 2
35+
if i_str[half_len:] == i_str[:half_len]:
36+
result += i
37+
return result
38+
39+
40+
def solve_part2(ranges: set[tuple[int, int]]) -> int:
41+
result = 0
42+
for start, end in sorted(ranges):
43+
for i in range(start, end + 1):
44+
i_str = str(i)
45+
valid = False
46+
for divisor in get_divisors(len(i_str)):
47+
chunks = set()
48+
for j in range(0, len(i_str), divisor):
49+
chunk = i_str[j : j + divisor]
50+
chunks.add(chunk)
51+
if len(chunks) > 1:
52+
break
53+
if len(chunks) == 1:
54+
valid = True
55+
break
56+
if valid:
57+
result += i
58+
return result
59+
60+
61+
def get_divisors(n: int) -> set[int]:
62+
divisors = set()
63+
for i in range(1, int(math.sqrt(n)) + 2):
64+
if n % i == 0:
65+
divisors.add(i)
66+
divisors.add(n // i)
67+
return divisors - {n}
68+
69+
70+
if __name__ == "__main__":
71+
debug_mode = True
72+
# debug_mode = False
73+
main(debug_mode)

src/2025/02/sample_input.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
11-33,195-1115,9398-12012

src/2025/03/2025_03.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from src.utils.data import load_data
2+
from src.utils.submission import submit_or_print
3+
4+
5+
def main(debug: bool) -> None:
6+
input_data = load_data(debug)
7+
banks = parse_data(input_data)
8+
9+
result_part1 = solve(banks)
10+
result_part2 = solve(banks, digits=12)
11+
12+
submit_or_print(result_part1, result_part2, debug)
13+
14+
15+
def parse_data(input_data: str):
16+
return [list(map(int, bank)) for bank in input_data.splitlines()]
17+
18+
19+
def solve(banks: list[list[int]], digits: int = 2) -> int:
20+
result = 0
21+
for bank in banks:
22+
batteries = []
23+
start = 0
24+
end = len(bank) - digits
25+
for _ in range(digits):
26+
max_digit, max_digit_position = find_max_digit(bank, start, end)
27+
start = max_digit_position + 1
28+
end = end + 1
29+
batteries.append(max_digit)
30+
result += int("".join(map(str, batteries)))
31+
32+
return result
33+
34+
35+
def find_max_digit(bank: list[int], start: int, end: int) -> tuple[int, int]:
36+
max_digit = -1
37+
max_digit_position = None
38+
for i in range(end, start - 1, -1):
39+
digit = bank[i]
40+
if digit >= max_digit:
41+
max_digit = digit
42+
max_digit_position = i
43+
return max_digit, max_digit_position
44+
45+
46+
if __name__ == "__main__":
47+
debug_mode = True
48+
# debug_mode = False
49+
main(debug_mode)

src/2025/03/sample_input.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
511111111111114
2+
987654321111111
3+
124342342345672

src/2025/04/2025_04.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from itertools import repeat, product
2+
3+
import numpy as np
4+
5+
from src.utils.data import load_data
6+
from src.utils.submission import submit_or_print
7+
8+
9+
def main(debug: bool) -> None:
10+
input_data = load_data(debug)
11+
12+
grid = parse_input(input_data)
13+
14+
result_part1 = solve_part1(grid)
15+
result_part2 = solve_part2(grid)
16+
17+
submit_or_print(result_part1, result_part2, debug)
18+
19+
20+
def parse_input(input_data: str) -> np.ndarray:
21+
rows = [list(line) for line in input_data.splitlines()]
22+
# add guards
23+
for row in rows:
24+
row.insert(0, ".")
25+
row.append(".")
26+
rows.insert(0, list(repeat(".", len(rows[0]))))
27+
rows.append(list(repeat(".", len(rows[0]))))
28+
29+
return np.array(rows)
30+
31+
32+
def solve_part1(grid: np.ndarray) -> int:
33+
result = 0
34+
it = np.nditer(grid, flags=["multi_index"])
35+
for elem in it:
36+
if elem == "@":
37+
x, y = it.multi_index
38+
neighboring_rolls = 0
39+
for xd, yd in product([-1, 0, 1], [-1, 0, 1]):
40+
if xd == yd == 0:
41+
continue
42+
if grid[x + xd, y + yd] == "@":
43+
neighboring_rolls += 1
44+
if neighboring_rolls < 4:
45+
result += 1
46+
return result
47+
48+
49+
def solve_part2(grid: np.ndarray) -> int:
50+
result = 0
51+
while True:
52+
removed = False
53+
it = np.nditer(grid, flags=["multi_index"])
54+
for elem in it:
55+
if elem == "@":
56+
x, y = it.multi_index
57+
neighboring_rolls = 0
58+
for xd, yd in product([-1, 0, 1], [-1, 0, 1]):
59+
if xd == yd == 0:
60+
continue
61+
if grid[x + xd, y + yd] == "@":
62+
neighboring_rolls += 1
63+
if neighboring_rolls < 4:
64+
grid[x, y] = "."
65+
result += 1
66+
removed = True
67+
if not removed:
68+
break
69+
return result
70+
71+
72+
if __name__ == "__main__":
73+
debug_mode = True
74+
# debug_mode = False
75+
main(debug_mode)

src/2025/04/sample_input.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.@@.@.@.@@
2+
@.@@@.@...
3+
@@.@.@.@@.

0 commit comments

Comments
 (0)