From 9d314599e44c29a5a6f3e44cfc6d74ac8d5ef095 Mon Sep 17 00:00:00 2001 From: chrisly42 Date: Fri, 8 Dec 2023 06:40:24 +0100 Subject: [PATCH] Day 8. --- src/aoc2023/Day08.kt | 144 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 src/aoc2023/Day08.kt diff --git a/src/aoc2023/Day08.kt b/src/aoc2023/Day08.kt new file mode 100644 index 0000000..633f5fc --- /dev/null +++ b/src/aoc2023/Day08.kt @@ -0,0 +1,144 @@ +package aoc2023 + +import println +import readInput + +/* +--- Day 8: Haunted Wasteland --- +You're still riding a camel across Desert Island when you spot a sandstorm quickly approaching. When you turn to warn the Elf, she disappears before your eyes! To be fair, she had just finished warning you about ghosts a few minutes ago. +One of the camel's pouches is labeled "maps" - sure enough, it's full of documents (your puzzle input) about how to navigate the desert. At least, you're pretty sure that's what they are; one of the documents contains a list of left/right instructions, and the rest of the documents seem to describe some kind of network of labeled nodes. +It seems like you're meant to use the left/right instructions to navigate the network. Perhaps if you have the camel follow the same instructions, you can escape the haunted wasteland! +After examining the maps for a bit, two nodes stick out: AAA and ZZZ. You feel like AAA is where you are now, and you have to follow the left/right instructions until you reach ZZZ. +This format defines each node of the network individually. For example: +RL + +AAA = (BBB, CCC) +BBB = (DDD, EEE) +CCC = (ZZZ, GGG) +DDD = (DDD, DDD) +EEE = (EEE, EEE) +GGG = (GGG, GGG) +ZZZ = (ZZZ, ZZZ) + +Starting with AAA, you need to look up the next element based on the next left/right instruction in your input. In this example, start with AAA and go right (R) by choosing the right element of AAA, CCC. Then, L means to choose the left element of CCC, ZZZ. By following the left/right instructions, you reach ZZZ in 2 steps. +Of course, you might not find ZZZ right away. If you run out of left/right instructions, repeat the whole sequence of instructions as necessary: RL really means RLRLRLRLRLRLRLRL... and so on. For example, here is a situation that takes 6 steps to reach ZZZ: +LLR + +AAA = (BBB, BBB) +BBB = (AAA, ZZZ) +ZZZ = (ZZZ, ZZZ) + +Starting at AAA, follow the left/right instructions. How many steps are required to reach ZZZ? + +*/ +fun main() { + + val inlineTestInput = """ +RL + +AAA = (BBB, CCC) +BBB = (DDD, EEE) +CCC = (ZZZ, GGG) +DDD = (DDD, DDD) +EEE = (EEE, EEE) +GGG = (GGG, GGG) +ZZZ = (ZZZ, ZZZ) +""" + val inlineTestInput2 = """ +LR + +ABA = (ABB, XXX) +ABB = (XXX, ABZ) +ABZ = (ABB, XXX) +BAA = (BAB, XXX) +BAB = (BAC, BAC) +BAC = (BAZ, BAZ) +BAZ = (BAB, BAB) +XXX = (XXX, XXX) +""" + + fun part1(input: List): Int { + val cmd = input[0] + val map = HashMap>() + for (i in input.drop(2)) { + "([A-Z][A-Z][A-Z]) = .([A-Z][A-Z][A-Z]), ([A-Z][A-Z][A-Z]).".toRegex().matchEntire(i)!!.destructured + .let { (id, left, right) -> map[id] = left to right } + } + var instPos = 0 + var steps = 0 + var loc = "AAA" + do { + loc = if (cmd[instPos] == 'L') map[loc]!!.first else map[loc]!!.second + instPos = (instPos + 1) % cmd.length + steps++ + } while (loc != "ZZZ") + return steps + } + + fun part2(input: List): Long { + val cmd = input[0] + val map = HashMap>() + for (i in input.drop(2)) { + "([A-Z][A-Z][A-Z]) = .([A-Z][A-Z][A-Z]), ([A-Z][A-Z][A-Z]).".toRegex().matchEntire(i)!!.destructured + .let { (id, left, right) -> map[id] = left to right } + } + val starts = map.keys.filter { it.endsWith("A") } + var ggts = HashSet() + for (start in starts) { + var instPos = 0 + var steps = 0 + var loc = start + do { + loc = if (cmd[instPos] == 'L') map[loc]!!.first else map[loc]!!.second + instPos = (instPos + 1) % cmd.length + steps++ + } while (!loc.endsWith("Z")) + ggts.add(steps) + } + val primes = ArrayList() + val factors = HashSet() + var prime = 2 + primes.add(2) + do { + val newGgts = HashSet() + for (f in ggts) { + if (prime * 2 - 1 > f) { + factors.add(f) + } else { + if (f % prime == 0) { + newGgts.add(f / prime) + factors.add(prime) + } else { + newGgts.add(f) + } + } + } + ggts = newGgts + if (prime == 2) { + prime = 3 + } else { + do { + prime += 2 + } while (primes.any { (prime % it) == 0 }) + } + primes.add(prime) + } while (ggts.isNotEmpty()) + + return factors.map { it.toLong() }.reduce(Long::times) + } + + // test if implementation meets criteria from the description, like: + val testInput = inlineTestInput.trim().reader().readLines() + val testInput2 = inlineTestInput2.trim().reader().readLines() + //val testInput = readInput("aoc2023/Day08_test") + val testInputPart1Result = part1(testInput) + println("Part 1 Test: $testInputPart1Result") + val testInputPart2Result = part2(testInput2) + println("Part 2 Test: $testInputPart2Result") + check(testInputPart1Result == 2) + check(testInputPart2Result == 6L) + + val input = readInput("aoc2023/Day08") + part1(input).println() + part2(input).println() +}