From 7c4e98ebcf260078336be4e2b494560697bf9a69 Mon Sep 17 00:00:00 2001 From: Sebastian Mark Date: Fri, 6 Dec 2024 13:06:10 +0100 Subject: [PATCH] add 2024/day1-day5 python --- 2024/01/main.py | 51 +++++++++++++++++++++++++++ 2024/02/main.py | 76 ++++++++++++++++++++++++++++++++++++++++ 2024/03/main.py | 52 ++++++++++++++++++++++++++++ 2024/04/main.py | 89 +++++++++++++++++++++++++++++++++++++++++++++++ 2024/05/main.py | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 360 insertions(+) create mode 100755 2024/01/main.py create mode 100755 2024/02/main.py create mode 100644 2024/03/main.py create mode 100644 2024/04/main.py create mode 100644 2024/05/main.py diff --git a/2024/01/main.py b/2024/01/main.py new file mode 100755 index 0000000..9f28a02 --- /dev/null +++ b/2024/01/main.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Author: Sebastian Mark +# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de) + +# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string + + +def readinput() -> (list[int], list[int]): + a = [] + b = [] + with open("input", "r", encoding="utf-8") as file: + for line in file: + num1, num2 = map(int, line.split()) + a.append(num1) + b.append(num2) + return a, b + + +def distance(list_a: list[int], list_b: list[int]) -> int: + list_a.sort() + list_b.sort() + + dist = 0 + for a_val, b_val in zip(list_a, list_b): + dist += abs(a_val - b_val) + + return dist + + +def similarity(list_a: list[int], list_b: list[int]) -> int: + sim = 0 + for a_val in list_a: + sim += a_val * list_b.count(a_val) + + return sim + + +def main(): + list_a, list_b = readinput() + + # part1 + print("Distance: %d" % distance(list_a, list_b)) + + # part 2 + print("Similarity: %d" % similarity(list_a, list_b)) + + +if __name__ == "__main__": + main() diff --git a/2024/02/main.py b/2024/02/main.py new file mode 100755 index 0000000..986d295 --- /dev/null +++ b/2024/02/main.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Author: Sebastian Mark +# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de) + +# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string + + +def readinput() -> list[int]: + reports = [] + with open("input", "r", encoding="utf-8") as file: + for line in file: + levels = list(map(int, line.split(" "))) + reports.append(levels) + return reports + + +def is_valid_level_difference(i: int, j: int) -> bool: + if i == j: + return False + + if abs(i - j) > 3: + return False + + return True + + +def is_sorted(levels: list) -> bool: + asc_sorted = levels == sorted(levels) + desc_sorted = levels == sorted(levels, reverse=True) + return asc_sorted or desc_sorted + + +def is_save(levels: list) -> bool: + if not is_sorted(levels): + return False + + for i in range(len(levels) - 1): + if not is_valid_level_difference(levels[i], levels[i + 1]): + return False + + return True + + +def remove_level_by_index(levels: list, index: int) -> list: + copy = levels.copy() + copy.pop(index) + return copy + + +def is_save_with_damper(levels: list) -> bool: + if is_save(levels): + return True + + for i in range(len(levels)): + if is_save(remove_level_by_index(levels, i)): + return True + + return False + + +def main(): + reports = readinput() + + # part 1 + save_count = sum(is_save(report) for report in reports) + print("Save reports: %d" % save_count) + + # part 2 + save_count = sum(is_save_with_damper(report) for report in reports) + print("Save reports (with damper): %d" % save_count) + + +if __name__ == "__main__": + main() diff --git a/2024/03/main.py b/2024/03/main.py new file mode 100644 index 0000000..48a83e4 --- /dev/null +++ b/2024/03/main.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Author: Sebastian Mark +# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de) + +# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string + +import re + + +def readinput() -> str: + with open("input", "r", encoding="utf-8") as file: + lines = file.read() + return lines + + +def find_and_execute_instructions(m: str) -> int: + regex = r"mul\((\d{1,3}),(\d{1,3})\)" + res = sum(int(inst[0]) * int(inst[1]) for inst in re.findall(regex, m)) + return res + + +def find_and_execute_enabled_instructions(m: str) -> int: + regex = r"mul\(\d{1,3},\d{1,3}\)|do\(\)|don't\(\)" + + res = 0 + allowed = True + for inst in re.findall(regex, m): + if inst.startswith("mul"): + if allowed: + res += find_and_execute_instructions(inst) + else: + allowed = inst.startswith("do()") + + return res + + +def main(): + currupted_memory = readinput() + + # part 1 + instructions_result = find_and_execute_instructions(currupted_memory) + print("Result: %d" % instructions_result) + + # part 2 + instructions_result = find_and_execute_enabled_instructions(currupted_memory) + print("Result (only enabled): %d" % instructions_result) + + +if __name__ == "__main__": + main() diff --git a/2024/04/main.py b/2024/04/main.py new file mode 100644 index 0000000..6b58f86 --- /dev/null +++ b/2024/04/main.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Author: Sebastian Mark +# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de) + +# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string + + +def readinput() -> list: + with open("input", "r", encoding="utf-8") as file: + lines = file.readlines() + return lines + + +def find_xmas(grid: list[list], x: int, y: int) -> int: + height = len(grid) - 1 + width = len(grid[0]) - 1 + + count = 0 + for searchstring in ["XMAS", "SAMX"]: + # horizontal right + if x + 3 <= width: + found = sum(grid[y][x + i] == searchstring[i] for i in range(4)) + if found == 4: + count += 1 + + # vertical down + if y + 3 <= height: + found = sum(grid[y + i][x] == searchstring[i] for i in range(4)) + if found == 4: + count += 1 + + # diagonal down right + if y + 3 <= height and x + 3 <= width: + found = sum(grid[y + i][x + i] == searchstring[i] for i in range(4)) + if found == 4: + count += 1 + + # diagonal down left + if y + 3 <= height and x - 3 >= 0: + found = sum(grid[y + i][x - i] == searchstring[i] for i in range(4)) + if found == 4: + count += 1 + + return count + + +def find_cross_mass(grid: list[list], x: int, y: int) -> int: + # check clockwise for + # M.M + # .A. + # S.S + # then rotate the outer ring clockwise and check again + for searchstring in ["MMSS", "SMMS", "SSMM", "MSSM"]: + found = ( + grid[y - 1][x - 1] == searchstring[0] + and grid[y - 1][x + 1] == searchstring[1] + and grid[y + 1][x + 1] == searchstring[2] + and grid[y + 1][x - 1] == searchstring[3] + ) + if found: + return 1 + + return 0 + + +def main(): + grid = readinput() + + count = 0 + for y, _ in enumerate(grid): + for x, _ in enumerate(grid[0]): + pos = grid[y][x] + if pos in ["X", "S"]: + count += find_xmas(grid, x, y) + print("XMAS count: %d" % count) + + count = 0 + for y in range(1, len(grid) - 1): + for x in range(1, len(grid[0]) - 1): + pos = grid[y][x] + if pos == "A": + count += find_cross_mass(grid, x, y) + print("X-MAS count: %d" % count) + + +if __name__ == "__main__": + main() diff --git a/2024/05/main.py b/2024/05/main.py new file mode 100644 index 0000000..b8a1e24 --- /dev/null +++ b/2024/05/main.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Author: Sebastian Mark +# CC-BY-SA (https://creativecommons.org/licenses/by-sa/4.0/deed.de) + +# pylint: disable=missing-module-docstring,missing-function-docstring,consider-using-f-string + + +from collections import defaultdict + + +def readinput() -> list: + with open("input", "r", encoding="utf-8") as file: + lines = file.readlines() + return lines + + +def get_orders_and_updates() -> tuple[list, list]: + lines = readinput() + + sep = lines.index("\n") # newline in input + + rules = defaultdict(set) + for line in lines[:sep]: + a, b = map(int, line.split("|")) + rules[a].add(b) + + updates = [] + for line in lines[sep + 1 :]: + updates.append(list(map(int, line.split(",")))) + + return (rules, updates) + + +def validate_rules(update: list, rules: list) -> bool: + for i in range(len(update) - 1): + next_page = update[i + 1] + page = update[i] + if next_page not in rules[page]: + return False + return True + + +def get_middle_number(update: list) -> int: + return update[int(len(update) / 2)] + + +def fix_with_rules(update: list, rules: list) -> list: + # this block is inspired by: + # https://github.com/nitekat1124/advent-of-code-2024/blob/main/solutions/day05.py + + # filter only the rules for the pages in the current update + filtered_rules = defaultdict(set) + for i in update: + new_rules = [] + for x in rules[i]: + if x in update: + new_rules.append(x) + filtered_rules[i] = new_rules + + # the more filtered rules for the value exist, + # the further to the end is has to be placed, + # then reverse this + ordered_keys = sorted( + filtered_rules, key=lambda val: len(filtered_rules[val]), reverse=True + ) + + return ordered_keys + + +def main(): + rules, updates = get_orders_and_updates() + + # part 1 + count = 0 + for update in updates: + if validate_rules(update, rules): + count += get_middle_number(update) + print("Summed updates: %d" % count) + + # part 2 + count = 0 + for update in updates: + if not validate_rules(update, rules): + new_update = fix_with_rules(update, rules) + count += get_middle_number(new_update) + print("Summ fixed updates: %d" % count) + + +if __name__ == "__main__": + main()