-
-
Save sreynen/ddc56f86ac9361edf02a6c3754bdcfba to your computer and use it in GitHub Desktop.
Advent of Code 2021
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
file = open('1a.txt', 'r') | |
depths = [int(line) for line in file.readlines()] | |
# Part A | |
def increases(values): | |
return [value for index, value in enumerate(values) | |
if index > 0 and value > values[index - 1]] | |
print(len(increases(depths))) | |
# Part B | |
windows = [depth + depths[index - 1] + depths[index - 2] | |
for index, depth in enumerate(depths) | |
if index > 1] | |
print(len(increases(windows))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from statistics import median | |
def is_invalid(line): | |
opens = ['(', '[', '{', '<'] | |
closes = [')', ']', '}', '>'] | |
stack = [] | |
for character in list(line): | |
if character in opens: | |
stack.append(character) | |
elif opens[closes.index(character)] == stack[-1]: | |
stack.pop() | |
else: | |
return [False, character, stack] | |
return [True, None, stack] | |
# Part A | |
lines = [line.strip() for line in open('10a.txt', 'r').readlines()] | |
scores = {')': 3, ']': 57, '}': 1197, '>': 25137} | |
line_validity = [is_invalid(line) for line in lines] | |
error_scores = [scores[validity[1]] for validity in line_validity if not validity[0]] | |
print(sum(error_scores)) | |
# Part B | |
incomplete_lines = [validity[2] for validity in line_validity if validity[0]] | |
autocomplete_scoring = ['(', '[', '{', '<'] | |
incomplete_line_scores = [] | |
for line in incomplete_lines: | |
score = 0 | |
for open_chunk in reversed(line): | |
score *= 5 | |
score += autocomplete_scoring.index(open_chunk) + 1 | |
incomplete_line_scores.append(score) | |
print(median(incomplete_line_scores)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def step(state): | |
state['flashed_in_step'] = set() | |
state['grid'] = [[value + 1 for value in row] for row in state['grid']] | |
still_flashing = True | |
while still_flashing: | |
to_flash = [[row_index, column_index] | |
for row_index, row in enumerate(state['grid']) | |
for column_index, value in enumerate(row) | |
if value > 9 | |
and tuple([row_index, column_index]) not in state['flashed_in_step']] | |
if len(to_flash): | |
state = flash(state, to_flash[0][0], to_flash[0][1]) | |
else: | |
still_flashing = False | |
state['grid'] = [[0 if value > 9 else value for value in row] for row in state['grid']] | |
return state | |
def flash(state, row_index, column_index): | |
state['flashed_in_step'].add(tuple([row_index, column_index])) | |
state['flashes'] += 1 | |
state['grid'][row_index][column_index] = 0 | |
if row_index > 0: | |
state = increase_if_not_flashed(state, row_index - 1, column_index) | |
if column_index > 0: | |
state = increase_if_not_flashed(state, row_index - 1, column_index - 1) | |
if column_index < 9: | |
state = increase_if_not_flashed(state, row_index - 1, column_index + 1) | |
if row_index < 9: | |
state = increase_if_not_flashed(state, row_index + 1, column_index) | |
if column_index > 0: | |
state = increase_if_not_flashed(state, row_index + 1, column_index - 1) | |
if column_index < 9: | |
state = increase_if_not_flashed(state, row_index + 1, column_index + 1) | |
if column_index > 0: | |
state = increase_if_not_flashed(state, row_index, column_index - 1) | |
if column_index < 9: | |
state = increase_if_not_flashed(state, row_index, column_index + 1) | |
return state | |
def increase_if_not_flashed(state, row_index, column_index): | |
if tuple([row_index, column_index]) not in state['flashed_in_step']: | |
state['grid'][row_index][column_index] += 1 | |
return state | |
lines = [[int(value) for value in line.strip()] for line in open('11a.txt', 'r').readlines()] | |
# Part A | |
state = dict(grid=lines, flashes=0, flashed_in_step=set()) | |
for i in range(0, 100): | |
state = step(state) | |
print(state['flashes']) | |
# Part B | |
state = dict(grid=lines, flashes=0, flashed_in_step=set()) | |
steps_taken = 0 | |
while len(state['flashed_in_step']) < 100: | |
state = step(state) | |
steps_taken += 1 | |
print(steps_taken) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
def paths_between(start, end, can_connect, visited=[]): | |
valid_paths = [] | |
if start in visited and start.lower() == start: | |
return [] | |
if start == end: | |
return [visited + [end]] | |
visited.append(start) | |
for point in can_connect[start]: | |
if point not in visited or point.lower() != point: | |
valid_paths += paths_between(point, end, can_connect, visited.copy()) | |
return valid_paths | |
def paths_between_repeat_small(start, end, can_connect, visited=[], small_repeated=False): | |
valid_paths = [] | |
if visited.count(start) > 1 and start.lower() == start and small_repeated: | |
return [] | |
if start == end: | |
return [visited + [end]] | |
visited.append(start) | |
for point in can_connect[start]: | |
if point not in visited or point.lower() != point: | |
valid_paths += paths_between_repeat_small(point, end, can_connect, visited.copy(), small_repeated) | |
elif point != 'start' and not small_repeated: | |
valid_paths += paths_between_repeat_small(point, end, can_connect, visited.copy(), True) | |
return valid_paths | |
paths = [line.strip().split('-') for line in open('12a.txt', 'r').readlines()] | |
connects_to = defaultdict(list) | |
for path in paths: | |
connects_to[path[0]].append(path[1]) | |
connects_to[path[1]].append(path[0]) | |
# Part A: | |
print(len(paths_between('start', 'end', connects_to))) | |
# Part B: | |
print(len(paths_between_repeat_small('start', 'end', connects_to))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def print_grid(points): | |
max_x = max([point[0] for point in points]) | |
max_y = max([point[1] for point in points]) | |
for y in range(0, max_y + 1): | |
for x in range(0, max_x + 1): | |
if (x, y) in points: | |
print('#', end='') | |
else: | |
print('.', end='') | |
print('') | |
def fold_grid(points, fold): | |
if fold[0] == 'y': | |
not_folding = [point for point in points if point[1] < fold[1]] | |
folding = [(point[0], (fold[1] - (point[1] - fold[1]))) for point in points if point[1] > fold[1]] | |
else: | |
not_folding = [point for point in points if point[0] < fold[1]] | |
folding = [((fold[1] - (point[0] - fold[1])), point[1]) for point in points if point[0] > fold[1]] | |
return list(set(not_folding + folding)) | |
lines = [line.strip() for line in open('13a.txt', 'r').readlines()] | |
points = [] | |
folds = [] | |
folding = False | |
for line in lines: | |
if folding: | |
folds.append([line.split()[2].split('=')[0], int(line.split()[2].split('=')[1])]) | |
elif len(line) == 0: | |
folding = True | |
else: | |
points.append(tuple([int(value) for value in line.split(',')])) | |
# Part A | |
points = fold_grid(points, folds[0]) | |
print(len(points)) | |
# Part B | |
for fold in folds[1:]: | |
points = fold_grid(points, fold) | |
print_grid(points) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import Counter | |
from itertools import pairwise | |
def step(pair_counts, letter_counts): | |
pairs = list(pair_counts) | |
new_pair_counts = Counter() | |
for pair in pairs: | |
if pair in replacements: | |
new_pair_counts[pair[0] + replacements[pair]] += pair_counts[pair] | |
new_pair_counts[replacements[pair] + pair[1]] += pair_counts[pair] | |
letter_counts[replacements[pair]] += pair_counts[pair] | |
else: | |
new_pair_counts[pair] += 1 | |
return new_pair_counts | |
lines = [line.strip() for line in open('14a.txt', 'r').readlines()] | |
template = lines[0] | |
replacements = {line.split(' -> ')[0]: line.split(' -> ')[1] for line in lines[2:]} | |
pairs = [''.join(pair) for pair in pairwise(template)] | |
# Part A | |
pair_counts = Counter(pairs) | |
letter_counts = Counter(template) | |
for i in range(0, 10): | |
pair_counts = step(pair_counts, letter_counts) | |
letter_count_numbers = letter_counts.values() | |
print(max(letter_count_numbers) - min(letter_count_numbers)) | |
# Part B | |
for i in range(0, 30): | |
pair_counts = step(pair_counts, letter_counts) | |
letter_count_numbers = letter_counts.values() | |
print(max(letter_count_numbers) - min(letter_count_numbers)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import networkx | |
def graph_from_grid(grid): | |
graph = networkx.DiGraph() | |
max_x = len(grid[0]) - 1 | |
max_y = len(grid) - 1 | |
for y in range(0, max_y + 1): | |
for x in range(0, max_x + 1): | |
if y > 0: | |
graph.add_edge(tuple([x, y]), tuple([x, y - 1]), weight=grid[y - 1][x]) | |
if y < max_y: | |
graph.add_edge(tuple([x, y]), tuple([x, y + 1]), weight=grid[y + 1][x]) | |
if x < 0: | |
graph.add_edge(tuple([x, y]), tuple([x - 1, y]), weight=grid[y][x - 1]) | |
if x < max_x: | |
graph.add_edge(tuple([x, y]), tuple([x + 1, y]), weight=grid[y][x + 1]) | |
return graph, max_x, max_y | |
grid = [[int(value) for value in line.strip()] for line in open('15a.txt', 'r').readlines()] | |
# Part A | |
graph, max_x, max_y = graph_from_grid(grid) | |
print(networkx.shortest_path_length(graph, source=tuple([0, 0]), target=tuple([max_y, max_x]), weight='weight')) | |
# Part B | |
for y in range(0, max_y + 1): | |
for x in range(0, max_x + 1): | |
for y_add in range(0, 5): | |
for x_add in range(0, 5): | |
if y_add > 0 or x_add > 0: | |
new_value = grid[y][x] + x_add + y_add | |
if new_value > 9: | |
new_value -= 9 | |
new_y = y + (y_add * (max_y + 1)) | |
new_x = x + (x_add * (max_x + 1)) | |
while new_y > len(grid) - 1: | |
grid.append([]) | |
while new_x > len(grid[new_y]) - 1: | |
grid[new_y].append(0) | |
grid[new_y][new_x] = new_value | |
graph, max_x, max_y = graph_from_grid(grid) | |
print(networkx.shortest_path_length(graph, source=tuple([0, 0]), target=tuple([max_y, max_x]), weight='weight')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import numpy | |
def parser(bits, tokens=[]): | |
if len(tokens) == 0: | |
tokens.append(dict(type='version', value=int(bits[0:3], 2))) | |
return parser(bits[3:], tokens) | |
elif tokens[-1]['type'] == 'version': | |
tokens.append(dict(type='type', value=int(bits[0:3], 2))) | |
return parser(bits[3:], tokens) | |
elif tokens[-1]['type'] == 'type' and tokens[-1]['value'] != 4: | |
tokens.append(dict(type='length_type', value=int(bits[0:1], 2))) | |
return parser(bits[1:], tokens) | |
elif tokens[-1]['type'] == 'length_type' and tokens[-1]['value'] == 0: | |
supackets_length = int(bits[0:15], 2) | |
tokens.append(dict(type='length', value=supackets_length)) | |
remainder = bits[15:] | |
subpackets = [] | |
while len(bits[15:]) - len(remainder) < supackets_length: | |
subpacket_tokens, remainder = parser(remainder, []) | |
subpackets.append(subpacket_tokens) | |
tokens.append(dict(type='subpackets', value=subpackets)) | |
elif tokens[-1]['type'] == 'length_type' and tokens[-1]['value'] == 1: | |
supackets_length = int(bits[0:11], 2) | |
tokens.append(dict(type='length', value=supackets_length)) | |
remainder = bits[11:] | |
subpackets = [] | |
while len(subpackets) < supackets_length: | |
subpacket_tokens, remainder = parser(remainder, []) | |
subpackets.append(subpacket_tokens) | |
tokens.append(dict(type='subpackets', value=subpackets)) | |
elif tokens[-1]['type'] == 'last': | |
tokens.append(dict(type='value', value=bits[0:4])) | |
if tokens[-2]['value'] == 1: | |
return parser(bits[4:], tokens) | |
else: | |
remainder = bits[4:] | |
else: | |
tokens.append(dict(type='last', value=int(bits[0:1], 2))) | |
return parser(bits[1:], tokens) | |
return tokens, remainder | |
def version_sum(tokens): | |
total_sum = sum([token['value'] for token in tokens | |
if token['type'] == 'version']) | |
subpacket_sets = [token for token in tokens | |
if token['type'] == 'subpackets'] | |
for subpackets in subpacket_sets: | |
for subpacket in subpackets['value']: | |
total_sum += version_sum(subpacket) | |
return total_sum | |
def calculate(tokens): | |
type = [token for token in tokens if token['type'] == 'type'][0]['value'] | |
sub_values = [] | |
subpacket_sets = [token for token in tokens | |
if token['type'] == 'subpackets'] | |
for subpackets in subpacket_sets: | |
for subpacket in subpackets['value']: | |
sub_values.append(calculate(subpacket)) | |
if type == 0: | |
return sum(sub_values) | |
elif type == 1: | |
return numpy.prod(sub_values) | |
elif type == 2: | |
return min(sub_values) | |
elif type == 3: | |
return max(sub_values) | |
elif type == 4: | |
bin_value = ''.join([token['value'] for token in tokens if token['type'] == 'value']) | |
return int(bin_value, 2) | |
elif type == 5: | |
if sub_values[0] > sub_values[1]: | |
return 1 | |
return 0 | |
elif type == 6: | |
if sub_values[0] < sub_values[1]: | |
return 1 | |
return 0 | |
elif type == 7: | |
if sub_values[0] == sub_values[1]: | |
return 1 | |
return 0 | |
return 0 | |
hex = [line.strip() for line in open('16a.txt', 'r').readlines()][0] | |
binary = ''.join([bin(int(digit, 16))[2:].zfill(4) for digit in hex]) | |
values, remainder = parser(binary) | |
# Part A | |
print(version_sum(values)) | |
# Part B | |
print(calculate(values)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
line = [line.strip() for line in open('17a.txt', 'r').readlines()][0] | |
area = line.split(': ')[1] | |
x_range, y_range = [value.split('=')[1] for value in area.split(', ')] | |
x_min, x_max = [int(value) for value in x_range.split('..')] | |
y_min, y_max = [int(value) for value in y_range.split('..')] | |
# Part A | |
valid_y_velocities = [] | |
for starting_y_velocity in range(y_min, 10000): | |
high_y = 0 | |
y = 0 | |
y_velocity = starting_y_velocity | |
steps = 0 | |
while y >= y_min: | |
y += y_velocity | |
y_velocity -= 1 | |
steps += 1 | |
if y > high_y: | |
high_y = y | |
if y_min <= y <= y_max: | |
valid_y_velocities.append([starting_y_velocity, steps, high_y]) | |
valid_y_steps = [velocity[1] for velocity in valid_y_velocities] | |
max_y_steps = max(valid_y_steps) | |
valid_x_velocities = [] | |
for starting_x_velocity in range(1, x_max + 1): | |
x = 0 | |
x_velocity = starting_x_velocity | |
steps = 0 | |
while x <= x_max and steps <= max_y_steps: | |
x += x_velocity | |
if x_velocity > 0: | |
x_velocity -= 1 | |
steps += 1 | |
if x_min <= x <= x_max: | |
valid_x_velocities.append([starting_x_velocity, steps]) | |
valid_steps = [velocity[1] for velocity in valid_x_velocities if velocity[1] in valid_y_steps] | |
matching_y_velocities = [velocity for velocity in valid_y_velocities if velocity[1] in valid_steps] | |
print(max([velocity[2] for velocity in matching_y_velocities])) | |
# Part B | |
matching_x_velocities = [velocity for velocity in valid_x_velocities if velocity[1] in valid_steps] | |
valid_velocities = set() | |
for y_velocity in matching_y_velocities: | |
for x_velocity in [velocity for velocity in valid_x_velocities | |
if velocity[1] == y_velocity[1]]: | |
valid_velocities.add(tuple([x_velocity[0], y_velocity[0]])) | |
print(len(valid_velocities)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
file = open('2a.txt', 'r') | |
commands = [line.split() for line in file.readlines()] | |
# Part A | |
def directional_total(direction, commands): | |
return sum([int(command[1]) for command in commands if command[0] == direction]) | |
forward_total = directional_total('forward', commands) | |
down_total = directional_total('down', commands) | |
up_total = directional_total('up', commands) | |
print(forward_total * (down_total - up_total)) | |
# Part B | |
aim = 0 | |
position = 0 | |
depth = 0 | |
for command in commands: | |
direction = command[0] | |
value = int(command[1]) | |
if direction == 'forward': | |
position += value | |
depth += aim * value | |
elif direction == 'up': | |
aim -= value | |
elif direction == 'down': | |
aim += value | |
print(position * depth) | |
# Part B, take 2 | |
forward_total = directional_total('forward', commands) | |
depth_changes = [(directional_total('down', commands[:index]) - directional_total('up', commands[:index])) * int(command[1]) | |
for index, command in enumerate(commands) if command[0] == 'forward' and index > 0] | |
print(forward_total * sum(depth_changes)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from statistics import mode | |
file = open('3a.txt', 'r') | |
binary_numbers = [line.strip() for line in file.readlines()] | |
# Part A | |
def characters_at_index(index, strings): | |
return [string[index] for string in strings] | |
def binary_list_to_int(binary_list): | |
return int(''.join(binary_list), 2) | |
most_common = [mode(characters_at_index(index, binary_numbers)) | |
for index, digit in enumerate(list(binary_numbers[0]))] | |
least_common = [['1', '0'][int(digit)] for digit in most_common] | |
gamma = binary_list_to_int(most_common) | |
epsilon = binary_list_to_int(least_common) | |
print(gamma * epsilon) | |
# Part B | |
def ogr_filter(numbers, index): | |
characters = characters_at_index(index, numbers) | |
ones = characters.count('1') | |
zeros = characters.count('0') | |
digit = '1' | |
if zeros > ones: | |
digit = '0' | |
return [number for number in numbers if number[index] == digit] | |
def csr_filter(numbers, index): | |
characters = characters_at_index(index, numbers) | |
ones = characters.count('1') | |
zeros = characters.count('0') | |
digit = '0' | |
if zeros > ones: | |
digit = '1' | |
return [number for number in numbers if number[index] == digit] | |
ogr_values = binary_numbers | |
index = 0 | |
while len(ogr_values) > 1: | |
ogr_values = ogr_filter(ogr_values, index) | |
index += 1 | |
csr_values = binary_numbers | |
index = 0 | |
while len(csr_values) > 1: | |
csr_values = csr_filter(csr_values, index) | |
index += 1 | |
ogr = int(ogr_values[0], 2) | |
csr = int(csr_values[0], 2) | |
print(ogr * csr) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import chain | |
file = open('4a.txt', 'r') | |
lines = [line.strip() for line in file.readlines()] | |
# Part A | |
calls = [int(number) for number in lines[0].split(',')] | |
boards = [] | |
line_index = 2 | |
while line_index < len(lines): | |
rows = [[int(number) for number in lines[row_index].split()] | |
for row_index in list(range(line_index, line_index + 5))] | |
columns = [[row[column_index] for row in rows] | |
for column_index in list(range(0, 5))] | |
board = { | |
'full': list(chain.from_iterable(rows)), | |
'wins': rows + columns | |
} | |
boards.append(board) | |
line_index += 6 | |
def won(board): | |
return len([win for win in board['wins'] if len(win) == 0]) > 0 | |
def marked_board(board, call): | |
return { | |
'full': [number for number in board['full'] if number != call], | |
'wins': [[number for number in win if number != call] for win in board['wins']] | |
} | |
call_index = 0 | |
won_boards = [] | |
while len(won_boards) == 0: | |
boards = [marked_board(board, calls[call_index]) for board in boards] | |
won_boards = [board for board in boards if won(board)] | |
call_index += 1 | |
unmarked = sum(won_boards[0]['full']) | |
last_call = calls[call_index - 1] | |
print(unmarked * last_call) | |
# Part B | |
unwon_boards = [board for board in boards if not won(board)] | |
while len(unwon_boards) > 1: | |
boards = [marked_board(board, calls[call_index]) for board in boards] | |
unwon_boards = [board for board in boards if not won(board)] | |
call_index += 1 | |
last_board = unwon_boards[0] | |
while not won(last_board): | |
last_board = marked_board(last_board, calls[call_index]) | |
call_index += 1 | |
unmarked = sum(last_board['full']) | |
last_call = calls[call_index - 1] | |
print(unmarked * last_call) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import Counter | |
from itertools import chain | |
def smart_range(a, b): | |
return list(range(a, b + 1) if b > a else reversed(range(b, a + 1))) | |
def points_between(a, b, diagonals=False): | |
if a[0] == b[0]: | |
return [(a[0], y) for y in smart_range(a[1], b[1])] | |
elif a[1] == b[1]: | |
return [(x, a[1]) for x in smart_range(a[0], b[0])] | |
elif diagonals: | |
return list(zip(smart_range(a[0], b[0]), smart_range(a[1], b[1]))) | |
else: | |
return [] | |
lines = [line.strip() for line in open('5ex.txt', 'r').readlines()] | |
line_ends = [[[int(coordinate) for coordinate in coordinates.split(',')] | |
for coordinates in line.split(' -> ')] | |
for line in lines] | |
line_points = chain.from_iterable([points_between(a, b, False) for a, b in line_ends]) | |
duplicate_points = [point for point, count in Counter(line_points).items() | |
if count > 1] | |
print(len(duplicate_points)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import Counter | |
file = open('5a.txt', 'r') | |
lines = [line.strip() for line in file.readlines()] | |
# Part A | |
line_ends = [[[int(coordinate) for coordinate in coordinates.split(',')] | |
for coordinates in line.split(' -> ')] | |
for line in lines] | |
vertical_line_ends = [sorted(end, key=lambda point: point[1]) | |
for end in line_ends if end[0][0] == end[1][0]] | |
horizontal_line_ends = [sorted(end, key=lambda point: point[0]) | |
for end in line_ends if end[0][1] == end[1][1]] | |
vertical_line_coordinates = [(end[0][0], y) | |
for end in vertical_line_ends | |
for y in list(range(end[0][1], end[1][1] + 1))] | |
horizontal_line_coordinates = [(x, end[0][1]) | |
for end in horizontal_line_ends | |
for x in list(range(end[0][0], end[1][0] + 1))] | |
all_coordinates = vertical_line_coordinates + horizontal_line_coordinates | |
duplicate_coordinates = [coordinate for coordinate, count in Counter(all_coordinates).items() | |
if count > 1] | |
print(len(duplicate_coordinates)) | |
# Part B | |
diagonal_up_line_ends = [end for end in line_ends | |
if abs(end[0][0] - end[1][0]) == abs(end[0][1] - end[1][1]) | |
and end[1][1] < end[0][1]] | |
diagonal_down_line_ends = [end for end in line_ends | |
if abs(end[0][0] - end[1][0]) == abs(end[0][1] - end[1][1]) | |
and end[1][1] > end[0][1]] | |
def sign(first, second): | |
return (second - first) / abs(second - first) | |
diagonal_up_line_coordinates = [(end[1][0] - int(diff * sign(end[0][0], end[1][0])), y) | |
for end in diagonal_up_line_ends | |
for diff, y in enumerate(list(range(end[1][1], end[0][1] + 1)))] | |
diagonal_down_line_coordinates = [(end[0][0] + int(diff * sign(end[0][0], end[1][0])), y) | |
for end in diagonal_down_line_ends | |
for diff, y in enumerate(list(range(end[0][1], end[1][1] + 1)))] | |
all_coordinates += diagonal_up_line_coordinates + diagonal_down_line_coordinates | |
duplicate_coordinates = [coordinate for coordinate, count in Counter(all_coordinates).items() | |
if count > 1] | |
print(len(duplicate_coordinates)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import lru_cache | |
@lru_cache(maxsize=1000) | |
def fish_production(countdown, days): | |
if countdown - days > -1: | |
return 1 | |
new_days = days - (countdown + 1) | |
return fish_production(6, new_days) + fish_production(8, new_days) | |
lines = [line.strip() for line in open('6a.txt', 'r').readlines()] | |
fish = tuple(int(number) for number in lines[0].split(',')) | |
# Part A | |
print(sum([fish_production(n, 80) for n in fish])) | |
# Part B | |
print(sum([fish_production(n, 256) for n in fish])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from functools import lru_cache | |
@lru_cache(maxsize=10000) | |
def fuel_for_distance(distance): | |
return sum(range(1, distance + 1)) | |
lines = [line.strip() for line in open('7a.txt', 'r').readlines()] | |
crabs = [int(number) for number in lines[0].split(',')] | |
# Part A | |
print(min([sum([abs(position - crab) for crab in crabs]) for position in range(min(crabs), max(crabs))])) | |
# Part B | |
print(min([sum([fuel_for_distance(abs(position - crab)) for crab in crabs]) for position in range(min(crabs), max(crabs))])) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import chain | |
def output_from_digit(digit, unique_digits): | |
if digit == 0: | |
return [unique for unique in unique_digits | |
if len(unique) == 6 | |
and output_from_digit(7, unique_digits).issubset(unique) | |
and not output_from_digit(5, unique_digits).issubset(unique)][0] | |
if digit == 1: | |
return [unique for unique in unique_digits | |
if len(unique) == 2][0] | |
if digit == 2: | |
return [unique for unique in unique_digits | |
if len(unique) == 5 | |
and not output_from_digit(1, unique_digits).issubset(unique) | |
and not unique.issubset(output_from_digit(6, unique_digits))][0] | |
if digit == 3: | |
return [unique for unique in unique_digits | |
if len(unique) == 5 | |
and output_from_digit(1, unique_digits).issubset(unique)][0] | |
if digit == 4: | |
return [unique for unique in unique_digits | |
if len(unique) == 4][0] | |
if digit == 5: | |
return [unique for unique in unique_digits | |
if len(unique) == 5 | |
and not output_from_digit(1, unique_digits).issubset(unique) | |
and unique.issubset(output_from_digit(6, unique_digits))][0] | |
if digit == 6: | |
return [unique for unique in unique_digits | |
if len(unique) == 6 | |
and not output_from_digit(7, unique_digits).issubset(unique)][0] | |
if digit == 7: | |
return [unique for unique in unique_digits | |
if len(unique) == 3][0] | |
if digit == 8: | |
return [unique for unique in unique_digits | |
if len(unique) == 7][0] | |
if digit == 9: | |
return [unique for unique in unique_digits | |
if len(unique) == 6 | |
and output_from_digit(7, unique_digits).issubset(unique) | |
and output_from_digit(5, unique_digits).issubset(unique)][0] | |
def numeric_output(unique_digits, output): | |
every_digit = [output_from_digit(digit, unique_digits) for digit in range(0, 10)] | |
output_digits = [every_digit.index(digit) for digit in output] | |
return int(''.join([str(digit) for digit in output_digits])) | |
# Part A | |
lines = [line.strip() for line in open('8a.txt', 'r').readlines()] | |
uniques = [[set(item) for item in line.split(' | ')[0].split()] for line in lines] | |
outputs = [[set(item) for item in line.split(' | ')[1].split()] for line in lines] | |
output_lengths = [[len(item) for item in output] for output in outputs] | |
unique_digit_counts = [2, 3, 4, 7] | |
unique_digit_output_lengths = [length for length in chain.from_iterable(output_lengths) | |
if length in unique_digit_counts] | |
print(len(unique_digit_output_lengths)) | |
# Part B | |
numeric_outputs = [numeric_output(uniques[index], output) for index, output in enumerate(outputs)] | |
print(sum(numeric_outputs)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from itertools import chain | |
lines = ['9' + line.strip() + '9' for line in open('9a.txt', 'r').readlines()] | |
lines = ['9' * len(lines[0])] + lines + ['9' * len(lines[0])] | |
# Part A | |
low_points = [int(value) + 1 | |
for row, line in enumerate(lines[1:-1]) | |
for column, value in enumerate(line[1:-1]) | |
if int(value) < int(lines[row][column + 1]) | |
and int(value) < int(lines[row + 2][column + 1]) | |
and int(value) < int(lines[row + 1][column]) | |
and int(value) < int(lines[row + 1][column + 2])] | |
print(sum(low_points)) | |
# Part B | |
basins = [] | |
for i in range(0, len(lines)): | |
basins.append(['9'] * len(lines[0])) | |
basin_letter = 'a' | |
for row, line in enumerate(lines[1:-1]): | |
for column, value in enumerate(line[1:-1]): | |
if value != '9': | |
if basins[row][column + 1] != '9': | |
basins[row + 1][column + 1] = basins[row][column + 1] | |
elif basins[row + 1][column] != '9': | |
basins[row + 1][column + 1] = basins[row + 1][column] | |
else: | |
basins[row + 1][column + 1] = basin_letter | |
basin_letter = chr(ord(basin_letter) + 1) | |
merged = True | |
while merged: | |
merged = False | |
for row, line in enumerate(basins[1:-1]): | |
for column, value in enumerate(line[1:-1]): | |
previous_value = basins[row + 1][column] | |
if value != '9' and previous_value != '9' and value != previous_value: | |
basins = [[letter if letter != value else previous_value for letter in update_row] for update_row in basins] | |
merged = True | |
flat_basins = list(chain.from_iterable(basins)) | |
basins_set = set(flat_basins) | |
basins_set.remove('9') | |
basin_sizes = sorted([flat_basins.count(item) for item in basins_set]) | |
print(basin_sizes[-3] * basin_sizes[-2] * basin_sizes[-1]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment