mirror of
https://github.com/mx42/adventofcode.git
synced 2026-01-14 13:59:51 +01:00
Adding day 12
This commit is contained in:
61
day12/part1.scala
Normal file
61
day12/part1.scala
Normal file
@@ -0,0 +1,61 @@
|
||||
import scala.io.StdIn.readLine
|
||||
|
||||
val LAST_GEN = 130
|
||||
|
||||
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))
|
||||
88
day12/part2.scala
Normal file
88
day12/part2.scala
Normal file
@@ -0,0 +1,88 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user