diff --git a/src/adventofcode/year_2023/day_08_2023.py b/src/adventofcode/year_2023/day_08_2023.py index 1d83fcb..f388413 100644 --- a/src/adventofcode/year_2023/day_08_2023.py +++ b/src/adventofcode/year_2023/day_08_2023.py @@ -1,3 +1,6 @@ +from functools import partial, reduce + +import math import re from collections import deque @@ -9,7 +12,7 @@ def parse_input(data: list[str]) -> tuple[deque, dict[str, tuple[str, str]]]: instructions = deque(data[0]) paths: dict[str, tuple[str, str]] = {} - pattern = re.compile("[A-Z]{3}") + pattern = re.compile("[A-Z0-9]{3}") for line in data[2:]: key, left, right = pattern.findall(line) @@ -36,6 +39,41 @@ def follow_instructions(data: list[str]) -> int: return steps +def highest_common_multiple(num_a: int, num_b: int) -> int: + return num_a * num_b // math.gcd(num_a, num_b) + + +def find_end_as_ghost(starting_position: str, instructions: deque[str], paths: dict[str, tuple[str, str]]) -> int: + """ + Count how many staps it will take to arrive at a location that ends with Z + """ + steps = 0 + current_location = starting_position + + while not current_location.endswith("Z"): + direction = 0 if instructions[0] == "L" else 1 + current_location = paths[current_location][direction] + steps += 1 + instructions.rotate(-1) + + return steps + + +def follow_instructions_as_a_ghost(data: list[str]) -> int: + """ + The solution for part one will not work here, it will take too much time. + Find the steps to the end for all starting position and then use the highest common multiple + """ + instructions, paths = parse_input(data) + starting_positions = list(filter(lambda k: k.endswith("A"), paths.keys())) + steps_required: list[int] = [] + + for position in starting_positions: + steps_required.append(find_end_as_ghost(position, instructions, paths)) + + return reduce(highest_common_multiple, steps_required) + + @register_solution(2023, 8, 1) def part_one(input_data: list[str]): answer = follow_instructions(input_data) @@ -48,7 +86,7 @@ def part_one(input_data: list[str]): @register_solution(2023, 8, 2) def part_two(input_data: list[str]): - answer = ... + answer = follow_instructions_as_a_ghost(input_data) if not answer: raise SolutionNotFoundError(2023, 8, 2) diff --git a/tests/adventofcode/year_2023/test_day_08_2023.py b/tests/adventofcode/year_2023/test_day_08_2023.py index bcba60f..c74468a 100644 --- a/tests/adventofcode/year_2023/test_day_08_2023.py +++ b/tests/adventofcode/year_2023/test_day_08_2023.py @@ -22,6 +22,19 @@ "ZZZ = (ZZZ, ZZZ)", ] +test_input_3 = [ + "LR", + "", + "11A = (11B, XXX)", + "11B = (XXX, 11Z)", + "11Z = (11B, XXX)", + "22A = (22B, XXX)", + "22B = (22C, 22C)", + "22C = (22Z, 22Z)", + "22Z = (22B, 22B)", + "XXX = (XXX, XXX)", +] + def test_parse_input(): assert parse_input(test_input_2) == ( @@ -44,4 +57,4 @@ def test_part_one(): def test_part_two(): - assert part_two(test_input) == "x" + assert part_two(test_input_3) == 6