1+ package day14
2+
3+ import utils.verify
4+ import java.io.File
5+
6+ /* * https://adventofcode.com/2021/day/14 */
7+
8+ fun main () {
9+
10+ val rootDir = File (" src/day14/" )
11+
12+ data class Insertion (val a : Char , val b : Char , val input : Char )
13+ data class Data (val polymer : String , val rules : List <Insertion >)
14+
15+ fun Data.allPosibilities (): Set <Char > =
16+ (this .polymer.toCharArray() + rules.map { it.a.toString() + it.b + it.input }
17+ .joinToString(separator = " " ) { it }.toCharArray()).toSet()
18+
19+ fun Data.polymerization (steps : Int ): String {
20+ var polymer = this .polymer
21+ for (i in 0 until steps) {
22+ val array = CharArray (polymer.length * 2 - 1 )
23+ polymer.windowed(2 ).forEachIndexed { pos, value ->
24+ array[pos * 2 ] = value[0 ]
25+ array[pos * 2 + 1 ] = this .rules.first { value[0 ] == it.a && value[1 ] == it.b }.input
26+ }
27+ array[array.size - 1 ] = polymer.last()
28+ polymer = array.concatToString()
29+ }
30+ return polymer
31+ }
32+
33+
34+ fun part1 (data : Data ): Int {
35+ val grouped = data.polymerization(10 ).groupBy { it }
36+ return grouped.maxOf { it.value.size } - grouped.minOf { it.value.size }
37+ }
38+
39+ fun MutableMap <String , Long >.append (pair : String , times : Long = 1) {
40+ this [pair] = (this [pair] ? : 0 ) + times
41+ }
42+
43+ fun MutableMap <String , Long >.drop (pair : String , times : Long = 1) {
44+ this [pair] = (this [pair] ? : 0 ) - times
45+ }
46+
47+ fun part2 (data : Data ): Long {
48+ val counts: MutableMap <String , Long > = mutableMapOf ()
49+ val countsPlus: MutableMap <String , Long > = mutableMapOf ()
50+
51+ data.polymer.windowed(2 ).forEach { counts.append(it) }
52+
53+ // print("0: ")
54+ // counts.forEach { (key, value) -> print("$key: $value, ") }
55+ // println()
56+
57+ for (i in 0 until 40 ) {
58+ counts.forEach { count ->
59+ data.rules.first { it.a == count.key[0 ] && it.b == count.key[1 ] }.let { insertion ->
60+ countsPlus.append(insertion.a.toString() + insertion.input.toString(), count.value)
61+ countsPlus.append(insertion.input.toString() + insertion.b.toString(), count.value)
62+ countsPlus.drop(count.key, count.value)
63+ }
64+ }
65+ countsPlus.forEach { (key, value) -> counts[key] = (counts[key] ? : 0 ) + value }
66+ countsPlus.clear()
67+ counts.filter { it.value == 0L }.forEach { counts.remove(it.key) }
68+ // print("${i + 1}: ")
69+ // counts.forEach { (key, value) -> print("$key: $value, ") }
70+ // println()
71+ }
72+
73+ val result: MutableMap <Char , Long > = mutableMapOf ()
74+ data.allPosibilities().forEach {
75+ result[it] = 0
76+ }
77+
78+ counts.map { it.key[0 ] to it.value }.forEach { result[it.first] = (result[it.first] ? : 0 ) + it.second }
79+ result[data.polymer.last()] = (result[data.polymer.last()] ? : 0 ) + 1
80+
81+ return result.maxOf { it.value } - result.minOf { it.value }
82+ }
83+
84+ // ---- RUN
85+
86+ fun File.read (): Data {
87+ var polymer = " "
88+ val rules = mutableListOf<Insertion >()
89+ readLines().forEachIndexed { id, value ->
90+ when (id) {
91+ 0 -> polymer = value
92+ 1 -> {}
93+ else -> rules.add(Insertion (value[0 ], value[1 ], value[6 ]))
94+ }
95+ }
96+ rules.sortBy { it.a }
97+ return Data (polymer, rules)
98+ }
99+
100+ val testData = File (rootDir, " input_test.txt" ).read()
101+ val data = File (rootDir, " input.txt" ).read()
102+
103+ verify(1588 , part1(testData))
104+ verify(3306 , part1(data))
105+
106+ verify(2188189693529 , part2(testData))
107+ verify(3760312702877 , part2(data))
108+ }
0 commit comments