Skip to content

Commit 81d234b

Browse files
committed
Refactor 2025 day 11 for alternative solutions
1 parent 13555e1 commit 81d234b

File tree

2 files changed

+67
-33
lines changed

2 files changed

+67
-33
lines changed

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

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,72 @@ import scala.collection.mutable
55
object Day11 {
66

77
type Device = String
8+
type Devices = Map[Device, Seq[Device]]
89

9-
trait Part {
10+
trait PartDevices {
1011
val from: Device
1112
val via: Set[Device]
1213
val to: Device = "out"
13-
14-
def countPaths(devices: Map[Device, Seq[Device]]): Long = {
15-
val memo = mutable.Map.empty[Device, Map[Set[Device], Long]]
16-
17-
def helper(device: Device): Map[Set[Device], Long] = {
18-
memo.getOrElseUpdate(device, {
19-
val deviceVia = via.intersect(Set(device))
20-
if (device == to)
21-
Map(deviceVia -> 1)
22-
else
23-
devices(device).flatMap(helper).groupMapReduce(_._1 ++ deviceVia)(_._2)(_ + _)
24-
})
25-
}
26-
27-
helper(from)(via)
28-
}
2914
}
3015

31-
object Part1 extends Part {
16+
trait Part1Devices extends PartDevices {
3217
override val from: Device = "you"
3318
override val via: Set[Device] = Set.empty
3419
}
3520

36-
object Part2 extends Part {
21+
trait Part2Devices extends PartDevices {
3722
override val from: Device = "svr"
3823
override val via: Set[Device] = Set("dac", "fft")
3924
}
4025

26+
trait PartSolution extends PartDevices {
27+
def countPaths(devices: Devices): Long
28+
}
29+
30+
trait Solution {
31+
val Part1: PartSolution
32+
val Part2: PartSolution
33+
}
34+
35+
/**
36+
* Solution, which counts paths separately for subsets of visited vias.
37+
*/
38+
object ViaMapSolution extends Solution {
39+
trait ViaMapPartSolution extends PartSolution {
40+
override def countPaths(devices: Devices): Long = {
41+
val memo = mutable.Map.empty[Device, Map[Set[Device], Long]]
42+
43+
def helper(device: Device): Map[Set[Device], Long] = {
44+
memo.getOrElseUpdate(device, {
45+
val deviceVia = via.intersect(Set(device))
46+
if (device == to)
47+
Map(deviceVia -> 1)
48+
else
49+
devices(device).flatMap(helper).groupMapReduce(_._1 ++ deviceVia)(_._2)(_ + _)
50+
})
51+
}
52+
53+
helper(from)(via)
54+
}
55+
}
56+
57+
override object Part1 extends ViaMapPartSolution with Part1Devices
58+
override object Part2 extends ViaMapPartSolution with Part2Devices
59+
}
60+
61+
// TODO: path count product solution
62+
4163
def parseDevice(s: String): (Device, Seq[Device]) = s match {
4264
case s"$key: $values" => key -> values.split(" ").toSeq
4365
}
4466

45-
def parseDevices(input: String): Map[Device, Seq[Device]] = input.linesIterator.map(parseDevice).toMap
67+
def parseDevices(input: String): Devices = input.linesIterator.map(parseDevice).toMap
4668

4769
lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day11.txt")).mkString.trim
4870

4971
def main(args: Array[String]): Unit = {
72+
import ViaMapSolution._
73+
5074
println(Part1.countPaths(parseDevices(input)))
5175
println(Part2.countPaths(parseDevices(input)))
5276
}

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

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

3-
import Day11._
3+
import Day11.*
4+
import Day11Test.*
5+
import org.scalatest.Suites
46
import org.scalatest.funsuite.AnyFunSuite
57

6-
class Day11Test extends AnyFunSuite {
8+
class Day11Test extends Suites(
9+
new ViaMapSolutionTest,
10+
)
11+
12+
object Day11Test {
713

814
val exampleInput =
915
"""aaa: you hhh
@@ -32,19 +38,23 @@ class Day11Test extends AnyFunSuite {
3238
|ggg: out
3339
|hhh: out""".stripMargin
3440

35-
test("Part 1 examples") {
36-
assert(Part1.countPaths(parseDevices(exampleInput)) == 5)
37-
}
41+
abstract class SolutionTest(solution: Solution) extends AnyFunSuite {
42+
test("Part 1 examples") {
43+
assert(solution.Part1.countPaths(parseDevices(exampleInput)) == 5)
44+
}
3845

39-
test("Part 1 input answer") {
40-
assert(Part1.countPaths(parseDevices(input)) == 643)
41-
}
46+
test("Part 1 input answer") {
47+
assert(solution.Part1.countPaths(parseDevices(input)) == 643)
48+
}
4249

43-
test("Part 2 examples") {
44-
assert(Part2.countPaths(parseDevices(exampleInput2)) == 2)
45-
}
50+
test("Part 2 examples") {
51+
assert(solution.Part2.countPaths(parseDevices(exampleInput2)) == 2)
52+
}
4653

47-
test("Part 2 input answer") {
48-
assert(Part2.countPaths(parseDevices(input)) == 417190406827152L)
54+
test("Part 2 input answer") {
55+
assert(solution.Part2.countPaths(parseDevices(input)) == 417190406827152L)
56+
}
4957
}
58+
59+
class ViaMapSolutionTest extends SolutionTest(ViaMapSolution)
5060
}

0 commit comments

Comments
 (0)