1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
# -*- coding: utf-8 -*-
from abc import ABC
from copy import copy
from dataclasses import dataclass
from typing import Tuple, Iterator, List, Set
from aoc import BaseAssignment
@dataclass
class Coordinate:
x: int
y: int
def __hash__(self):
return tuple([self.x, self.y]).__hash__()
def __sub__(self, other: "Coordinate"):
return Coordinate(self.x - other.x, self.y - other.y)
@property
def polarity_x(self):
try:
return abs(self.x) / self.x
except ZeroDivisionError:
return 0
@property
def polarity_y(self):
try:
return abs(self.y) / self.y
except ZeroDivisionError:
return 0
class Assignment(BaseAssignment, ABC):
def parse_line(self, item: str) -> Tuple[str, int]:
direction, amount = item.split(" ")
return direction, int(amount)
def move(self, direction: str, amount: int):
pass
@staticmethod
def next_head(head: Coordinate, direction: str):
match direction:
case "R":
head.x += 1
case "L":
head.x -= 1
case "U":
head.y += 1
case "D":
head.y -= 1
@staticmethod
def next_tail(head: Coordinate, tail: Coordinate):
delta = head - tail
if abs(delta.x) > 1 and delta.y == 0:
tail.x += delta.x - delta.polarity_x
if abs(delta.x) > 1 and abs(delta.y) == 1:
tail.x += delta.x - delta.polarity_x
tail.y += delta.y
if abs(delta.y > 1) and delta.x == 0:
tail.y += delta.y - delta.polarity_y
if abs(delta.y) > 1 and abs(delta.x) == 1:
tail.y += delta.y - delta.polarity_y
tail.x += delta.x
def tail_positions(self, input: Iterator[str]) -> Iterator[Coordinate]:
head = Coordinate(0, 0)
tail = Coordinate(0, 0)
for line in input:
direction, amount = self.parse_line(line)
for _ in range(amount):
self.next_head(head, direction)
self.next_tail(head, tail)
yield tail
def unique_tail_positions(self, input: Iterator[str]) -> Set[Coordinate]:
unique_tail_positions = set()
for position in self.tail_positions(input):
unique_tail_positions.add(copy(position))
return unique_tail_positions
def visualize(self, width: int, height: int, positions: Set[Coordinate]):
rows = []
for y in range(height):
items = []
for x in range(width):
if x == 0 and y == 0:
items.append("s")
elif Coordinate(x, y) in positions:
items.append("#")
else:
items.append(".")
rows.append(items)
return "\n".join(["".join(row) for row in reversed(rows)])
class AssignmentOne(Assignment):
example_result = 13
def run(self, input: Iterator) -> int:
unique_positions = self.unique_tail_positions(input)
print()
print(self.visualize(6, 5, unique_positions))
return len(unique_positions)
class AssignmentTwo(Assignment):
pass
|