summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2025-12-02 07:57:38 +0100
committerGravatar Tom van der Lee <tom@vanderlee.io>2025-12-02 09:40:04 +0100
commitf315ef05c548da80410cb4f6665a9bba7a953f94 (patch)
treea727c6ad862a4a9c237c320705483b3def7acc11
parentd7e30321ae6ae4c82a8ab7455f6ce33afd719c67 (diff)
download2025-f315ef05c548da80410cb4f6665a9bba7a953f94.tar.gz
2025-f315ef05c548da80410cb4f6665a9bba7a953f94.tar.bz2
2025-f315ef05c548da80410cb4f6665a9bba7a953f94.zip
Day 1 and 2
-rw-r--r--.gitignore2
-rw-r--r--aoc/__init__.py6
-rw-r--r--day1/__init__.py60
-rw-r--r--day1/example.txt10
-rw-r--r--day1/test_init.py38
-rw-r--r--day2/__init__.py57
-rw-r--r--day2/example.txt1
-rw-r--r--day2/test_init.py41
8 files changed, 212 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 0618b3a..6ad58aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -233,3 +233,5 @@ dmypy.json
233 233
234.DS_Store 234.DS_Store
235# End of https://www.toptal.com/developers/gitignore/api/python,pycharm+all 235# End of https://www.toptal.com/developers/gitignore/api/python,pycharm+all
236
237day*/input.txt
diff --git a/aoc/__init__.py b/aoc/__init__.py
index 7a089f6..0257b69 100644
--- a/aoc/__init__.py
+++ b/aoc/__init__.py
@@ -17,8 +17,8 @@ class BaseAssignment(Generic[T, I], ABC):
17 def __str__(self): 17 def __str__(self):
18 return f"{self.__module__}.{self.__class__.__name__}" 18 return f"{self.__module__}.{self.__class__.__name__}"
19 19
20 def parse_item(self, item: str) -> I: 20 def parse_item(self, item: str) -> Iterator[I]:
21 return item 21 yield item
22 22
23 @property 23 @property
24 def part(self) -> int: 24 def part(self) -> int:
@@ -37,7 +37,7 @@ class BaseAssignment(Generic[T, I], ABC):
37 37
38 with open(file, "r") as input_file: 38 with open(file, "r") as input_file:
39 for line in input_file.readlines(): 39 for line in input_file.readlines():
40 yield self.parse_item(line.strip("\n")) 40 yield from self.parse_item(line.strip("\n"))
41 41
42 def run(self, input: Iterator[I]) -> T: 42 def run(self, input: Iterator[I]) -> T:
43 raise NotImplementedError("Please implement run") 43 raise NotImplementedError("Please implement run")
diff --git a/day1/__init__.py b/day1/__init__.py
new file mode 100644
index 0000000..6e95329
--- /dev/null
+++ b/day1/__init__.py
@@ -0,0 +1,60 @@
1# -*- coding: utf-8 -*-
2from abc import ABC
3from typing import Iterator
4
5from aoc import BaseAssignment, I
6
7
8class Assignment(BaseAssignment, ABC):
9 def parse_item(self, item: str) -> Iterator[I]:
10 [rotation, *places] = item
11 places = int("".join(places))
12
13 yield -places if rotation == "L" else places
14
15
16class AssignmentOne(Assignment):
17 example_result = 3
18
19 def run(self, input: Iterator[int]) -> int:
20 seen_0 = 0
21 position = 50
22 for rotation in input:
23 position = (position + rotation) % 100
24 if position == 0:
25 seen_0 += 1
26
27 return seen_0
28
29
30class AssignmentTwo(Assignment):
31 example_result = 6
32
33 @staticmethod
34 def calculate_new_position(position, rotation) -> tuple[int, int]:
35 previous_position = position
36 new_position = position + rotation
37
38 overturned = new_position >= 100 or new_position < 0
39
40 multiplier = position - (0 - -previous_position) // 100
41
42 if overturned:
43 new_position = new_position % 100
44
45 seen_0 = 0
46 if new_position == 0 and multiplier == 0:
47 seen_0 += multiplier + 1
48 elif overturned:
49 seen_0 += multiplier
50
51 return new_position, seen_0
52
53 def run(self, input: Iterator[int]) -> int:
54 seen_0_total = 0
55 position = 50
56 for rotation in input:
57 position, seen_0 = self.calculate_new_position(position, rotation)
58 seen_0_total += seen_0
59
60 return seen_0_total
diff --git a/day1/example.txt b/day1/example.txt
new file mode 100644
index 0000000..53287c7
--- /dev/null
+++ b/day1/example.txt
@@ -0,0 +1,10 @@
1L68
2L30
3R48
4L5
5R60
6L55
7L1
8L99
9R14
10L82
diff --git a/day1/test_init.py b/day1/test_init.py
new file mode 100644
index 0000000..a24e272
--- /dev/null
+++ b/day1/test_init.py
@@ -0,0 +1,38 @@
1# -*- coding: utf-8 -*-
2import pytest
3
4from day1 import AssignmentTwo
5
6
7class TestAssignmentTwo:
8 data = [
9 # Example Data
10 (50, -68, 82, 1),
11 (82, -30, 52, 0),
12 (52, 48, 0, 1),
13 (0, -5, 95, 0),
14 (95, 60, 55, 1),
15 (55, -55, 0, 1),
16 (0, -1, 99, 0),
17 (99, -99, 0, 1),
18 (0, 14, 14, 0),
19 (14, -82, 32, 1),
20 # Additional cases
21 (0, 10, 10, 0),
22 (0, -10, 90, 0),
23 (0, 100, 0, 1),
24 (0, -100, 0, 1),
25 (80, 40, 20, 1),
26 (80, 140, 20, 2),
27 (80, 100, 80, 1),
28 (0, -300, 0, 3),
29 (0, 299, 99, 2),
30 (0, -299, 1, 2),
31 ]
32
33 @pytest.mark.parametrize("position,rotation,new_position,seen_0", data)
34 def test_calculate_new_position(self, position, rotation, new_position, seen_0):
35 assert AssignmentTwo.calculate_new_position(position, rotation) == (
36 new_position,
37 seen_0,
38 )
diff --git a/day2/__init__.py b/day2/__init__.py
new file mode 100644
index 0000000..882bcad
--- /dev/null
+++ b/day2/__init__.py
@@ -0,0 +1,57 @@
1# -*- coding: utf-8 -*-
2import re
3from abc import ABC
4from typing import Iterator
5
6from aoc import BaseAssignment, I, T
7
8
9class Assignment(BaseAssignment, ABC):
10 def parse_item(self, item: str) -> Iterator[range]:
11 for r in item.split(","):
12 [start, end] = r.split("-")
13 yield range(int(start), int(end) + 1)
14
15 def find_invalid_ids(self, item: range) -> Iterator[int]:
16 raise NotImplementedError()
17
18 def run(self, input: Iterator[range]) -> int:
19 totals = 0
20 for item in input:
21 totals += sum(self.find_invalid_ids(item))
22
23 return totals
24
25
26class AssignmentOne(Assignment):
27 example_result = 1227775554
28
29 @classmethod
30 def find_invalid_ids(cls, item: range):
31 for i in item:
32 i_str = str(i)
33 if i_str[: len(i_str) // 2] == i_str[len(i_str) // 2 :]:
34 yield i
35
36
37class AssignmentTwo(Assignment):
38 example_result = 4174379265
39
40 @classmethod
41 def is_invalid_id(cls, item: str) -> bool:
42 for i in range(1, (len(item) // 2) + 1):
43 pattern = item[:i]
44 rest = item[i:]
45
46 if re.match(rf"({pattern})+$", rest):
47 return True
48
49 return False
50
51 @classmethod
52 def find_invalid_ids(cls, item: range):
53 for i in item:
54 i_str = str(i)
55
56 if AssignmentTwo.is_invalid_id(i_str):
57 yield i
diff --git a/day2/example.txt b/day2/example.txt
new file mode 100644
index 0000000..a3f22ef
--- /dev/null
+++ b/day2/example.txt
@@ -0,0 +1 @@
11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124
diff --git a/day2/test_init.py b/day2/test_init.py
new file mode 100644
index 0000000..dc1ab40
--- /dev/null
+++ b/day2/test_init.py
@@ -0,0 +1,41 @@
1# -*- coding: utf-8 -*-
2import pytest
3
4from day2 import AssignmentOne, AssignmentTwo
5
6
7class TestAssignmentOne:
8 data = [
9 (range(11, 23), [11, 22]),
10 (range(95, 116), [99]),
11 (range(998, 1013), [1010]),
12 (range(1188511880, 1188511891), [1188511885]),
13 (range(222220, 222225), [222222]),
14 (range(1698522, 1698529), []),
15 (range(446443, 446450), [446446]),
16 (range(38593856, 38593863), [38593859]),
17 ]
18
19 @pytest.mark.parametrize("r,invalid", data)
20 def test_find_invalid_ids(self, r: range, invalid: list[str]):
21 assert list(AssignmentOne.find_invalid_ids(r)) == invalid
22