diff --git a/2024/day05/day05.py b/2024/day05/day05.py new file mode 100644 index 0000000..260d01b --- /dev/null +++ b/2024/day05/day05.py @@ -0,0 +1,120 @@ +from collections import defaultdict + + +def day5(input: str, part: int) -> int: + split_input = input.split("\n\n") + + reversed_graph: defaultdict[int, list[int]] = defaultdict(list) + for line in split_input[0].splitlines(): + rule_parts = line.split("|") + X, Y = int(rule_parts[0]), int(rule_parts[1]) + reversed_graph[Y].append(X) + + updates: list[list[int]] = [ + [int(x) for x in line.split(",")] for line in split_input[1].splitlines() + ] + part1_ans: int = 0 + + # for part 2 + invalid_updates: list[list[int]] = [] + + for update in updates: + # assuming there are no repeat updates... + seen_set: set[int] = set() + disallowed_set: set[int] = set() + is_valid = True + + for num in update: + if num in disallowed_set: + is_valid = False + break + for cannot_come_before in reversed_graph[num]: + if not cannot_come_before in seen_set: + disallowed_set.add(cannot_come_before) + + seen_set.add(num) + + if is_valid: + part1_ans += update[len(update) // 2] + else: + invalid_updates.append(update) + if part == 1: + return part1_ans + + # part2 + # can assume there's only one valid order... or that unordered ones will not affect the middle value + # so just take all the numbers and create the correct order by traversing the graph of dependencies? + + part2_ans: int = 0 + for update in invalid_updates: + correct_order: list[int] = [] + all_nums: set[int] = set(update) + used_nums: set[int] = set() + while len(all_nums) > len(used_nums): + for num in all_nums: + if num in used_nums: + continue + if not num in reversed_graph: + correct_order.append(num) + # all_nums.remove(num) + used_nums.add(num) + continue + + # check if all of this num's dependencies are in used_nums + # or if its dependencies are not present at all + # there's definitely a better algo for this... + if all( + [ + dep in used_nums or not dep in all_nums + for dep in reversed_graph[num] + ] + ): + correct_order.append(num) + # all_nums.remove(num) + used_nums.add(num) + continue + part2_ans += correct_order[len(correct_order) // 2] + + return part2_ans + + +# page ordering rules, X|Y -> X must come before Y +# updates, basically orders of pages +# missing page numbers are ignored.. +# part1_ans: sum middle page of each valid update +example = """47|53 +97|13 +97|61 +97|47 +75|29 +61|13 +75|53 +29|13 +97|29 +53|29 +61|53 +97|53 +61|29 +47|13 +75|47 +97|75 +47|61 +75|61 +47|29 +75|13 +53|13 + +75,47,61,53,29 +97,61,53,29,13 +75,29,13 +75,97,47,61,53 +61,13,29 +97,13,75,29,47""" + +input = open("input.txt").read() + +print(f"day5 example: {day5(example,1)} want 143") +print(f"day5: {day5(input,1)} want 5166") + +print(f"part2 example: {day5(example,2)} want 123") +print(f"part2: {day5(input,2)} want 4679")