Spoiler
with open("input8.txt") as f:
inp = [x[:-1] for x in f.readlines()]
data = [(x.split('|')[0].split(), x.split('|')[1].split()) for x in inp]
# Part 1
fourdigits = [x[1] for x in data]
print(sum([len(x) in [2,3,4,7] for x in [x for y in fourdigits for x in y]]))
# Part 2
# Segments: a: upper, b: upper left, c: upper right, d: central, e: lower left, f: lower right, g: lower
num_to_char = {0:'abcefg',
1:'cf',
2:'acdeg',
3:'acdfg',
4:'bcdf',
5:'abdfg',
6:'abdefg',
7:'acf',
8:'abcdefg',
9:'abcdfg'}
char_to_num = {y:x for x,y in num_to_char.items()}
def find_letters(inp):
"""Given a list of the digit segment (randomized) returns
a dict with the correspondence with the original segments (dict[random]=original)"""
# Convert every element of the list to a set
inp = [set(x) for x in inp]
corr = dict()
# Step 1: Find the letter which is in 7 (length = 3) but not in 1 (length = 2)
a = list([x for x in inp if len(x)==3][0] - [x for x in inp if len(x)==2][0])[0]
corr['a'] = a
# Step 2: Find b (appears 6 times), e (appears 4 times) and f (appears 9 times)
for char in 'abcdefg':
x = sum([char in x for x in inp])
if x==6:
corr['b'] = char
elif x==4:
corr['e'] = char
elif x==9:
corr['f'] = char
# Step 3: Find c as the only char appearing in 1 (unique set of len 2) which is not f
corr['c'] = list([x for x in inp if len(x)==2][0] - {corr['f']})[0]
# Step 4: Find g as the only char appearing in 0 which is not abcef
corr['g'] = list([x for x in inp if len(x)==6 and set([corr[ x ] for x in 'abcef']).issubset(x)][0]\
- {corr[ x ] for x in 'abcef'})[0]
# Step 5: Find d as the remaining letter
corr['d'] = [x for x in 'abcdefg' if x not in corr.values()][0]
return {y:x for x,y in corr.items()}
def word_to_num(inp, corr):
"""Given a list of 4 words returns the corresponding number.
Corr: dictionary giving the correspondences with original segments"""
digits = []
for x in inp:
x = char_to_num[''.join(sorted(list({corr[y] for y in x})))]
digits.append(x)
return sum([10**(3-i)*digits for i in range(4)])
def solve(inp):
"""Returns the sum of all 4-digit numbers"""
nums = []
for x,y in inp:
corr = find_letters(x)
nums.append(word_to_num(y,corr))
return sum(nums)
print(solve(data))
Spoiler
with open("input9.txt") as f:
inp = [x[:-1] for x in f.readlines()]
# Part 1
import numpy as np
matrix = np.array([[int(x) for x in y] for y in inp])
def local_minima(matrix):
"""Returns list with locations of all local minima"""
ncol, nrow = len(matrix), len(matrix[0])
matrix = np.pad(matrix, ((1,),(1,)), constant_values=(9,9))
minima=[]
for i in range(1, nrow+1):
for j in range(1, ncol+1):
if matrix[j] < min(matrix[i-1][j], matrix[j-1], matrix[i+1][j], matrix[j+1]):
minima.append((i-1,j-1))
return minima
minima = local_minima(matrix)
print(sum([matrix[j]+1 for i,j in minima]))
# Part 2
def basin(minima, matrix):
"""Returns a list with the points of the basin corresponding to the given minima"""
matrix = np.pad(matrix, ((1,),(1,)), constant_values=(9,9))
points = [minima]
iteration = points
end = False
while not end:
new_iter = []
for x in iteration:
list_pos = [(x[0]-1, x[1]), (x[0]+1, x[1]), (x[0], x[1]-1), (x[0], x[1]+1)]
new_iter = new_iter + [(i,j) for (i,j) in list_pos if matrix[i+1][j+1] != 9]
new_iter = [x for x in list(set(new_iter)) if x not in points]
if not new_iter:
end = True
iteration = new_iter
points = points + new_iter
return points
basin_sizes = [len(basin(x, matrix)) for x in minima]
print(np.prod(sorted(basin_sizes)[-3:]))