Skip to content

Commit 352a574

Browse files
committed
Solve 2025 day 10 part 2 using Z3
1 parent a2562d5 commit 352a574

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

src/main/scala/eu/sim642/adventofcode2025/Day10.scala

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package eu.sim642.adventofcode2025
22

3+
import com.microsoft.z3.{ArithExpr, Context, IntExpr, IntSort, Status}
34
import eu.sim642.adventofcodelib.graph.{BFS, Dijkstra, GraphSearch, TargetNode, UnitNeighbors}
45

6+
import scala.jdk.CollectionConverters.*
7+
58
object Day10 {
69

710
type Lights = Vector[Boolean]
@@ -25,9 +28,19 @@ object Day10 {
2528

2629
def sumFewestPresses(machines: Seq[Machine]): Int = machines.map(fewestPresses).sum
2730

31+
/*
32+
x0 x1 x2 x3 x4 x5
33+
(3) (1,3) (2) (2,3) (0,2) (0,1)
34+
0: x4 x5 = 3
35+
1: x1 x5 = 5
36+
2: x2 x3 x4 = 4
37+
3: x0 x3 = 7
38+
39+
*/
40+
2841
// TODO: optimize
2942
def fewestPresses2(machine: Machine): Int = {
30-
val graphSearch = new GraphSearch[Joltages] with UnitNeighbors[Joltages] with TargetNode[Joltages] {
43+
/*val graphSearch = new GraphSearch[Joltages] with UnitNeighbors[Joltages] with TargetNode[Joltages] {
3144
override val startNode: Joltages = machine.joltages.map(_ => 0)
3245
3346
override def unitNeighbors(joltages: Joltages): IterableOnce[Joltages] =
@@ -36,10 +49,34 @@ object Day10 {
3649
override val targetNode: Joltages = machine.joltages
3750
}
3851
39-
BFS.search(graphSearch).target.get._2
52+
BFS.search(graphSearch).target.get._2*/
53+
54+
val ctx = new Context(Map("model" -> "true").asJava)
55+
import ctx._
56+
val s = mkOptimize()
57+
58+
val buttonVars = machine.buttons.zipWithIndex.map((_, i) => mkIntConst(s"x$i"))
59+
val lhss =
60+
machine.buttons
61+
.lazyZip(buttonVars)
62+
.foldLeft(machine.joltages.map[ArithExpr[IntSort]](i => mkInt(i)))({ case (accs, (button, buttonVar)) =>
63+
button.foldLeft(accs)((accs, i) => accs.updated(i, mkSub(accs(i), buttonVar)))
64+
})
65+
66+
for (lhs <- lhss)
67+
s.Add(mkEq(lhs, mkInt(0)))
68+
69+
for (v <- buttonVars)
70+
s.Add(mkGe(v, mkInt(0)))
71+
72+
val presses = buttonVars.foldLeft[ArithExpr[IntSort]](mkInt(0))((acc, v) => mkAdd(acc, v))
73+
s.MkMinimize(presses)
74+
assert(s.Check() == Status.SATISFIABLE)
75+
//println(s.getModel)
76+
s.getModel.evaluate(presses, false).toString.toInt
4077
}
4178

42-
def sumFewestPresses2(machines: Seq[Machine]): Int = machines.map(fewestPresses2).sum
79+
def sumFewestPresses2(machines: Seq[Machine]): Int = machines.map(fewestPresses2).tapEach(println).sum
4380

4481
def parseMachine(s: String): Machine = s match {
4582
case s"[$lightsStr] $buttonsStr {$joltagesStr}" =>

src/test/scala/eu/sim642/adventofcode2025/Day10Test.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ class Day10Test extends AnyFunSuite {
2323
}
2424

2525
test("Part 2 input answer") {
26-
//assert(sumFewestPresses2(parseMachines(input)) == 449)
26+
assert(sumFewestPresses2(parseMachines(input)) == 17848)
2727
}
2828
}

0 commit comments

Comments
 (0)