|
| 1 | +fun main() { |
| 2 | + |
| 3 | + val symbolsCount = 26 |
| 4 | + val pairsCount = symbolsCount * symbolsCount |
| 5 | + |
| 6 | + fun List<String>.parse(): Pair<List<Int>, Map<Int, Int>> { |
| 7 | + val template = first().map { it - 'A' } |
| 8 | + val rules = drop(2) |
| 9 | + .map { it.split(" -> ") } |
| 10 | + .associate { pair -> |
| 11 | + val leftChar = pair.first().first() - 'A' |
| 12 | + val rightChar = pair.first().last() - 'A' |
| 13 | + val middleChar = pair.last().first() - 'A' |
| 14 | + leftChar * symbolsCount + rightChar to middleChar |
| 15 | + } |
| 16 | + return Pair(template, rules) |
| 17 | + } |
| 18 | + |
| 19 | + fun solve(template: List<Int>, rules: Map<Int, Int>, steps: Int): Long { |
| 20 | + val symbolsRange = 0 until symbolsCount |
| 21 | + val pairsRange = 0 until pairsCount |
| 22 | + |
| 23 | + val d = Array(steps + 1) { Array(pairsCount) { LongArray(symbolsCount) { 0L } } } |
| 24 | + |
| 25 | + for (i in pairsRange) { |
| 26 | + for (j in symbolsRange) { |
| 27 | + d[0][i][j] += if (j == i / symbolsCount) 1L else 0L |
| 28 | + d[0][i][j] += if (j == i % symbolsCount) 1L else 0L |
| 29 | + } |
| 30 | + } |
| 31 | + |
| 32 | + for (step in 1..steps) { |
| 33 | + for (i in pairsRange) { |
| 34 | + val leftChar = i / symbolsCount |
| 35 | + val rightChar = i % symbolsCount |
| 36 | + val middleChar = rules[i] ?: continue |
| 37 | + |
| 38 | + val leftPair = leftChar * symbolsCount + middleChar |
| 39 | + val rightPair = middleChar * symbolsCount + rightChar |
| 40 | + |
| 41 | + for (j in symbolsRange) { |
| 42 | + d[step][i][j] = d[step - 1][leftPair][j] + d[step - 1][rightPair][j] |
| 43 | + } |
| 44 | + |
| 45 | + d[step][i][middleChar] -= 1L |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + val result = LongArray(symbolsCount) { 0L } |
| 50 | + template.dropLast(1).forEachIndexed { index, value -> |
| 51 | + val pair = value * symbolsCount + template[index + 1] |
| 52 | + for (i in symbolsRange) { |
| 53 | + result[i] += d[steps][pair][i] |
| 54 | + } |
| 55 | + } |
| 56 | + template.drop(1).dropLast(1).forEach { result[it] -= 1L } |
| 57 | + |
| 58 | + return result.filterNot { it == 0L }.maxOf { it } - result.filterNot { it == 0L }.minOf { it } |
| 59 | + } |
| 60 | + |
| 61 | + fun part1( |
| 62 | + input: List<String> |
| 63 | + ) = input.parse().let { (template, rules) -> solve(template, rules, 10) } |
| 64 | + |
| 65 | + fun part2( |
| 66 | + input: List<String> |
| 67 | + ) = input.parse().let { (template, rules) -> solve(template, rules, 40) } |
| 68 | + |
| 69 | + val input = readInput("Day14") |
| 70 | + println(part1(input)) |
| 71 | + println(part2(input)) |
| 72 | +} |
0 commit comments