Skip to content
Snippets Groups Projects
Commit 5b407987 authored by Olle Kjellqvist's avatar Olle Kjellqvist
Browse files

Added some solutions

parent a97dc9e9
No related branches found
No related tags found
No related merge requests found
from typing import List, Tuple
import numpy as np
def read_file(filename: str) -> List[List[int]]:
with open(filename, 'r') as file:
data = file.read().strip().split('\n')
topographic_map = [[int(c) for c in row] for row in data]
return topographic_map
def get_all_indices(value: int, topographic_map: List[List[int]]) -> List[Tuple[int, int]]:
return [(i, j) for i in range(len(topographic_map)) for j in range(len(topographic_map[0])) if topographic_map[i][j] == value]
def create_value_map(topographic_map: List[List[int]]) -> np.ndarray:
height, width = len(topographic_map), len(topographic_map[0])
# Initialize values to 1 for all indices with value 9
value_map = {}
for i, j in get_all_indices(9, topographic_map):
value_map[(i, j)] = set([(i, j)])
# Iterate backwards from 8 to 0
for value in range(8, -1, -1):
for i, j in get_all_indices(value, topographic_map):
if (i, j) not in value_map:
value_map[(i, j)] = set()
if ((i + 1) <= (height - 1) and
topographic_map[i + 1][j] == value + 1):
value_map[(i, j)] = value_map[(i, j)].union(value_map[(i + 1, j)])
if ((i - 1) >= 0 and
topographic_map[i - 1][j] == value + 1):
value_map[(i, j)] = value_map[(i, j)].union(value_map[(i - 1, j)])
if ((j + 1) <= (width - 1) and
topographic_map[i][j + 1] == value + 1):
value_map[(i, j)] = value_map[(i, j)].union(value_map[(i, j + 1)])
if ((j - 1) >= 0 and
topographic_map[i][j - 1] == value + 1):
value_map[(i, j)] = value_map[(i, j)].union(value_map[(i, j - 1)])
value_sums = [[len(value_map[(i, j)]) for j in range(width)] for i in range(height)]
return np.array(value_sums)
def create_value_map_2(topographic_map: List[List[int]]) -> np.ndarray:
height, width = len(topographic_map), len(topographic_map[0])
value_map = np.zeros((height, width), dtype=int)
# Initialize values to 1 for all indices with value 9
for i, j in get_all_indices(9, topographic_map):
value_map[i][j] = 1
# Iterate backwards from 8 to 0
for value in range(8, -1, -1):
for i, j in get_all_indices(value, topographic_map):
if ((i + 1) <= (height - 1) and
topographic_map[i + 1][j] == value + 1):
value_map[i][j] += value_map[i + 1][j]
if ((i - 1) >= 0 and
topographic_map[i - 1][j] == value + 1):
value_map[i][j] += value_map[i - 1][j]
if ((j + 1) <= (width - 1) and
topographic_map[i][j + 1] == value + 1):
value_map[i][j] += value_map[i][j + 1]
if ((j - 1) >= 0 and
topographic_map[i][j - 1] == value + 1):
value_map[i][j] += value_map[i][j - 1]
return value_map
def sum_of_trailhead_scores(topographic_map: List[List[int]]) -> int:
value_map = create_value_map(topographic_map)
sum_scores = 0
for i, j in get_all_indices(0, topographic_map):
sum_scores += value_map[i][j]
return sum_scores
def sum_of_trailhead_scores_2(topographic_map: List[List[int]]) -> int:
value_map = create_value_map_2(topographic_map)
sum_scores = 0
for i, j in get_all_indices(0, topographic_map):
sum_scores += value_map[i][j]
return sum_scores
if __name__ == '__main__':
topographic_map = read_file('input')
print(sum_of_trailhead_scores(topographic_map))
print(sum_of_trailhead_scores_2(topographic_map))
from typing import List, Dict
import time
def read_file(filename:str) -> List[str]:
with open(filename) as f:
return f.read().strip().split(' ')
def read_file_optimized(filename:str) -> Dict[str, int]:
arrangement = read_file(filename)
new_arrangement = {}
for stone in arrangement:
try:
new_arrangement[stone] += 1
except KeyError:
new_arrangement[stone] = 1
return new_arrangement
def blink(arrangement:List[str]) -> List[str]:
new_arrangement = []
for stone in arrangement:
if int(stone) == 0:
new_arrangement.append('1')
elif len(stone) % 2 == 0:
first_half = stone[:len(stone)//2]
second_half = stone[len(stone)//2:]
# remove leading zeros of second half
second_half = str(int(second_half))
new_arrangement.append(first_half)
new_arrangement.append(second_half)
else:
new_arrangement.append(str(int(stone) * 2024))
return new_arrangement
def blink_optimized(arrangement: Dict[str, int]) -> Dict[str, int]:
new_arrangement = {}
for stone, count in arrangement.items():
if int(stone) == 0:
try:
new_arrangement['1'] += count
except KeyError:
new_arrangement['1'] = count
elif len(stone) % 2 == 0:
first_half = stone[:len(stone)//2]
second_half = stone[len(stone)//2:]
# remove leading zeros of second half
second_half = str(int(second_half))
try:
new_arrangement[first_half] += count
except KeyError:
new_arrangement[first_half] = count
try:
new_arrangement[second_half] += count
except KeyError:
new_arrangement[second_half] = count
else:
try:
new_arrangement[str(int(stone) * 2024)] += count
except KeyError:
new_arrangement[str(int(stone) * 2024)] = count
return new_arrangement
if __name__ == '__main__':
arrangement = read_file('input')
new_arrangement = read_file_optimized('input')
tic = time.time()
for i in range(25):
arrangement = blink(arrangement)
toc = time.time()
print(f"25 blinks took {toc-tic} seconds with unoptimized version")
print("Number of stones after 25 blinks: ", len(arrangement))
tic = time.time()
for i in range(25):
new_arrangement = blink_optimized(new_arrangement)
toc = time.time()
print(f"25 blinks took {toc-tic} seconds with optimized version")
print("Number of stones after 25 blinks: ", sum(new_arrangement.values()))
new_arrangement = read_file_optimized('input')
for i in range(75):
new_arrangement = blink_optimized(new_arrangement)
print("Number of stones after 75 blinks: ", sum(new_arrangement.values()))
from typing import List, Tuple
class Turtle:
def __init__(self, direction, environment, coords=(0, 0)):
self.direction = direction
self.coords = coords
self.environment = environment
self.has_visited = set([(coords[0], coords[1], direction)])
self.in_loop = False
def step(self) -> bool:
x, y = self.coords
if self.direction == 'N':
if y == 0:
return False
elif self.environment[y - 1][x] == '#':
self.direction = 'E'
else:
y -= 1
elif self.direction == 'E':
if x == len(self.environment[0]) - 1:
return False
elif self.environment[y][x + 1] == '#':
self.direction = 'S'
else:
x += 1
elif self.direction == 'S':
if y == len(self.environment) - 1:
return False
elif self.environment[y + 1][x] == '#':
self.direction = 'W'
else:
y += 1
elif self.direction == 'W':
if x == 0:
return False
elif self.environment[y][x - 1] == '#':
self.direction = 'N'
else:
x -= 1
else:
raise ValueError("Invalid direction")
# Update position and track visited coordinates
self.coords = (x, y)
if (x, y, self.direction) in self.has_visited:
self.in_loop = True
return False
self.has_visited.add((x, y, self.direction))
return True
def run(self):
while self.step():
pass
if self.in_loop:
return False
else:
return True
def get_visited(self) -> int:
return len(set([(x, y) for x, y, _ in self.has_visited]))
def get_starting_coords(environment: List[str]) -> Tuple[int, int]:
for row, col in enumerate(environment):
if '^' in col:
return (col.index('^'), row)
raise ValueError("Starting position not found in environment")
def read_file(filename: str) -> List[str]:
with open(filename, 'r') as f:
data = f.read().strip().split('\n')
return data
def get_p2_solution(filename: str) -> int:
orig_environment = read_file(filename)
start_coords = get_starting_coords(orig_environment)
num_loops = 0
for i in range(len(orig_environment)):
print(f"Row {i} of {len(orig_environment)}, num_loops: {num_loops}")
for j in range(len(orig_environment[0])):
if orig_environment[i][j] in ['^', '#']:
continue
environment = [list(row) for row in orig_environment]
environment[i][j] = '#'
turtle = Turtle(direction='N', environment=environment, coords=start_coords)
turtle.run()
if turtle.in_loop:
num_loops += 1
return num_loops
if __name__ == "__main__":
environment = read_file('input')
start_coords = get_starting_coords(environment)
turtle = Turtle(direction='N', environment=environment, coords=start_coords)
turtle.run()
print(turtle.get_visited())
print(get_p2_solution('input'))
from typing import List, Tuple
from math import log10
def read_file(file_name: str) -> Tuple[List[int], List[List[int]]]:
lhs = []
rhs = []
with open(file_name, 'r') as file:
for line in file:
if line == '':
break
line = line.strip().split(': ')
lhs.append(int(line[0]))
rhs.append([int(x) for x in line[1].split(' ')])
return lhs, rhs
def sum_valid_equations(lhs: List[int], rhs: List[List[int]]) -> int:
max_len = max(len(l) for l in rhs) - 1 # -1 because only operators between numbers
operator_table = [
[['+'], ['*']]
]
for i in range(1, max_len):
operator_table.append(
[o + operator for o in operator_table[-1] for operator in [['+'], ['*']]]
)
valid_lhs = 0
for l, r in zip(lhs, rhs):
operator_list = operator_table[len(r) - 2]
for operators in operator_list:
if check_equation(l, r, operators):
valid_lhs += l
break
return valid_lhs
def sum_valid_equations_p2(lhs: List[int], rhs: List[List[int]]) -> int:
max_len = max(len(l) for l in rhs) - 1 # -1 because only operators between numbers
operator_table = [
[['+'], ['*'], ['||']]
]
for i in range(1, max_len):
operator_table.append(
[o + operator for o in operator_table[-1] for operator in [['+'], ['*'],['||']]]
)
valid_lhs = 0
for l, r in zip(lhs, rhs):
operator_list = operator_table[len(r) - 2]
for operators in operator_list:
if check_equation(l, r, operators):
valid_lhs += l
break
return valid_lhs
def check_equation(lhs: int, rhs: List[int], operators: List[str]) -> bool:
result = rhs[0]
for i in range(1, len(rhs)):
if operators[i-1] == '+':
result += rhs[i]
elif operators[i-1] == '*':
result *= rhs[i]
elif operators[i-1] == '||':
result = result * 10**int(log10(rhs[i]) + 1) + rhs[i]
return result == lhs
if __name__ == "__main__":
lhs, rhs = read_file('input')
print(sum_valid_equations(lhs, rhs))
print(sum_valid_equations_p2(lhs, rhs))
from math import gcd
from typing import List, Set, Dict
def read_file(filename: str) -> List[str]:
with open(filename, 'r') as file:
data = file.read().strip().split('\n')
return data
def get_letters(environment: List[str]) -> Set[str]:
letters = set()
for row in environment:
letters = letters.union(set(row))
letters.discard('.')
return letters
def get_coordinates(environment: List[str]) -> Dict:
height = len(environment)
width = len(environment[0])
letter_coordinates = {}
for i in range(height):
line = environment[i]
for j in range(width):
if line[j] == '.':
continue
if line[j] in letter_coordinates.keys():
letter_coordinates[line[j]].append((i, j))
else:
letter_coordinates[line[j]] = [(i, j)]
return letter_coordinates
def num_of_antinodes(environment: List[str]) -> int:
height = len(environment)
width = len(environment[0])
antinodes = set()
coords_dict = get_coordinates(environment)
for key in coords_dict.keys():
if len(coords_dict[key]) < 2:
continue
else:
coords = coords_dict[key]
for j in range(len(coords) - 1):
for k in range(j + 1, len(coords)):
row1, col1 = coords[j]
row2, col2 = coords[k]
antinode1_row = 2 * row2 - row1
antinode2_row = 2 * row1 - row2
antinode1_col = 2 * col2 - col1
antinode2_col = 2 * col1 - col2
if (0 <= antinode1_row < height
and 0 <= antinode1_col < width):
antinodes.add((antinode1_row, antinode1_col))
if (0 <= antinode2_row < height
and 0 <= antinode2_col < width):
antinodes.add((antinode2_row, antinode2_col))
return len(antinodes)
def num_of_antinodes_2(environment: List[str]) -> int:
height = len(environment)
width = len(environment[0])
antinodes = set()
coords_dict = get_coordinates(environment)
for key in coords_dict.keys():
if len(coords_dict[key]) < 2:
continue
else:
coords = coords_dict[key]
for j in range(len(coords) - 1):
for k in range(j + 1, len(coords)):
row1, col1 = coords[j]
row2, col2 = coords[k]
rowdist = row2-row1
coldist = col2-col1
rowdist = rowdist // gcd(rowdist, coldist)
coldist = coldist // gcd(rowdist, coldist)
antirow, anticol = row1, col1
while (0 <= antirow < height and
0 <= anticol < height):
antinodes.add((antirow, anticol))
antirow += rowdist
anticol += coldist
antirow, anticol = row1, col1
antirow -= rowdist
anticol -= coldist
while (0 <= antirow < height and
0 <= anticol < height):
antinodes.add((antirow, anticol))
antirow -= rowdist
anticol -= coldist
return len(antinodes)
if __name__ == "__main__":
env = read_file("input")
print(num_of_antinodes(env))
print(num_of_antinodes_2(env))
from typing import List
def read_file(filename: str) -> str:
with open(filename) as f:
return f.readline().strip()
def get_id_representation(file: str) -> List[str]:
i = 0
id_rep = []
while i < len(file):
if i % 2 == 0:
id_rep += [str(i//2)]*int(file[i])
else:
id_rep += ['.']*int(file[i])
i += 1
return id_rep
def rearrange(id_rep: str) -> List[str]:
i = 0
j = len(id_rep) - 1
rearranged_rep = []
while i < j:
while id_rep[i].isnumeric() and i < j:
rearranged_rep += [id_rep[i]]
i += 1
while (id_rep[j] == '.') and i < j:
j -= 1
if i == j:
break
else:
rearranged_rep += [id_rep[j]]
i += 1
j -= 1
rearranged_rep += [id_rep[j]]
print(len(id_rep))
print(len(rearranged_rep))
return rearranged_rep + ['.'] * (len(id_rep) - len(rearranged_rep))
def rearrange_whole(file: str) -> List[str]:
file = list(file)
ids = []
i = 0
for i in range(len(file)):
if i % 2 == 0:
ids += [str(i // 2)]
else:
ids += [str('.')]
j = 1
while j <= (len(file) - 1):
if ids[-j] == '.':
j += 1
continue
i = 0
while (i < (len(file) - j) and
(ids[i].isnumeric() or int(file[i]) < int(file[-j]))):
i += 1
if i == (len(file) - j):
j += 1
continue
elif int(file[i]) == int(file[-j]):
ids[i], ids[-j] = ids[-j], ids[i]
file[i], file[-j] = file[-j], file[i]
j += 1
else:
numel_to_keep = int(file[i]) - int(file[-j])
file[i] = file[-j]
file = file[:i+1] + [str(numel_to_keep)] + file[i+1:]
ids[i], ids[-j] = ids[-j], ids[i]
ids = ids[:i+1] + ['.'] + ids[i+1:]
j += 2
rearranged_file = []
for i in range(len(file)):
rearranged_file += [ids[i]]*int(file[i])
return rearranged_file
def compute_checksum(arranged_file: List[str]) -> int:
checksum = 0
i = 0
while arranged_file[i].isnumeric():
checksum += int(arranged_file[i]) * i
i += 1
return checksum
def compute_checksum_whole(arranged_file: List[str]) -> int:
checksum = 0
i = 0
for i in range(len(arranged_file)):
if arranged_file[i].isnumeric():
checksum += int(arranged_file[i]) * i
return checksum
if __name__ == "__main__":
file = read_file('input')
id_rep = get_id_representation(file)
print(compute_checksum(rearrange(id_rep)))
print(compute_checksum_whole(rearrange_whole(file)))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment