summaryrefslogtreecommitdiffstats
path: root/aoc/datastructures.py
diff options
context:
space:
mode:
Diffstat (limited to 'aoc/datastructures.py')
-rw-r--r--aoc/datastructures.py98
1 files changed, 98 insertions, 0 deletions
diff --git a/aoc/datastructures.py b/aoc/datastructures.py
new file mode 100644
index 0000000..1f141e2
--- /dev/null
+++ b/aoc/datastructures.py
@@ -0,0 +1,98 @@
1# -*- coding: utf-8 -*-
2from collections import namedtuple
3from typing import Iterator
4
5
6class Coordinate(namedtuple("Coordinate", ["x", "y"])):
7 def __sub__(self, other: "Coordinate") -> "Coordinate":
8 return Coordinate(self.x - other.x, self.y - other.y)
9
10 def __add__(self, other: "Coordinate") -> "Coordinate":
11 return Coordinate(self.x + other.x, self.y + other.y)
12
13 def manhattan_distance(self, other: "Coordinate") -> int:
14 return abs(self.x - other.x) + abs(self.y - other.y)
15
16 @property
17 def polarity(self) -> "Coordinate":
18 try:
19 px = abs(self.x) / self.x
20 except ZeroDivisionError:
21 px = 0
22
23 try:
24 py = abs(self.y) / self.y
25 except ZeroDivisionError:
26 py = 0
27
28 return Coordinate(
29 px,
30 py,
31 )
32
33 def neighbours(self, no_diagonal: bool = False) -> Iterator["Coordinate"]:
34 if no_diagonal:
35 yield self + Coordinate(-1, 0)
36 yield self + Coordinate(1, 0)
37 yield self + Coordinate(0, -1)
38 yield self + Coordinate(0, 1)
39 else:
40 for dy in range(self.y - 1, self.y + 2):
41 for dx in range(self.x - 1, self.x + 2):
42 if dy == self.y and dx == self.x:
43 continue
44
45 yield Coordinate(dx, dy)
46
47
48class Coordinate3(namedtuple("Coordinate3", ["x", "y", "z"])):
49 def __sub__(self, other: "Coordinate3") -> "Coordinate3":
50 return Coordinate3(self.x - other.x, self.y - other.y, self.z - other.z)
51
52 def __add__(self, other: "Coordinate3") -> "Coordinate3":
53 return Coordinate3(self.x + other.x, self.y + other.y, self.z + other.z)
54
55 def manhattan_distance(self, other: "Coordinate3") -> int:
56 return abs(self.x - other.x) + abs(self.y - other.y) + abs(self.z - other.z)
57
58 @property
59 def polarity(self) -> "Coordinate3":
60 try:
61 px = abs(self.x) / self.x
62 except ZeroDivisionError:
63 px = 0
64
65 try:
66 py = abs(self.y) / self.y
67 except ZeroDivisionError:
68 py = 0
69
70 try:
71 pz = abs(self.z) / self.z
72 except ZeroDivisionError:
73 pz = 0
74
75 return Coordinate3(
76 px,
77 py,
78 pz,
79 )
80
81 def neighbours(self, no_diagonal: bool = False) -> Iterator["Coordinate3"]:
82 if no_diagonal:
83 yield self + Coordinate3(-1, 0, 0)
84 yield self + Coordinate3(1, 0, 0)
85 yield self + Coordinate3(0, -1, 0)
86 yield self + Coordinate3(0, 1, 0)
87 yield self + Coordinate3(0, 0, -1)
88 yield self + Coordinate3(0, 0, 1)
89 else:
90 for dz in range(self.z - 1, self.z + 2):
91 for dy in range(self.y - 1, self.y + 2):
92 for dx in range(self.x - 1, self.x + 2):
93 coordinate = Coordinate3(dx, dy, dz)
94
95 if dy == self.y and dx == self.x and dz == self.z:
96 continue
97
98 yield coordinate