| # 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() |
| # 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() |
| 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() |
| 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() |