-
Notifications
You must be signed in to change notification settings - Fork 0
/
day3.py
129 lines (116 loc) · 4.54 KB
/
day3.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
import aocd
import numpy as np
import time
import os
data = """467..114..
...*......
..35..633.
......#...
617*......
.....+.58.
..592.....
......755.
...$.*....
.664.598..
"""
data = aocd.get_data(day=3)
if not os.path.exists("day3.txt"):
with open("day3.txt", "w") as f:
f.write(data)
start = time.time()
symbols = set(data)
symbols = set([sym for sym in symbols if sym not in [".","\n"] and not sym.isdigit()])
symbols.remove("*")
print(f"Found symbols = {symbols}")
data = data.split("\n")
# We must find all the numbers that are adjacent to a symbol (other than .)
# A number is adjacent to a symbol if:
# - The symbol is next to the number, i.e. the symbol is in the same row as the number and its index
# is either the index of the first digit of the number - 1 or the index of the last digit of the number + 1
# - OR the symbol is in the previous or next row and its index is the same as the index of any of the digits of the number, OR +1/-1
# consider the data as a matrix
# Lets convert the data to a matrix, where the numbers stay, but symbols are -1 and . are 0
matrix = np.zeros((len(data), len(data[0])), dtype=np.int32)
for i in range(len(data)):
for j in range(len(data[i])):
if data[i][j] == "*":
matrix[i,j] = -3
elif data[i][j] == ".":
matrix[i,j] = -2
elif data[i][j] in symbols:
matrix[i,j] = -1
else:
matrix[i,j] = int(data[i][j])
print(matrix)
# Now we find all symbols in the matrix, and see if they are adjacent to any number
symbol_indices = np.where(matrix == -3)
print(f"Symbol indices = {symbol_indices}")
def get_adjacent_indices(A, ind):
""" Get all indices adjacent to the given index.
"""
# Get the indices of the adjacent elements
indices = [
(ind[0]-1, ind[1]-1),
(ind[0]-1, ind[1]),
(ind[0]-1, ind[1]+1),
(ind[0], ind[1]-1),
(ind[0], ind[1]+1),
(ind[0]+1, ind[1]-1),
(ind[0]+1, ind[1]),
(ind[0]+1, ind[1]+1),
]
# Filter out indices that are outside the matrix
indices = [ind for ind in indices if ind[0] >= 0 and ind[0] < A.shape[0] and ind[1] >= 0 and ind[1] < A.shape[1]]
return indices
def find_connected_digits(A, ind):
""" Find all digits that are before or after the given index, and return the indices of all of them.
"""
if A[ind] < 0:
return []
# Then go backwards on the row, to find the first digit
for j in range(ind[1], -1, -1):
#print(f"j = {j}")
if A[ind[0], j] < 0:
# If the loop breaks, the last digit was at j+1
j += 1
break
# If the loop didn't break, the last digit is at j = 0
# Now we know that the first digit is at (ind[0], j)
first_digit_index = (ind[0], j)
# Find the last digit
for j in range(ind[1], A.shape[1]):
if A[ind[0], j] < 0:
# If the loop breaks, the last digit was at j-1
j -= 1
break
# Otherwise, the last digit is at j = A.shape[1]-1
last_digit_index = (ind[0], j)
return [(ind[0], j) for j in range(first_digit_index[1], last_digit_index[1]+1)]
found_numbers = []
for symbol_row_idx, symbol_col_idx in zip(symbol_indices[0], symbol_indices[1]):
#print(f"Symbol index = {(symbol_row_idx, symbol_col_idx)}")
# Get the indices of the adjacent elements
adjacent_indices = get_adjacent_indices(matrix, (symbol_row_idx, symbol_col_idx))
digits_connected_to_symbol = []
digits_connected_to_symbol_indices = []
# For each adjacent index we find the indices of digits that are connected to it
for adj_row_idx, adj_col_idx in adjacent_indices:
connected_digits = find_connected_digits(matrix, (adj_row_idx, adj_col_idx))
if not connected_digits:
continue
# Now we have the indices of a number that is adjacent to the symbol
number = int("".join([str(matrix[ind]) for ind in connected_digits]))
#print(f"Found number = {number}")
if connected_digits in digits_connected_to_symbol_indices:
continue
digits_connected_to_symbol.append(number)
digits_connected_to_symbol_indices.append(connected_digits)
if len(digits_connected_to_symbol) == 2:
found_numbers.append(digits_connected_to_symbol[0] * digits_connected_to_symbol[1])
#print(f"Matrix = \n{matrix}")
print(matrix[-1,:])
#print(f"Found numbers = {found_numbers}")
print(f"Total = {sum(found_numbers)}")
end = time.time()
print(f"Time taken = {end-start}")
#aocd.submit(sum(found_numbers), day=3, year=2020, part="1")