Skip to content

Commit 466402f

Browse files
committed
Add bifurcate solution to 2025 day 10 part 2
1 parent 06b56b6 commit 466402f

File tree

2 files changed

+48
-7
lines changed

2 files changed

+48
-7
lines changed

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

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

3-
import eu.sim642.adventofcodelib.IteratorImplicits.*
4-
import com.microsoft.z3.{ArithExpr, Context, IntExpr, IntSort, Status}
5-
import eu.sim642.adventofcodelib.{GaussianElimination, NumberTheory}
6-
import eu.sim642.adventofcodelib.graph.{BFS, Dijkstra, GraphSearch, TargetNode, UnitNeighbors}
3+
import com.microsoft.z3.{ArithExpr, Context, IntSort, Status}
4+
import eu.sim642.adventofcodelib.GaussianElimination
5+
import eu.sim642.adventofcodelib.graph.{BFS, GraphSearch, TargetNode, UnitNeighbors}
76

8-
import scala.collection.mutable
97
import scala.jdk.CollectionConverters.*
108

119
object Day10 {
@@ -64,7 +62,7 @@ object Day10 {
6462
object Z3Part2Solution extends Part2Solution {
6563
override def fewestPresses(machine: Machine): Int = {
6664
val ctx = new Context(Map("model" -> "true").asJava)
67-
import ctx._
65+
import ctx.*
6866
val s = mkOptimize()
6967

7068
val buttonPresses = machine.buttons.zipWithIndex.map((_, i) => mkIntConst(s"x$i"))
@@ -150,6 +148,46 @@ object Day10 {
150148
}
151149
}
152150

151+
/**
152+
* Solution, which reduces parity of joltages to part 1-like problem.
153+
* @see [[https://www.reddit.com/r/adventofcode/comments/1pk87hl/2025_day_10_part_2_bifurcate_your_way_to_victory/]]
154+
*/
155+
object BifurcatePart2Solution extends Part2Solution {
156+
override def fewestPresses(machine: Machine): Int = {
157+
def parity(joltages: Joltages): Lights =
158+
joltages.map(i => if (i % 2 != 0) true else false)
159+
160+
val zeroJoltages: Joltages = machine.joltages.map(_ => 0)
161+
val parityPresses =
162+
machine.buttons.toSet
163+
.subsets()
164+
.map(buttons =>
165+
buttons.foldLeft(zeroJoltages)((acc, button) =>
166+
button.foldLeft(acc)((acc, i) => acc.updated(i, acc(i) + 1))
167+
) -> buttons.size
168+
)
169+
.toSeq
170+
.groupBy((joltages, _) => parity(joltages))
171+
.withDefaultValue(Seq.empty)
172+
173+
def helper(joltages: Joltages): Option[Int] = {
174+
if (joltages == zeroJoltages)
175+
Some(0)
176+
else if (joltages.exists(_ < 0))
177+
None
178+
else {
179+
(for {
180+
(pressJoltages, presses) <- parityPresses(parity(joltages))
181+
newJoltages = (joltages lazyZip pressJoltages).map(_ - _).map(_ / 2)
182+
newPresses <- helper(newJoltages)
183+
} yield 2 * newPresses + presses).minOption
184+
}
185+
}
186+
187+
helper(machine.joltages).get
188+
}
189+
}
190+
153191
def parseMachine(s: String): Machine = s match {
154192
case s"[$lightsStr] $buttonsStr {$joltagesStr}" =>
155193
val lights = lightsStr.map(_ == '#').toVector
@@ -164,6 +202,6 @@ object Day10 {
164202

165203
def main(args: Array[String]): Unit = {
166204
println(Part1.sumFewestPresses(parseMachines(input)))
167-
println(GaussianEliminationPart2Solution.sumFewestPresses(parseMachines(input)))
205+
println(BifurcatePart2Solution.sumFewestPresses(parseMachines(input)))
168206
}
169207
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Day10Test extends Suites(
1010
new NaivePart2SolutionTest,
1111
new Z3Part2SolutionTest,
1212
new GaussianEliminationPart2SolutionTest,
13+
new BifurcatePart2SolutionTest,
1314
)
1415

1516
object Day10Test {
@@ -52,4 +53,6 @@ object Day10Test {
5253
class Z3Part2SolutionTest extends Part2SolutionTest(Z3Part2Solution)
5354

5455
class GaussianEliminationPart2SolutionTest extends Part2SolutionTest(GaussianEliminationPart2Solution)
56+
57+
class BifurcatePart2SolutionTest extends Part2SolutionTest(BifurcatePart2Solution)
5558
}

0 commit comments

Comments
 (0)