Advent of Code: Day 8
Day8: Resonant Collinearity
Get ready to mess around with radio frequencies.
Where I finally learn what the heck "antinodes" are.
Check out Resonant Collinearity for the day8 puzzle.
Part 1
The first thing that I did was look up antinodes on wikipedia. spoiler: It didn't help.
I think the biggest challenge in this puzzle is to understand exactly what's being done to create an antinode. I had to read the puzzle description a few times before I got it: we need to look at the slope between two points and then extend out to find the next point.
I spend most of my coding time, parsing the input so that I could look at each frequency line by line. Once that was done this one came together pretty quickly.
Part 1 Solution:
import itertools
testPath = './testInput.txt'
inputPath = './input.txt'
chosenPath = inputPath
def parseInput(path):
frequencies = {}
with open(path, 'r') as file:
frequencies = {}
strings = [line.strip() for line in file.readlines()]
map = [list(string) for string in strings]
for y, col in enumerate(map):
for x, char in enumerate(col):
if char != '.':
frequencies[char] = []
for y, col in enumerate(map):
for x, char in enumerate(col):
if char != '.':
frequencies[char].append((x, y))
return (frequencies, map)
input, map = parseInput(chosenPath)
def getAntiNodes(key, frequencies):
print(f'key: {key} appears in map {len(frequencies)} times: {frequencies}
')
pairings = list(itertools.combinations(frequencies, 2))
def coordIsOffMap(coord):
x, y = coord
return x < 0 or x >= len(map[0]) or y < 0 or y >= len(map)
antinodes = []
for pair in pairings:
#print(f'pair: {pair[0]} and {pair[1]}')
distanceBetweenY = (pair[1][1] - pair[0][1])
distanceBetweenX = (pair[1][0] - pair[0][0])
#print(f'distance between: {distanceBetweenX}, {distanceBetweenY}')
antiNode1 = (pair[0][0] - distanceBetweenX, pair[0][1] - distanceBetweenY)
antiNode2 = (pair[1][0] + distanceBetweenX, pair[1][1] + distanceBetweenY)
#print(f'antiNode1 for {pair[0]}: {antiNode1}')
#print(f'antiNode2 for {pair[1]}: {antiNode2}
')
if not coordIsOffMap(antiNode1):
antinodes.append(antiNode1)
if not coordIsOffMap(antiNode2):
antinodes.append(antiNode2)
return antinodes
result = []
for key in input:
antiNodesByKey = (getAntiNodes(key, input[key]))
for coord in antiNodesByKey:
if coord not in result:
result.append(coord)
print(f'antiNodes: {len(result)}')
Part 2
I think the setup I did in the first part, helped me out quite a bit for part 2.
Instead of just appending the next node based on the slope, I had to keep on appending points until I fell off the map. Like the first part, this took me multiple reads of the puzzle description to understand the requirement.
I did get snagged a bit: because I had one sub-function that got both nodes, I ran into a problem when I tried to loop through the antinodes. each loop tried to figure out nodes for both pairs which led to an infinite loop. I had to refactor the function to get the antinodes for each pair separately.
for pair in pairings:
appendAntiNode1(pair)
appendAntiNode2(pair)
I made the adjustment to add discrete functions for each pair and then looped through each separately.
Once I did that, I still came up short. When I ran the function against the example given, I was still 3 nodes short on the solution. I reread the puzzle description once again and realized that the original nodes should also be included. I added a check to make sure that the original nodes were included in the antinodes array. That change got me the correct solution.
Part 2 Solution:
import itertools
# import sys
# limit = 10 ** 6
# sys.setrecursionlimit(limit)
testPath = './testInput.txt'
inputPath = './input.txt'
chosenPath = inputPath
def parseInput(path):
frequencies = {}
with open(path, 'r') as file:
frequencies = {}
strings = [line.strip() for line in file.readlines()]
map = [list(string) for string in strings]
for y, col in enumerate(map):
for x, char in enumerate(col):
if char != '.':
frequencies[char] = []
for y, col in enumerate(map):
for x, char in enumerate(col):
if char != '.':
frequencies[char].append((x, y))
return (frequencies, map)
input, map = parseInput(chosenPath)
def renderAntinodes(antinodes):
for y, col in enumerate(map):
for x, char in enumerate(col):
if (x, y) in antinodes:
print('#', end='')
else:
print(char, end='')
print('')
def getAntiNodes(key, frequencies):
print(f'key: {key} appears in map {len(frequencies)} times: {frequencies}
')
pairings = list(itertools.combinations(frequencies, 2))
def coordIsOffMap(coord):
x, y = coord
return x < 0 or x >= len(map[0]) or y < 0 or y >= len(map)
antinodes = []
def appendAntiNode1(pair):
if not antinodes.__contains__(pair[0]):
antinodes.append(pair[0])
if not antinodes.__contains__(pair[1]):
antinodes.append(pair[1])
distanceBetweenY = (pair[1][1] - pair[0][1])
distanceBetweenX = (pair[1][0] - pair[0][0])
def getAntiNode1(coord):
result = (coord[0] - distanceBetweenX, coord[1] - distanceBetweenY)
if not coordIsOffMap(result):
return result
antiNode1 = getAntiNode1(pair[0])
if antiNode1:
antinodes.append(antiNode1)
appendAntiNode1((antiNode1, pair[0]))
def appendAntiNode2(pair):
distanceBetweenY = (pair[1][1] - pair[0][1])
distanceBetweenX = (pair[1][0] - pair[0][0])
def getAntiNode2(coord):
result = (coord[0] + distanceBetweenX, coord[1] + distanceBetweenY)
if not coordIsOffMap(result):
return result
antiNode2 = getAntiNode2(pair[1])
if antiNode2:
antinodes.append(antiNode2)
newPair = (pair[1], antiNode2)
appendAntiNode2(newPair)
for pair in pairings:
appendAntiNode1(pair)
appendAntiNode2(pair)
renderAntinodes(antinodes)
return antinodes
result = []
for key in input:
antiNodesByKey = (getAntiNodes(key, input[key]))
for coord in antiNodesByKey:
if coord not in result:
result.append(coord)
print(f'antiNodes: {len(result)}')