A combination of poor reading and not wanting to give up code that I had already written.
Part 1 | Part 2 | Total | |
---|---|---|---|
Time | 41:20 | 42:51 | 1:24:11 |
Oh boy, I really wanted to clean up this code before posting it, but I think it better serves as an example of how not to do an Advent of Code problem. Below is a list of things I did wrong in Part 1, that made a simple problem take substantially longer.
- I did not read the problem properly. I found internal reflections, instead of checking for "perfect" reflections that went to the edge of the valley. This caused me to make logic for finding multiple reflections and picking the "biggest" one. Even though the input was designed for there to be decisively only one line of reflection - which the problem stated multiple times - I was unnecessarily handling that case.
- I refused to let go of bad code. I forced my idea of how I wanted to code it to fit the problem, rather than letting the problem shape my code. I was wrestling with bad variable names and duplicated segments. Instead of forcing your code to work, consider a restart, sometimes even when you're going for time.
- Duplicated code fragments and multi-line initialization sections, ewww. Lots of scrolling was done. This goes for Part 2 as well.
from helpers.datagetter import aocd_data_in
import numpy as np
din, aocd_submit = aocd_data_in(split=True, numbers=False)
ans = 0
matrixes = []
matrix = []
for line in din:
if len(line) == 0:
matrixes.append(matrix)
matrix = []
continue
mline = []
for c in line:
mline.append(0 if c == "." else 1)
matrix.append(mline)
matrixes.append(matrix)
for matrix in matrixes:
matrix = np.array(matrix)
i = 0
j = 1
old_i = i
old_j = j
found = False
vertical_reflections = [[0]]
while i < matrix.shape[1] and j < matrix.shape[1]:
if np.array_equal(matrix[:, i], matrix[:, j]):
if not found:
old_i = i
old_j = j
found = True
i -= 1
j += 1
else:
if found:
if i == -1 or j == matrix.shape[1]:
vertical_reflections.append([old_i - i, old_i])
i = old_i
j = old_j
found = False
i += 1
j += 1
if found:
if i == -1 or j == matrix.shape[1]:
vertical_reflections.append([old_i - i, old_i])
vertical_reflections.sort(key=lambda x: -x[0])
i = 0
j = 1
old_i = i
old_j = j
found = False
horizontal_reflections = [[0]]
while i < matrix.shape[0] and j < matrix.shape[0]:
if np.array_equal(matrix[i, :], matrix[j, :]):
if not found:
old_i = i
old_j = j
found = True
i -= 1
j += 1
else:
if found:
if i == -1 or j == matrix.shape[0]:
horizontal_reflections.append([old_i - i, old_i])
i = old_i
j = old_j
found = False
i += 1
j += 1
if found:
if i == -1 or j == matrix.shape[0]:
horizontal_reflections.append([old_i - i, old_i])
horizontal_reflections.sort(key=lambda x: -x[0])
if vertical_reflections[0][0] > horizontal_reflections[0][0]:
ans += vertical_reflections[0][1] + 1
else:
ans += (horizontal_reflections[0][1] + 1) * 100
aocd_submit(ans)
You will see that a number of the pitfalls from Part 1 remain. This is because, for the most part, when I see a Part 2 I immediately copy over my Part 1 code and begin making changes to suit the input.
- I did the thing I just said. Instead of taking the time to update my code according to what I had learned, I kept working with the flawed code from Part 1. This was in spite of already figuring out that there was only going to be one perfect reflection. Not only would my code be much prettier, but it would also run faster because I could have quit early.
- Using flags. Using flags is very helpful a lot of the time, but for me it can lead to confusion a lot of the time. Instead of flags, I could have used a variable to keep track of the number of differences between each pair of rows or columns, and then I wouldn't need that extra
elif
section. Technically my solution is fast, but it could be prettier without much speed penalty, the matrices aren't that big.
All of these combined mistakes lead to a delta that was just as long as Part 1, which wasn't good to begin with. Tomorrow, I will strive to read the problem closer when something doesn't work, be more willing to restart, and cut down on my use of flags when possible.
from helpers.datagetter import aocd_data_in
import numpy as np
din, aocd_submit = aocd_data_in(split=True, numbers=False)
ans = 0
matrixes = []
matrix = []
for line in din:
if len(line) == 0:
matrixes.append(matrix)
matrix = []
continue
mline = []
for c in line:
mline.append(0 if c == "." else 1)
matrix.append(mline)
matrixes.append(matrix)
for matrix in matrixes:
matrix = np.array(matrix)
vertical_reflections = [[0]]
for k in range(matrix.shape[1] - 1):
i = k
j = k + 1
found = False
xored = False
while i >= 0 and j < matrix.shape[1]:
xor = np.bitwise_xor(matrix[:, i], matrix[:, j])
if np.array_equal(matrix[:, i], matrix[:, j]):
found = True
i -= 1
j += 1
elif np.sum(xor) == 1 and not xored:
xored = True
found = True
i -= 1
j += 1
else:
break
if found and xored and (i == -1 or j == matrix.shape[1]):
vertical_reflections.append([k - i, k])
vertical_reflections.sort(key=lambda x: -x[0])
horizontal_reflections = [[0]]
for k in range(matrix.shape[0] - 1):
i = k
j = k + 1
found = False
xored = False
while i >= 0 and j < matrix.shape[0]:
xor = np.bitwise_xor(matrix[i, :], matrix[j, :])
if np.array_equal(matrix[i, :], matrix[j, :]):
found = True
i -= 1
j += 1
elif np.sum(xor) == 1 and not xored:
xored = True
found = True
i -= 1
j += 1
else:
break
if found and xored and (i == -1 or j == matrix.shape[0]):
horizontal_reflections.append([k - i, k])
break
horizontal_reflections.sort(key=lambda x: -x[0])
if vertical_reflections[0][0] > horizontal_reflections[0][0]:
ans += vertical_reflections[0][1] + 1
else:
ans += (horizontal_reflections[0][1] + 1) * 100
aocd_submit(ans)