@@ -0,0 +1,35 @@ | |||
# https://adventofcode.com/2024/day/1 | |||
# Calculate the sum of the distances between the smallest values in each | |||
# list, then the second-smallest, then the third-smallest, and so on. | |||
# The lists are the same length. | |||
FILENAME = "input01.txt" | |||
def main(): | |||
with open(FILENAME, "r") as file: | |||
lines = [line.strip().split() for line in file.readlines()] | |||
first_list, second_list = [], [] | |||
for line in lines: | |||
first_list.append(int(line[0])) | |||
second_list.append(int(line[1])) | |||
sorted_first = sorted(first_list) | |||
sorted_second = sorted(second_list) | |||
print(f"""First list: {first_list[:10]}... | |||
First list sorted: {sorted_first[:10]}... | |||
Second list: {second_list[:10]}... | |||
Second list sorted: {sorted_second[:10]}... | |||
""") | |||
sum_dists = 0 | |||
for i, el in enumerate(sorted_first): | |||
s_el = sorted_second[i] | |||
dist = abs(el-s_el) | |||
sum_dists += dist | |||
if i%5 == 0: | |||
print(f"Current locations {el} and {s_el}, current distance {dist}, accumulated distance {sum_dists}.") | |||
print(f"Total accumulated distance: {sum_dists}") | |||
return sum_dists | |||
if __name__ == "__main__": | |||
main() |
@@ -0,0 +1,28 @@ | |||
# https://adventofcode.com/2024/day/1#part2 | |||
# Calculate a similarity score by multiplying each value in list 1 | |||
# by the number of times it appears in list 2. If a value in list 1 | |||
# doesn't appear in list 2, it contributes 0 to the similarity score. | |||
FILENAME = "input01.txt" | |||
def main(): | |||
with open(FILENAME, "r") as file: | |||
lines = [line.strip().split() for line in file.readlines()] | |||
first_list, second_list = [], [] | |||
for line in lines: | |||
first_list.append(int(line[0])) | |||
second_list.append(int(line[1])) | |||
similarity = 0 | |||
for i, el in enumerate(first_list): | |||
el_num = second_list.count(el) | |||
el_sim = el * el_num | |||
similarity += el_sim | |||
if i%5 == 0: | |||
print(f"Current location {el}, which appears {el_num} times in list 2, current similarity {el_sim}, accumulated similarity {similarity}.") | |||
print(f"Total accumulated similarity: {similarity}") | |||
return similarity | |||
if __name__ == "__main__": | |||
main() |
@@ -0,0 +1,46 @@ | |||
import logging | |||
from itertools import pairwise | |||
from sys import stdout | |||
logger = logging.Logger(__name__) | |||
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') | |||
sh = logging.StreamHandler(stdout) | |||
sh.setLevel(logging.INFO) | |||
sh.setFormatter(formatter) | |||
fh = logging.FileHandler("./day02-1.log", mode="w", encoding="utf-8") | |||
fh.setLevel(logging.DEBUG) | |||
fh.setFormatter(formatter) | |||
logger.addHandler(sh) | |||
logger.addHandler(fh) | |||
# So, a report only counts as safe if both of the following are true: | |||
# The levels are either all increasing or all decreasing. | |||
# Any two adjacent levels differ by at least one and at most three. | |||
def main(): | |||
with open("input02.txt", "r", encoding="utf-8") as f: | |||
lines = [list(map(int,l.split(" "))) for l in f.readlines()] | |||
line_stats = [] | |||
for i, line in enumerate(lines): | |||
pw_l = list(pairwise(line)) | |||
ascending = all([x < y for x,y in pw_l]) | |||
descending = all([x > y for x,y in pw_l]) | |||
lessthan = all([abs(x - y) <= 3 for x,y in pw_l]) | |||
safe = (ascending or descending) and lessthan | |||
line_dict = {"ascending": ascending, "descending": descending, "less than 3": lessthan, "safe": (ascending or descending) and lessthan} | |||
line_stats.append(line_dict) | |||
if i % 5 == 0: | |||
logger.info(f"Spot check: {line} is {'' if safe else 'UN'}safe") | |||
else: | |||
logger.debug(f"{line}: {line_dict}") | |||
print(f"Number of safe lines: {sum([1 for s in line_stats if s['safe']])}") | |||
if __name__ == "__main__": | |||
main() |
@@ -0,0 +1,100 @@ | |||
import logging | |||
from itertools import pairwise | |||
from sys import stdout | |||
logger = logging.Logger(__name__) | |||
logger_2 = logging.Logger(f"{__name__}_2") | |||
formatter = logging.Formatter('[%(asctime)s][%(levelname)s] %(message)s') | |||
sh = logging.StreamHandler(stdout) | |||
sh.setLevel(logging.INFO) | |||
sh.setFormatter(formatter) | |||
fh = logging.FileHandler("./day02-2.log", mode="w", encoding="utf-8") | |||
fh_2 = logging.FileHandler("./day02-2_round2.log", mode="w", encoding="utf-8") | |||
fh.setLevel(logging.DEBUG) | |||
fh.setFormatter(formatter) | |||
fh_2.setLevel(logging.DEBUG) | |||
fh_2.setFormatter(formatter) | |||
logger.addHandler(sh) | |||
logger.addHandler(fh) | |||
logger_2.addHandler(fh_2) | |||
# So, a report only counts as safe if both of the following are true: | |||
# The levels are either all increasing or all decreasing. | |||
# Any two adjacent levels differ by at least one and at most three. | |||
# The Problem Dampener is a reactor-mounted module that lets the reactor | |||
# safety systems tolerate a single bad level in what would otherwise be a | |||
# safe report. It's like the bad level never happened! | |||
# Now, the same rules apply as before, except if removing a single level | |||
# from an unsafe report would make it safe, the report instead counts as safe. | |||
def report(msg, i=0, spotter=20, use_2=False): | |||
if i % spotter == 0: | |||
logger.info(msg) | |||
else: | |||
logger.debug(msg) | |||
if use_2: | |||
logger_2.debug(msg) | |||
def test_line(line): | |||
pw_l = list(pairwise(line)) | |||
raw_distances = [(y-x) for x,y in pw_l] | |||
abs_distances = [abs(x) for x in raw_distances] | |||
# -1 if the pair is going from high to low | |||
# 1 if the pair is going from low to high | |||
# 0 if the pair is equal | |||
directions = [-1 if x > y else (0 if x == y else 1) for x,y in pw_l] | |||
pure_ascending = all([d > 0 for d in directions]) | |||
pure_descending = all([d < 0 for d in directions]) | |||
pure_and_close = (pure_ascending or pure_descending) and all([1 <= d <= 3 for d in abs_distances]) | |||
report(f"""Line {line}: | |||
Pairs: {pw_l} | |||
Raw distances: {raw_distances} | |||
Absolute distances: {abs_distances} | |||
Directions: {directions} | |||
Pure ascending: {pure_ascending} | |||
Pure descending: {pure_descending} | |||
Pure and close: {pure_and_close}""", spotter=100, use_2=True) | |||
return { | |||
"Pairwise": pw_l, | |||
"Raw distances": raw_distances, | |||
"Absolute distances": abs_distances, | |||
"Directions": directions, | |||
"Pure ascending": pure_ascending, | |||
"Pure descending": pure_descending, | |||
"Pure and close": pure_and_close | |||
} | |||
def main(): | |||
with open("input02.txt", "r", encoding="utf-8") as f: | |||
lines = [list(map(int,l.split(" "))) for l in f.readlines()] | |||
line_stats = [] | |||
safe_lines = 0 | |||
for i, line in enumerate(lines): | |||
base_stats = test_line(line) | |||
line_stats.append(base_stats) | |||
if base_stats["Pure and close"]: | |||
safe_lines += 1 | |||
continue | |||
break_out = False | |||
j = 0 | |||
while not break_out and j < len(line): | |||
new_line = line[:j] + line[j+1:] | |||
report(f"Checking variant of line {line}: {new_line}") | |||
nl_stats = test_line(new_line) | |||
if nl_stats["Pure and close"]: | |||
safe_lines += 1 | |||
break_out = True | |||
continue | |||
j += 1 | |||
report(f"Number of safe lines: {safe_lines}") | |||
if __name__ == "__main__": | |||
main() |