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() }