This commit is contained in:
Christian
2024-12-19 10:14:53 +01:00
parent 0198ead034
commit 57852ccfc1
3 changed files with 9 additions and 32 deletions

View File

@@ -4,15 +4,8 @@ import scala.collection.mutable
object Memo: object Memo:
def Y[I, O](f: (I, I => O) => O): I => O = def Y[I, O](f: (I, I => O) => O): I => O =
var yf: I => O = null lazy val yf: I => O = Memo(f(_, yf(_))); yf
yf = Memo(f(_, yf(_)))
yf
class Memo[-I, +O](f: I => O) extends (I => O): class Memo[-I, +O](f: I => O) extends (I => O):
private[this] val memo = mutable.Map.empty[I, O] private[this] val memo = mutable.Map.empty[I, O]
def apply(i: I): O = { lazy val o = f(i); memo.getOrElseUpdate(i, o) }
def apply(i: I): O =
if memo.contains(i) then memo(i)
else {
val o = f(i); memo(i) = o; o
}

View File

@@ -51,7 +51,6 @@ object Day16 extends Solver(16):
val all = mutable.Set(endPose) val all = mutable.Set(endPose)
var cur = Set(endPose) var cur = Set(endPose)
println(start)
while cur.nonEmpty do while cur.nonEmpty do
cur = cur.filter(_ != Pose(start, Direction.Right)).flatMap(ancestor(_)) cur = cur.filter(_ != Pose(start, Direction.Right)).flatMap(ancestor(_))
all.addAll(cur) all.addAll(cur)

View File

@@ -2,38 +2,23 @@ package dev.ctsk.aoc.days
import dev.ctsk.aoc.* import dev.ctsk.aoc.*
import scala.util.boundary
import scala.util.boundary.break
object Day19 extends Solver(19): object Day19 extends Solver(19):
def pre(input: os.ReadablePath): (Trie, Seq[String]) = def pre(input: os.ReadablePath): (Trie, Seq[String]) =
val Array(rules_, words_) = os.read(input).split("\n\n") val Array(rules_, words_) = os.read(input).split("\n\n")
val trie = Trie() val trie = Trie()
for rule <- rules_.split(", ") do trie.insert(rule) for rule <- rules_.split(", ") do trie.insert(rule)
(trie, words_.linesIterator.toSeq) (trie, words_.linesIterator.toSeq)
def part1(trie: Trie, words: Seq[String]): Int = private def arrangements(trie: Trie, word: String): Long =
def valid(word: String, inj: String => Boolean): Boolean = def rec(offset: Int, inj: Int => Long): Long =
if word.isEmpty then return true if offset == word.length then return 1L
boundary: trie.prefixes(word, offset).map(inj).sum
for p <- trie.prefixes(word) do Memo.Y(rec)(0)
if inj(word.slice(p, word.length)) then break(true)
false
words.count(Memo.Y(valid))
def part2(trie: Trie, words: Seq[String]): Long =
def valid(word: String, inj: String => Long): Long =
if word.isEmpty then return 1L
trie.prefixes(word).map(p => inj(word.slice(p, word.length))).sum
words.map(Memo.Y(valid)).sum
override def run(input: os.ReadablePath): (Timings, Solution) = override def run(input: os.ReadablePath): (Timings, Solution) =
val (pre_time, (trie, words)) = timed { pre(input) } val (pre_time, (trie, words)) = timed { pre(input) }
val (p1_time, p1) = timed { part1(trie, words) } val (p1_time, p1) = timed { words.count(arrangements(trie, _) > 0) }
val (p2_time, p2) = timed { part2(trie, words) } val (p2_time, p2) = timed { words.map(arrangements(trie, _)).sum }
( (
Timings(pre_time, p1_time, p2_time), Timings(pre_time, p1_time, p2_time),