-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
150 lines (92 loc) · 3.43 KB
/
utils.py
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
from enum import Enum
from typing import Iterator, List, Optional, Tuple
def input_as_string(filename: str) -> str:
with open(filename, "r") as f:
return f.read().strip()
def input_as_strings_iter(filename: str) -> Iterator[str]:
with open(filename, "r") as f:
for line in f:
yield line.strip()
def input_as_strings(filename: str) -> List[str]:
return list(input_as_strings_iter(filename))
def input_as_numbers_iter(filename: str) -> Iterator[int]:
with open(filename, "r") as f:
for line in f:
yield int(line.strip())
def input_as_numbers(filename: str) -> List[int]:
return list(input_as_numbers_iter(filename))
def input_as_list_of_numbers_iter(
filename: str, split_on: Optional[str] = None
) -> Iterator[List[int]]:
with open(filename, "r") as f:
for line in f:
yield list(map(lambda v: int(v.strip()), line.strip().split(split_on)))
def input_as_list_of_numbers(
filename: str, split_on: Optional[str] = None
) -> List[List[int]]:
return list(input_as_list_of_numbers_iter(filename, split_on))
class Dir(Enum):
NORTH = -1j
SOUTH = 1j
WEST = -1
EAST = 1
NORTHEAST = 1 - 1j
NORTHWEST = -1 - 1j
SOUTHEAST = 1 + 1j
SOUTHWEST = -1 + 1j
def get_directions_cardinal() -> Iterator[Dir]:
yield Dir.NORTH
yield Dir.SOUTH
yield Dir.WEST
yield Dir.EAST
def get_directions_diagonal() -> Iterator[Dir]:
yield Dir.NORTHEAST
yield Dir.NORTHWEST
yield Dir.SOUTHEAST
yield Dir.SOUTHWEST
def get_directions_all() -> Iterator[Dir]:
for d in get_directions_cardinal():
yield d
for d in get_directions_diagonal():
yield d
def get_neighbors_cardinal(pos: complex) -> Iterator[Tuple[Dir, complex]]:
for d in get_directions_cardinal():
yield (d, pos + d.value)
def get_neighbors_diagonal(pos: complex) -> Iterator[Tuple[Dir, complex]]:
for d in get_directions_diagonal():
yield (d, pos + d.value)
def get_neighbors_all(pos: complex) -> Iterator[Tuple[Dir, complex]]:
for d in get_neighbors_cardinal(pos):
yield d
for d in get_neighbors_diagonal(pos):
yield d
def turn_left(dir: Dir) -> Dir:
return Dir(dir.value * -1j)
def turn_right(dir: Dir) -> Dir:
return Dir(dir.value * 1j)
def move(pos: complex, dir: Dir, steps: int = 1) -> complex:
return pos + (dir.value * steps)
def move_north(pos: complex) -> complex:
return pos + Dir.NORTH.value
def move_south(pos: complex) -> complex:
return pos + Dir.SOUTH.value
def move_east(pos: complex) -> complex:
return pos + Dir.EAST.value
def move_west(pos: complex) -> complex:
return pos + Dir.WEST.value
def move_northeast(pos: complex) -> complex:
return pos + Dir.NORTHEAST.value
def move_northwest(pos: complex) -> complex:
return pos + Dir.NORTHWEST.value
def move_southeast(pos: complex) -> complex:
return pos + Dir.SOUTHEAST.value
def move_southwest(pos: complex) -> complex:
return pos + Dir.SOUTHWEST.value
def coord_to_xy(coord: complex) -> Tuple[int, int]:
return (int(coord.real), int(coord.imag))
def xy_to_coord(x: int, y: int) -> complex:
return x + y * 1j
def coord_in_bounds(c: complex, x_range: range, y_range: range) -> bool:
return int(c.real) in x_range and int(c.imag) in y_range
def manhattan_distance(a: complex, b: complex) -> int:
return abs(int(a.real) - int(b.real)) + abs(int(a.imag) - int(b.imag))