-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathaoc.py
128 lines (89 loc) · 3.19 KB
/
aoc.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
import re
from itertools import chain, product
# Most of this is shamelessly stolen from Peter Norvig.
cat = ''.join
inf = float('inf')
flatten = chain.from_iterable
def mapl(f, iterable):
return list(map(f, iterable))
def mapt(f, iterable):
return tuple(map(f, iterable))
def filterl(f, iterable):
return list(filter(f, iterable))
def parse_multiline_string(s, datatype=str, sep='\n'):
return mapl(datatype, s.split(sep))
def read_input(filename, datatype=str, sep='\n'):
filename = f"{filename:02d}" if isinstance(filename, int) else filename
with open(f"inputs/{filename}.txt") as f:
return parse_multiline_string(f.read(), datatype, sep)
def read_input_line(filename, sep=''):
filename = f"{filename:02d}" if isinstance(filename, int) else filename
with open(f"inputs/{filename}.txt") as f:
contents = f.read().strip()
return contents if not sep else contents.split(sep)
def digits(line):
return mapl(int, line)
def integers(text, negative=True):
return mapt(int, re.findall(r"-?\d+" if negative else r"\d+", text))
def first_int(text):
if (m := re.search(r"-?\d+", text)):
return int(m.group(0))
def count_if(iterable, pred=bool):
return sum(1 for item in iterable if pred(item))
def first(iterable, default=None):
return next(iter(iterable), default)
def filter_first(iterable, pred):
return first(el for el in iterable if pred(el))
def move_point(a, b):
return tuple(p + q for p, q in zip(a, b))
def manhattan(a, b=(0, 0)):
return sum(abs(p - q) for p, q in zip(a, b))
def sign(n):
if n > 0: return 1
elif n < 0: return -1
else: return 0
def print_2d(lines):
for line in lines:
print(cat(line))
def maxval(d):
return max(d.values())
def transpose(matrix):
return list(zip(*matrix))
def bin2int(s):
return int(s, 2)
def neighbours(x, y, amount=4):
assert amount in {4, 5, 8, 9}
for dy, dx in product((-1, 0, 1), repeat=2):
if ((amount == 4 and abs(dx) != abs(dy)) or
(amount == 5 and abs(dx) + abs(dy) <= 1) or
(amount == 8 and not dx == dy == 0) or
amount == 9):
yield (x+dx, y+dy)
def complex_neighbours(pt, amount=4):
assert amount in {4, 5, 8, 9}
for dy, dx in product((-1, 0, 1), repeat=2):
if ((amount == 4 and abs(dx) != abs(dy)) or
(amount == 5 and abs(dx) + abs(dy) <= 1) or
(amount == 8 and not dx == dy == 0) or
amount == 9):
yield pt + dx + dy*1j
def neighbours_3d(x, y, z):
yield from [(x-1, y, z), (x+1, y, z),
(x, y-1, z), (x, y+1, z),
(x, y, z-1), (x, y, z+1)]
def list2grid(lines, pred=None):
return {(x, y): val
for y, line in enumerate(lines)
for x, val in enumerate(line)
if (pred(val) if pred else True)}
def grid2list(grid, pred=bool):
min_x, min_y = map(min, zip(*grid))
if min_x < 0 or min_y < 0:
raise ValueError
max_x, max_y = map(max, zip(*grid))
lines = [[' ' for _ in range(max_x+1)]
for _ in range(max_y+1)]
for x, y in grid:
if pred(grid[(x, y)]):
lines[y][x] = '█'
return lines