@@ -3,66 +3,119 @@ package de.ronny_h.aoc.year2018.day12
33import de.ronny_h.aoc.AdventOfCode
44import de.ronny_h.aoc.extensions.collections.split
55
6- fun main () = SubterraneanSustainability (). run ( 3798 , 0 )
6+ private val verbose = false
77
8- class SubterraneanSustainability : AdventOfCode <Int >(2018 , 12 ) {
9- override fun part1 (input : List <String >): Int {
8+ fun main () = SubterraneanSustainability ().run (3798 , 3900000002212 )
9+
10+ class SubterraneanSustainability : AdventOfCode <Long >(2018 , 12 ) {
11+ override fun part1 (input : List <String >): Long {
1012 val pots = GameOfPlants (input, 20 )
1113 pots.simulateGenerations()
1214 return pots.sumOfPlantContainingPotNumbers()
1315 }
1416
15- override fun part2 (input : List <String >): Int {
16- return 0
17+ override fun part2 (input : List <String >): Long {
18+ val generations = 50000000000
19+ val pots = GameOfPlants (input, generations)
20+ val (generationCount, shifted) = pots.simulateGenerations()
21+ return pots.sumOfPlantContainingPotNumbers(generations - generationCount, shifted)
1722 }
1823}
1924
20- class GameOfPlants (input : List <String >, val generations : Int ) {
25+ class GameOfPlants (input : List <String >, private val generations : Long ) {
2126 private val plant = ' #'
2227 private val noPlant = ' .'
23- private val initialState = input.first().substringAfter(" initial state: " )
28+ private val initialState = input.first().substringAfter(" initial state: " ).toList()
2429
2530 // a rule has the form of: LLCRR => N
2631 private val plantProducingPatterns = input.split()[1 ]
2732 .map { it.split(" => " ) }
2833 .filter { it[1 ] == " $plant " }
29- .map { it.first() }
34+ .map { it.first().toList() }
3035 .toSet()
3136 private val patternLength = 5
3237 private val patternCenter = 2
3338
3439 // per generation the plants grow max 2 pots wider in each direction
35- private val offset = generations * 2
36- private val padding = " $noPlant " .repeat(offset)
37-
38- var currentGeneration = padding + initialState + padding
39- private set
40+ private val paddingLength = 40
41+ private var offset = 0
42+ private val padding = List (paddingLength) { noPlant }
4043
41- fun nextGeneration (): String {
42- val nextGen = currentGeneration.toMutableList()
44+ private var currentGeneration = initialState.toMutableList()
45+ private var nextGeneration = currentGeneration.toMutableList()
4346
44- for (index in 0 .. nextGen.lastIndex - patternLength) {
45- nextGen[index + patternCenter] =
46- if (currentGeneration.substring(index, index + patternLength) in plantProducingPatterns) {
47+ fun nextGeneration (): List <Char > {
48+ var firstPlantIndex = currentGeneration.indexOf(plant)
49+ if (firstPlantIndex < patternLength) {
50+ firstPlantIndex + = addPaddingAtFront()
51+ }
52+ if (currentGeneration.lastIndexOf(plant) > currentGeneration.lastIndex - patternLength) {
53+ addPaddingAtEnd()
54+ }
55+ for (index in firstPlantIndex - patternLength.. nextGeneration.lastIndex - patternLength) {
56+ nextGeneration[index + patternCenter] =
57+ if (currentGeneration.subList(index, index + patternLength) in plantProducingPatterns) {
4758 plant
4859 } else {
4960 noPlant
5061 }
5162 }
52- currentGeneration = nextGen.joinToString( " " )
63+ swapGenerations( )
5364 return currentGeneration
5465 }
5566
56- fun sumOfPlantContainingPotNumbers (): Int =
57- currentGeneration.foldIndexed(0 ) { i, acc, pot ->
58- if (pot == plant) acc + i - offset else acc
67+ private fun swapGenerations () {
68+ val tmp = currentGeneration
69+ currentGeneration = nextGeneration
70+ nextGeneration = tmp
71+ }
72+
73+ private fun addPaddingAtFront (): Int {
74+ if (verbose) println (" adding padding at the beginning" )
75+ offset + = paddingLength
76+ currentGeneration = (padding + currentGeneration).toMutableList()
77+ nextGeneration = currentGeneration.toMutableList()
78+ return paddingLength
79+ }
80+
81+ private fun addPaddingAtEnd () {
82+ if (verbose) println (" adding padding at the end" )
83+ currentGeneration = (currentGeneration + padding).toMutableList()
84+ nextGeneration = currentGeneration.toMutableList()
85+ }
86+
87+ fun sumOfPlantContainingPotNumbers (remainingGenerations : Long = 0L, shiftPerGeneration : Int = 0): Long {
88+ val correction = remainingGenerations * shiftPerGeneration - offset
89+ return currentGeneration.foldIndexed(0L ) { i, acc, pot ->
90+ if (pot == plant) acc + i + correction else acc
5991 }
92+ }
6093
61- fun simulateGenerations () {
62- println (" generation 0:$currentGeneration " )
63- repeat(generations) {
94+ // returns: a pair of
95+ // - the number of the generation at which the configuration of plants does not change anymore and
96+ // - the number of positions the pattern is shifted compared to the previous generation
97+ fun simulateGenerations (): Pair <Long , Int > {
98+ if (verbose) println (" generation 0:${currentGeneration.joinToString(" " )} " )
99+ var generationCount = 1L
100+ var lastPlantCount = currentGeneration.count { it == plant }
101+ while (generationCount <= generations) {
64102 nextGeneration()
65- println (" generation ${" %2d" .format(it + 1 )} : $currentGeneration " )
103+ if (generationCount < 202 || generationCount % 10000000 == 0L ) {
104+ if (verbose) println (" generation ${" %2d" .format(generationCount)} : ${currentGeneration.joinToString(" " )} " )
105+ }
106+ val thisPlantCount = currentGeneration.count { it == plant }
107+ if (thisPlantCount == lastPlantCount) {
108+ if (currentGeneration.allPlantsContainingSubList() == nextGeneration.allPlantsContainingSubList()) {
109+ if (verbose) println (" generation $generationCount : plants configuration did not change" )
110+ return generationCount to currentGeneration.indexOf(plant) - nextGeneration.indexOf(plant)
111+ }
112+ }
113+ generationCount++
114+ lastPlantCount = thisPlantCount
66115 }
116+ return generationCount to 0
67117 }
118+
119+ private fun MutableList<Char>.allPlantsContainingSubList (): MutableList <Char > =
120+ subList(indexOf(plant), lastIndexOf(plant) + 1 )
68121}
0 commit comments