Skip to content

Commit 4004e9e

Browse files
committed
Revert "Z3 implementation using ints"
This reverts commit 7024da9.
1 parent 7024da9 commit 4004e9e

File tree

3 files changed

+95
-62
lines changed

3 files changed

+95
-62
lines changed
Lines changed: 93 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,111 @@
11
package me.peckb.aoc._2025.calendar.day10
22

3-
import com.microsoft.z3.ArithExpr
3+
import com.microsoft.z3.BitVecNum
4+
import com.microsoft.z3.BitVecSort
45
import com.microsoft.z3.Context
5-
import com.microsoft.z3.IntExpr
6-
import com.microsoft.z3.IntNum
7-
import com.microsoft.z3.IntSort
6+
import com.microsoft.z3.Expr
7+
import com.microsoft.z3.Optimize
88
import com.microsoft.z3.Status
99
import javax.inject.Inject
1010
import me.peckb.aoc.generators.InputGenerator.InputGeneratorFactory
11-
import kotlin.collections.component1
12-
import kotlin.collections.component2
11+
import org.apache.commons.math3.stat.inference.TestUtils.g
1312
import kotlin.math.min
13+
import kotlin.use
1414

1515
class Day10 @Inject constructor(
1616
private val generatorFactory: InputGeneratorFactory,
1717
) {
1818
fun partOne(filename: String) = generatorFactory.forFile(filename).readAs(::day10) { input ->
19-
input.sumOf { machine -> flipLights(machine.indicatorLights, machine.buttonSchematics) }
19+
input.sumOf { machine ->
20+
thing(".".repeat(machine.indicatorLights.length), machine.indicatorLights, machine.buttonSchematics)
21+
}
2022
}
2123

2224
fun partTwo(filename: String) = generatorFactory.forFile(filename).readAs(::day10) { input ->
23-
input.sumOf { machine -> enableJoltages(machine) }
24-
}
25-
26-
private fun enableJoltages(machine: Machine) : Int {
27-
return Context().use { ctx ->
28-
val opt = ctx.mkOptimize()
29-
30-
fun intVariableOf(name: String) = ctx.mkIntConst(name)
31-
32-
fun intValueOf(value: Int) = ctx.mkInt(value)
33-
34-
infix fun IntExpr.gte(t: IntExpr) = ctx.mkGe(this, t)
35-
36-
operator fun ArithExpr<IntSort>.plus(t: IntExpr) = ctx.mkAdd(this, t)
37-
38-
infix fun ArithExpr<IntSort>.equalTo(t: IntExpr) = ctx.mkEq(this, t)
39-
40-
fun List<IntExpr>.sum() = ctx.mkAdd(*this.toTypedArray())
41-
42-
val ZERO = intValueOf(0)
43-
44-
val affectedJoltages = mutableMapOf<Int, MutableList<IntExpr>>()
45-
val buttonVariables = machine.buttonSchematics.mapIndexed { index, schematic ->
46-
// create button variable
47-
intVariableOf(index.toString()).also { buttonVariable ->
48-
// track the joltages if affects
49-
schematic.affectedIndices.forEach { affectedIndex ->
50-
affectedJoltages.computeIfAbsent(affectedIndex) { _ -> mutableListOf() }.add(buttonVariable)
51-
}
52-
// add it to the optimizer
53-
opt.Add(buttonVariable gte ZERO)
54-
}
55-
}
56-
57-
affectedJoltages.forEach { (joltageIndex, buttonsAffecting) ->
58-
val targetValue = intValueOf(machine.joltages[joltageIndex])
59-
val sumOfButtonPresses = buttonsAffecting.sum()
60-
opt.Add(sumOfButtonPresses equalTo targetValue)
61-
}
62-
63-
opt.MkMinimize(buttonVariables.sum())
64-
65-
val status = opt.Check()
66-
67-
if (status == Status.SATISFIABLE) {
68-
val model = opt.getModel()
69-
((model.evaluate(buttonVariables.sum(), true) as IntNum).int)
70-
} else {
71-
throw IllegalStateException("No Solution Found")
25+
input.sumOf { machine ->
26+
27+
Context().use { ctx ->
28+
var bestFound = Int.MAX_VALUE
29+
30+
val bits = 64 // the answer will fit inside a long
31+
32+
fun valueOf(value: Int) = ctx.mkBV(value, bits)
33+
34+
fun variableOf(name: String) = ctx.mkBVConst(name, bits)
35+
36+
infix fun Expr<BitVecSort>.equalTo(t: Expr<BitVecSort>) = ctx.mkEq(this, t)
37+
38+
infix fun Expr<BitVecSort>.notEqual(t: Expr<BitVecSort>) = ctx.mkNot(this equalTo t)
39+
40+
operator fun Expr<BitVecSort>.plus(t: Expr<BitVecSort>) = ctx.mkBVAdd(this, t)
41+
42+
operator fun Expr<BitVecSort>.times(t: Expr<BitVecSort>) = ctx.mkBVMul(this, t)
43+
44+
infix fun Expr<BitVecSort>.lessThan(t: Expr<BitVecSort>) = ctx.mkBVSLT(this, t)
45+
46+
infix fun Expr<BitVecSort>.gte(t: Expr<BitVecSort>) = ctx.mkBVSGE(this, t)
47+
48+
val a = variableOf("a")
49+
val b = variableOf("b")
50+
val c = variableOf("c")
51+
val d = variableOf("d")
52+
val e = variableOf("e")
53+
val f = variableOf("f")
54+
55+
val optimizer = ctx.mkOptimize()
56+
57+
optimizer.Add(e + f equalTo valueOf(3))
58+
optimizer.Add(b + f equalTo valueOf(5))
59+
optimizer.Add(c + d + e equalTo valueOf(4))
60+
optimizer.Add(a + b + d equalTo valueOf(7))
61+
// optimizer.Add(a lessThan valueOf(10000))
62+
// optimizer.Add(b lessThan valueOf(10000))
63+
// optimizer.Add(c lessThan valueOf(10000))
64+
// optimizer.Add(d lessThan valueOf(10000))
65+
// optimizer.Add(e lessThan valueOf(10000))
66+
// optimizer.Add(f lessThan valueOf(10000))
67+
optimizer.Add(a gte valueOf(0))
68+
optimizer.Add(b gte valueOf(0))
69+
optimizer.Add(c gte valueOf(0))
70+
optimizer.Add(d gte valueOf(0))
71+
optimizer.Add(e gte valueOf(0))
72+
optimizer.Add(f gte valueOf(0))
73+
74+
optimizer.MkMinimize(a + b + c + d + e + f)
75+
76+
optimizer.Check()
77+
// while(optimizer.Check() == Status.SATISFIABLE) {
78+
val model = optimizer.model
79+
80+
val aEval = (model.evaluate(a, true) as BitVecNum)
81+
val bEval = (model.evaluate(b, true) as BitVecNum)
82+
val cEval = (model.evaluate(c, true) as BitVecNum)
83+
val dEval = (model.evaluate(d, true) as BitVecNum)
84+
val eEval = (model.evaluate(e, true) as BitVecNum)
85+
val fEval = (model.evaluate(f, true) as BitVecNum)
86+
87+
bestFound = min(bestFound, aEval.int + bEval.int + cEval.int + dEval.int + eEval.int + fEval.int)
88+
89+
// optimizer.Add(
90+
// ctx.mkOr(
91+
// a notEqual aEval,
92+
// b notEqual bEval,
93+
// c notEqual cEval,
94+
// d notEqual dEval,
95+
// e notEqual eEval,
96+
// f notEqual fEval,
97+
// )
98+
// )
99+
// }
100+
// println(bestFound)
101+
bestFound
72102
}
73103
}
74104
}
75105

76-
fun flipLights(goal: String, buttonSchematics: List<ButtonSchematic>): Long {
77-
val minPressesForState = mutableMapOf(".".repeat(goal.length) to 0L)
106+
107+
fun thing(current: String, goal: String, buttonSchematics: List<ButtonSchematic>): Long {
108+
val minPressesForState = mutableMapOf(current to 0L)
78109
while(!minPressesForState.containsKey(goal)) {
79110
minPressesForState.entries.toList().forEach { (light, cost) ->
80111
val nextStates = possibleLights(light, buttonSchematics)
@@ -97,7 +128,7 @@ class Day10 @Inject constructor(
97128

98129
private fun applyLightPress(current: String, buttonSchematic: ButtonSchematic): String {
99130
return current.mapIndexed { index, c ->
100-
if (buttonSchematic.affectedIndices.contains(index)) {
131+
if (buttonSchematic.lightsAffected.contains(index)) {
101132
if (c == '#') { '.' } else { '#' }
102133
} else { c }
103134
}.joinToString("")
@@ -122,4 +153,6 @@ data class Machine(
122153
val joltages: List<Int>,
123154
)
124155

125-
data class ButtonSchematic(val affectedIndices: List<Int>)
156+
/** zero indexed */
157+
// TODO rename
158+
data class ButtonSchematic(val lightsAffected: List<Int>)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
## [Day 10: Factory](https://adventofcode.com/2025/day/10)
1+
## [](https://adventofcode.com/2025/day/10)

src/test/kotlin/me/peckb/aoc/_2025/calendar/day10/Day10Test.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ internal class Day10Test {
2323

2424
@Test
2525
fun testDay10PartTwo() {
26-
assertEquals(19810, day10.partTwo(DAY_10))
26+
assertEquals(-1, day10.partTwo(DAY_10))
2727
}
2828

2929
companion object {

0 commit comments

Comments
 (0)