Day 8.
This commit is contained in:
parent
ba3d677880
commit
9d314599e4
144
src/aoc2023/Day08.kt
Normal file
144
src/aoc2023/Day08.kt
Normal file
@ -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<String>): Int {
|
||||
val cmd = input[0]
|
||||
val map = HashMap<String, Pair<String, String>>()
|
||||
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<String>): Long {
|
||||
val cmd = input[0]
|
||||
val map = HashMap<String, Pair<String, String>>()
|
||||
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<Int>()
|
||||
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<Int>()
|
||||
val factors = HashSet<Int>()
|
||||
var prime = 2
|
||||
primes.add(2)
|
||||
do {
|
||||
val newGgts = HashSet<Int>()
|
||||
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()
|
||||
}
|
Loading…
Reference in New Issue
Block a user