From ea329a70e524306e1ce5a7f3953d74dfe31c7973 Mon Sep 17 00:00:00 2001 From: Daniel Lin Date: Fri, 8 Dec 2023 02:14:07 -0500 Subject: [PATCH] Day 8: Haunted Wasteland --- README.md | 2 +- py/aoc2023/day8.py | 103 +++++++++++++++++++++++++++++++++++++++++++++ py/pyproject.toml | 1 + 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 py/aoc2023/day8.py diff --git a/README.md b/README.md index 213cbdf9..b8cd5e3e 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,4 @@ Development occurs in language-specific directories: |[Day5.hs](hs/src/Day5.hs)|[Day5.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day5.kt)|[day5.py](py/aoc2023/day5.py)|[day5.rs](rs/src/day5.rs)| |[Day6.hs](hs/src/Day6.hs)|[Day6.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day6.kt)|[day6.py](py/aoc2023/day6.py)|[day6.rs](rs/src/day6.rs)| |[Day7.hs](hs/src/Day7.hs)|[Day7.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day7.kt)|[day7.py](py/aoc2023/day7.py)|[day7.rs](rs/src/day7.rs)| -|[Day8.hs](hs/src/Day8.hs)|[Day8.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day8.kt)||| +|[Day8.hs](hs/src/Day8.hs)|[Day8.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day8.kt)|[day8.py](py/aoc2023/day8.py)|| diff --git a/py/aoc2023/day8.py b/py/aoc2023/day8.py new file mode 100644 index 00000000..5a5ab2a6 --- /dev/null +++ b/py/aoc2023/day8.py @@ -0,0 +1,103 @@ +""" +Day 8: Haunted Wasteland +""" + +import re +from functools import reduce +from itertools import accumulate, repeat +from math import lcm + +SAMPLE_INPUT_1, SAMPLE_INPUT_2, SAMPLE_INPUT_3 = ( + """ +RL + +AAA = (BBB, CCC) +BBB = (DDD, EEE) +CCC = (ZZZ, GGG) +DDD = (DDD, DDD) +EEE = (EEE, EEE) +GGG = (GGG, GGG) +ZZZ = (ZZZ, ZZZ) +""", + """ +LLR + +AAA = (BBB, BBB) +BBB = (AAA, ZZZ) +ZZZ = (ZZZ, ZZZ) +""", + """ +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) +""", +) + +INSTRUCTIONS = re.compile(r"[LR]+") +NODE = re.compile(r"(\w+) = \((\w+), (\w+)\)") + + +def _parse(data): + instructions = INSTRUCTIONS.search(data).group() + table = {node: (left, right) for node, left, right in NODE.findall(data)} + + def step(node, instruction): + match instruction: + case "L": + return table[node][0] + case "R": + return table[node][1] + + return ( + lambda start: reduce(step, instructions, start), + len(instructions), + table.keys(), + ) + + +def part1(data): + """ + >>> part1(SAMPLE_INPUT_1) + 2 + >>> part1(SAMPLE_INPUT_2) + 6 + """ + step, n, _ = _parse(data) + return n * next( + i + for i, node in enumerate( + accumulate(repeat(()), lambda node, _: step(node), initial="AAA") + ) + if node == "ZZZ" + ) + + +def part2(data): + """ + >>> part2(SAMPLE_INPUT_3) + 6 + """ + step, n, nodes = _parse(data) + + def find_cycle(start): + i, end = next( + (i, node) + for i, node in enumerate( + accumulate(repeat(()), lambda node, _: step(node), initial=start) + ) + if node.endswith("Z") + ) + assert step(start) == step(end) + return i + + return n * reduce(lcm, (find_cycle(node) for node in nodes if node.endswith("A"))) + + +parts = (part1, part2) diff --git a/py/pyproject.toml b/py/pyproject.toml index d99ca4de..d0d8be4e 100644 --- a/py/pyproject.toml +++ b/py/pyproject.toml @@ -29,6 +29,7 @@ day4 = "aoc2023.day4:parts" day5 = "aoc2023.day5:parts" day6 = "aoc2023.day6:parts" day7 = "aoc2023.day7:parts" +day8 = "aoc2023.day8:parts" [tool.black] target_version = ["py312"]