mirror of
https://github.com/mx42/adventofcode.git
synced 2026-01-14 13:59:51 +01:00
89 lines
2.6 KiB
Scala
89 lines
2.6 KiB
Scala
import scala.io.StdIn.readLine
|
|
|
|
val LAST_GEN = 5000
|
|
|
|
case class Rule(m2: Boolean, m1: Boolean, o: Boolean, p1: Boolean, p2: Boolean, r: Boolean) {
|
|
def computePot(n: Int, input: Set[Int]): Option[Int] =
|
|
if (input.contains(n - 2) == m2 &&
|
|
input.contains(n - 1) == m1 &&
|
|
input.contains(n) == o &&
|
|
input.contains(n + 1) == p1 &&
|
|
input.contains(n + 2) == p2 &&
|
|
r) {
|
|
Some(n)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
def parseRule(in: String): Option[Rule] =
|
|
(("(#|\\.)" * 5) + " => (#|\\.)").r.findFirstMatchIn(in).map(
|
|
m => Rule(m.group(1) == "#", m.group(2) == "#", m.group(3) == "#", m.group(4) == "#", m.group(5) == "#", m.group(6) == "#")
|
|
)
|
|
|
|
def computeGeneration(current: Set[Int], rules: List[Rule]): Set[Int] =
|
|
((current.min - 2).to(current.max + 2))
|
|
.flatMap(k => rules.flatMap(_.computePot(k, current)).headOption)
|
|
.toSet
|
|
|
|
def printGeneration(min: Int, max: Int)(gen: (Int, Set[Int])): Unit = gen match {
|
|
case (id, pots) =>
|
|
val chars = pots.map(k => k -> '#').toMap.withDefaultValue('.')
|
|
val str = List.range(min, max, 1).map(chars).mkString("")
|
|
val sum = pots.sum
|
|
println(s"$id: $str $sum")
|
|
}
|
|
|
|
val initialStateReg = "^initial state: ((?:#|\\.)+)$".r
|
|
|
|
val origInit = readLine
|
|
|
|
val init = initialStateReg.findFirstMatchIn(origInit)
|
|
.map(m => m.group(1)).get
|
|
.zipWithIndex.flatMap {
|
|
case ('.', i) => None
|
|
case ('#', i) => Some(i)
|
|
}
|
|
.toSet
|
|
|
|
val rules = Iterator
|
|
.continually(readLine)
|
|
.takeWhile(_ != null)
|
|
.flatMap(parseRule)
|
|
.toList
|
|
|
|
val gens = List.range(1, LAST_GEN + 1, 1).scanLeft(0 -> init) {
|
|
case (gen, id) => id -> computeGeneration(gen._2, rules) }
|
|
// val min = gens.map(_._2.min).min - 2
|
|
// val max = gens.map(_._2.max).max + 2
|
|
// gens.foreach(printGeneration(min, max))
|
|
/**
|
|
* After ~100 generations, the same pattern simply moves
|
|
* 38 pots
|
|
* min pot = generation id - 80
|
|
* max pot = generation id + 98
|
|
#....#....#....#....#....#....#....#....#....#....#....#....#....#....#....#....#....#...#....#...#...#...#....#....#....#....#....#....#....#...#...#....#...#....#....#....#....#
|
|
*
|
|
* Observed that :
|
|
* GenerationId = (Sum - 4) / 38 - 10
|
|
* -> Sum = ((GenerationId + 10) * 38) + 4
|
|
*/
|
|
|
|
def printGenData(id: Int, gen: Set[Int]): Unit = {
|
|
val cnt = gen.size
|
|
val sum = gen.sum
|
|
val x = (sum - 4) / 38.0 - 10
|
|
val guess = ((id + 10) * 38) + 4
|
|
|
|
println(s"Generation $id")
|
|
println(s"CNT(p) = $cnt")
|
|
println(s"SUM(p) = $sum")
|
|
println(x)
|
|
println(s"Guess = $guess")
|
|
println("")
|
|
}
|
|
|
|
List(100, 101, 110, 120, 130, 140, 150, 200, 300, 500, 1000, 5000).foreach(g => printGenData(g, gens(g)._2))
|
|
|
|
println((50000000000L + 10) * 38 + 4)
|