diff --git a/src/year2021/day14/Day14.kt b/src/year2021/day14/Day14.kt new file mode 100644 index 0000000..d9379f0 --- /dev/null +++ b/src/year2021/day14/Day14.kt @@ -0,0 +1,89 @@ +package year2021.day14 + +import readInput + +typealias PolymerPair = String +typealias PolymerRules = Map +typealias PolymerTemplate = Map + +data class Polymer( + val rules: PolymerRules, + val template: MutableMap, + val pairsInTemplate: MutableMap +) { + constructor(rules: PolymerRules, template: String) : this(rules, template.associate { + it to template.count { it2 -> it == it2 }.toLong() + }.toMutableMap(), template.toPolymerTemplate().toMutableMap()) + + fun step() { + val addedPairs = mutableMapOf() + + for ((pair, count) in pairsInTemplate) { + if (!rules.contains(pair) || count == 0.toLong()) { + continue + } + + val addedElement = rules[pair]!! + val leftPair = pair[0].toString() + addedElement + val rightPair = addedElement + pair[1].toString() + + addedPairs[leftPair] = (addedPairs[leftPair] ?: 0) + count + addedPairs[rightPair] = (addedPairs[rightPair] ?: 0) + count + addedPairs[pair] = (addedPairs[pair] ?: 0) - count + + // update frequency counter + template[addedElement] = (template[addedElement] ?: 0) + count + } + + for ((pair, change) in addedPairs) { + pairsInTemplate[pair] = (pairsInTemplate[pair] ?: 0) + change + } + } + + val elements: Map + get() = template +} + +fun List.toPolymerRules(): PolymerRules = this.associate { + val (polymerPair, insertedElement) = it.split(" -> ") + polymerPair to insertedElement[0] +} + +fun String.toPolymerTemplate(): PolymerTemplate = + this.windowed(2) + .fold(mapOf()) { template, it -> + template + (it to template.getOrDefault(it, 0) + 1) + } + +fun part1(input: List): Long { + val polymer = Polymer(input.drop(2).toPolymerRules(), input.first()) + + repeat(10) { + polymer.step() + } + + val elements = polymer.elements + return elements.maxOf { it.value } - elements.minOf { it.value } +} + +fun part2(input: List): Long { + val polymer = Polymer(input.drop(2).toPolymerRules(), input.first()) + + repeat(40) { + polymer.step() + } + + val elements = polymer.elements + return elements.maxOf { it.value } - elements.minOf { it.value } +} + +fun main() { + val sample = readInput(14, "sample") + val input = readInput(14, "input") + + check(part1(sample) == 1588.toLong()) + println(part1(input)) + + check(part2(sample) == 2188189693529) + println(part2(input)) +} diff --git a/src/year2021/day14/sample.txt b/src/year2021/day14/sample.txt new file mode 100644 index 0000000..6c1c3a1 --- /dev/null +++ b/src/year2021/day14/sample.txt @@ -0,0 +1,18 @@ +NNCB + +CH -> B +HH -> N +CB -> H +NH -> C +HB -> C +HC -> B +HN -> C +NN -> C +BH -> H +NC -> B +NB -> B +BN -> B +BB -> N +BC -> B +CC -> N +CN -> C \ No newline at end of file