diff options
| author | 2022-12-12 08:51:41 +0100 | |
|---|---|---|
| committer | 2022-12-12 08:51:41 +0100 | |
| commit | 0af1b042a29811bc5c850267681dc45469981845 (patch) | |
| tree | 45c22e15c932fac2e56a20b17207a8048d28f7b4 | |
| parent | cdd7aec2e28e65886c02bf2729bc8d2032f0ef6e (diff) | |
| download | 2022-0af1b042a29811bc5c850267681dc45469981845.tar.gz 2022-0af1b042a29811bc5c850267681dc45469981845.tar.bz2 2022-0af1b042a29811bc5c850267681dc45469981845.zip | |
Day 9 [WIP]
| -rw-r--r-- | aoc/__init__.py | 12 | ||||
| -rw-r--r-- | day8/test_init.py | 4 | ||||
| -rw-r--r-- | day9/__init__.py | 49 | ||||
| -rw-r--r-- | day9/example_part_1.txt (renamed from day9/example.txt) | 0 | ||||
| -rw-r--r-- | day9/example_part_2.txt | 8 | ||||
| -rw-r--r-- | day9/test_init.py | 128 |
6 files changed, 169 insertions, 32 deletions
diff --git a/aoc/__init__.py b/aoc/__init__.py index 3662e3a..8368f7b 100644 --- a/aoc/__init__.py +++ b/aoc/__init__.py | |||
| @@ -16,10 +16,20 @@ class BaseAssignment(ABC): | |||
| 16 | def parse_item(self, item: str) -> Any: | 16 | def parse_item(self, item: str) -> Any: |
| 17 | return item | 17 | return item |
| 18 | 18 | ||
| 19 | @property | ||
| 20 | def part(self): | ||
| 21 | return 1 if self.__class__.__name__.endswith("One") else 2 | ||
| 22 | |||
| 19 | def read_input(self, example=False) -> Generator: | 23 | def read_input(self, example=False) -> Generator: |
| 20 | file = f"{self.path}/input.txt" | 24 | file = f"{self.path}/input.txt" |
| 25 | |||
| 21 | if example or not os.path.isfile(file): | 26 | if example or not os.path.isfile(file): |
| 22 | file = f"{self.path}/example.txt" | 27 | for file in [ |
| 28 | f"{self.path}/example_part_{self.part}.txt", | ||
| 29 | f"{self.path}/example.txt", | ||
| 30 | ]: | ||
| 31 | if os.path.exists(file): | ||
| 32 | break | ||
| 23 | 33 | ||
| 24 | with open(file, "r") as input_file: | 34 | with open(file, "r") as input_file: |
| 25 | for line in input_file.readlines(): | 35 | for line in input_file.readlines(): |
diff --git a/day8/test_init.py b/day8/test_init.py index 6fd0e2b..16be2ec 100644 --- a/day8/test_init.py +++ b/day8/test_init.py | |||
| @@ -3,5 +3,5 @@ from day8 import AssignmentTwo | |||
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | def test_calculate_1d_scenic_score(): | 5 | def test_calculate_1d_scenic_score(): |
| 6 | assert 1 * 2 == AssignmentTwo.calculate_1d_scenic_score([3, 5, 3, 5, 3], 1) | 6 | assert AssignmentTwo.calculate_1d_scenic_score([3, 5, 3, 5, 3], 1) == 1 * 2 |
| 7 | assert 1 * 2 == AssignmentTwo.calculate_1d_scenic_score([2, 5, 5, 1, 2], 2) | 7 | assert AssignmentTwo.calculate_1d_scenic_score([2, 5, 5, 1, 2], 2) == 1 * 2 |
diff --git a/day9/__init__.py b/day9/__init__.py index f198deb..4846468 100644 --- a/day9/__init__.py +++ b/day9/__init__.py | |||
| @@ -34,6 +34,8 @@ class Coordinate: | |||
| 34 | 34 | ||
| 35 | 35 | ||
| 36 | class Assignment(BaseAssignment, ABC): | 36 | class Assignment(BaseAssignment, ABC): |
| 37 | rope_length = NotImplemented | ||
| 38 | |||
| 37 | def parse_line(self, item: str) -> Tuple[str, int]: | 39 | def parse_line(self, item: str) -> Tuple[str, int]: |
| 38 | direction, amount = item.split(" ") | 40 | direction, amount = item.split(" ") |
| 39 | return direction, int(amount) | 41 | return direction, int(amount) |
| @@ -54,7 +56,7 @@ class Assignment(BaseAssignment, ABC): | |||
| 54 | head.y -= 1 | 56 | head.y -= 1 |
| 55 | 57 | ||
| 56 | @staticmethod | 58 | @staticmethod |
| 57 | def next_tail(head: Coordinate, tail: Coordinate): | 59 | def next_knot(head: Coordinate, tail: Coordinate): |
| 58 | delta = head - tail | 60 | delta = head - tail |
| 59 | 61 | ||
| 60 | if abs(delta.x) > 1 and delta.y == 0: | 62 | if abs(delta.x) > 1 and delta.y == 0: |
| @@ -62,37 +64,43 @@ class Assignment(BaseAssignment, ABC): | |||
| 62 | if abs(delta.x) > 1 and abs(delta.y) == 1: | 64 | if abs(delta.x) > 1 and abs(delta.y) == 1: |
| 63 | tail.x += delta.x - delta.polarity_x | 65 | tail.x += delta.x - delta.polarity_x |
| 64 | tail.y += delta.y | 66 | tail.y += delta.y |
| 65 | if abs(delta.y > 1) and delta.x == 0: | 67 | if abs(delta.y) > 1 and delta.x == 0: |
| 66 | tail.y += delta.y - delta.polarity_y | 68 | tail.y += delta.y - delta.polarity_y |
| 67 | if abs(delta.y) > 1 and abs(delta.x) == 1: | 69 | if abs(delta.y) > 1 and abs(delta.x) == 1: |
| 68 | tail.y += delta.y - delta.polarity_y | 70 | tail.y += delta.y - delta.polarity_y |
| 69 | tail.x += delta.x | 71 | tail.x += delta.x |
| 70 | 72 | ||
| 71 | def tail_positions(self, input: Iterator[str]) -> Iterator[Coordinate]: | 73 | def tail_positions(self, input: Iterator[str], length: int) -> Iterator[Coordinate]: |
| 72 | head = Coordinate(0, 0) | 74 | knots = [Coordinate(0, 0) for _ in range(length)] |
| 73 | tail = Coordinate(0, 0) | ||
| 74 | 75 | ||
| 75 | for line in input: | 76 | for line in input: |
| 76 | direction, amount = self.parse_line(line) | 77 | direction, amount = self.parse_line(line) |
| 77 | 78 | ||
| 78 | for _ in range(amount): | 79 | for _ in range(amount): |
| 79 | self.next_head(head, direction) | 80 | for index in range(length): |
| 80 | self.next_tail(head, tail) | 81 | if index == 0: |
| 81 | yield tail | 82 | self.next_head(knots[index], direction) |
| 83 | continue | ||
| 84 | |||
| 85 | self.next_knot(knots[index - 1], knots[index]) | ||
| 86 | |||
| 87 | yield knots[length - 1] | ||
| 82 | 88 | ||
| 83 | def unique_tail_positions(self, input: Iterator[str]) -> Set[Coordinate]: | 89 | def unique_tail_positions( |
| 90 | self, input: Iterator[str], length: int | ||
| 91 | ) -> Set[Coordinate]: | ||
| 84 | unique_tail_positions = set() | 92 | unique_tail_positions = set() |
| 85 | 93 | ||
| 86 | for position in self.tail_positions(input): | 94 | for position in self.tail_positions(input, length): |
| 87 | unique_tail_positions.add(copy(position)) | 95 | unique_tail_positions.add(copy(position)) |
| 88 | 96 | ||
| 89 | return unique_tail_positions | 97 | return unique_tail_positions |
| 90 | 98 | ||
| 91 | def visualize(self, width: int, height: int, positions: Set[Coordinate]): | 99 | def visualize(self, width: range, height: range, positions: Set[Coordinate]): |
| 92 | rows = [] | 100 | rows = [] |
| 93 | for y in range(height): | 101 | for y in height: |
| 94 | items = [] | 102 | items = [] |
| 95 | for x in range(width): | 103 | for x in width: |
| 96 | if x == 0 and y == 0: | 104 | if x == 0 and y == 0: |
| 97 | items.append("s") | 105 | items.append("s") |
| 98 | elif Coordinate(x, y) in positions: | 106 | elif Coordinate(x, y) in positions: |
| @@ -103,17 +111,16 @@ class Assignment(BaseAssignment, ABC): | |||
| 103 | 111 | ||
| 104 | return "\n".join(["".join(row) for row in reversed(rows)]) | 112 | return "\n".join(["".join(row) for row in reversed(rows)]) |
| 105 | 113 | ||
| 114 | def run(self, input: Iterator) -> int: | ||
| 115 | unique_positions = self.unique_tail_positions(input, length=self.rope_length) | ||
| 116 | return len(unique_positions) | ||
| 117 | |||
| 106 | 118 | ||
| 107 | class AssignmentOne(Assignment): | 119 | class AssignmentOne(Assignment): |
| 108 | example_result = 13 | 120 | example_result = 13 |
| 109 | 121 | rope_length = 2 | |
| 110 | def run(self, input: Iterator) -> int: | ||
| 111 | unique_positions = self.unique_tail_positions(input) | ||
| 112 | print() | ||
| 113 | print(self.visualize(6, 5, unique_positions)) | ||
| 114 | |||
| 115 | return len(unique_positions) | ||
| 116 | 122 | ||
| 117 | 123 | ||
| 118 | class AssignmentTwo(Assignment): | 124 | class AssignmentTwo(Assignment): |
| 119 | pass | 125 | example_result = 36 |
| 126 | rope_length = 10 | ||
diff --git a/day9/example.txt b/day9/example_part_1.txt index 9874df2..9874df2 100644 --- a/day9/example.txt +++ b/day9/example_part_1.txt | |||
diff --git a/day9/example_part_2.txt b/day9/example_part_2.txt new file mode 100644 index 0000000..60bd43b --- /dev/null +++ b/day9/example_part_2.txt | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | R 5 | ||
| 2 | U 8 | ||
| 3 | L 8 | ||
| 4 | D 3 | ||
| 5 | R 17 | ||
| 6 | D 10 | ||
| 7 | L 25 | ||
| 8 | U 20 | ||
diff --git a/day9/test_init.py b/day9/test_init.py index b36eed6..eb889c7 100644 --- a/day9/test_init.py +++ b/day9/test_init.py | |||
| @@ -4,11 +4,123 @@ import os.path | |||
| 4 | import day9 | 4 | import day9 |
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | def test_output_visualization(): | 7 | class TestAssignment: |
| 8 | expected = "..##..\n" "...##.\n" ".####.\n" "....#.\n" "s###.." | 8 | def test_right(self): |
| 9 | 9 | expected = "\n".join( | |
| 10 | assignment = day9.AssignmentOne(path=os.path.dirname(day9.__file__)) | 10 | [ |
| 11 | unique_positions = assignment.unique_tail_positions( | 11 | "s###..", |
| 12 | input=assignment.read_input(True) | 12 | ] |
| 13 | ) | 13 | ) |
| 14 | assert expected == assignment.visualize(6, 5, unique_positions) | 14 | |
| 15 | input = ["R 4"] | ||
| 16 | |||
| 17 | assignment = day9.AssignmentOne(path=os.path.dirname(day9.__file__)) | ||
| 18 | unique_positions = assignment.unique_tail_positions(input=input, length=2) | ||
| 19 | |||
| 20 | assert assignment.visualize(range(6), range(1), unique_positions) == expected | ||
| 21 | |||
| 22 | def test_left(self): | ||
| 23 | expected = "\n".join( | ||
| 24 | [ | ||
| 25 | "..###s", | ||
| 26 | ] | ||
| 27 | ) | ||
| 28 | |||
| 29 | input = ["L 4"] | ||
| 30 | |||
| 31 | assignment = day9.AssignmentOne(path=os.path.dirname(day9.__file__)) | ||
| 32 | unique_positions = assignment.unique_tail_positions(input=input, length=2) | ||
| 33 | |||
| 34 | assert ( | ||
| 35 | assignment.visualize(range(-5, 1), range(1), unique_positions) == expected | ||
| 36 | ) | ||
| 37 | |||
| 38 | def test_up(self): | ||
| 39 | expected = "\n".join( | ||
| 40 | [ | ||
| 41 | ".", | ||
| 42 | ".", | ||
| 43 | "#", | ||
| 44 | "#", | ||
| 45 | "#", | ||
| 46 | "s", | ||
| 47 | ] | ||
| 48 | ) | ||
| 49 | |||
| 50 | input = ["U 4"] | ||
| 51 | |||
| 52 | assignment = day9.AssignmentOne(path=os.path.dirname(day9.__file__)) | ||
| 53 | unique_positions = assignment.unique_tail_positions(input=input, length=2) | ||
| 54 | |||
| 55 | assert assignment.visualize(range(1), range(6), unique_positions) == expected | ||
| 56 | |||
