Skip to content

Commit eb7a970

Browse files
committed
2024-24 Refactoring
1 parent 764a40c commit eb7a970

File tree

1 file changed

+50
-36
lines changed

1 file changed

+50
-36
lines changed

scala2/src/main/scala/jurisk/adventofcode/y2024/Advent24.scala

+50-36
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package jurisk.adventofcode.y2024
22

33
import cats.effect.IO
44
import cats.effect.IOApp
5-
import jurisk.adventofcode.y2024.Advent24.Connections.InputBits
6-
import jurisk.adventofcode.y2024.Advent24.Connections.OutputBits
75
import jurisk.adventofcode.y2024.Advent24.Operation.And
86
import jurisk.adventofcode.y2024.Advent24.Operation.Or
97
import jurisk.adventofcode.y2024.Advent24.Operation.Xor
@@ -20,8 +18,46 @@ import mouse.all.booleanSyntaxMouse
2018
import scala.annotation.tailrec
2119

2220
object Advent24 extends IOApp.Simple {
23-
private type Values = Map[Wire, Boolean]
24-
type Input = (Values, Connections)
21+
private val InputBits = 45
22+
private val OutputBits = InputBits + 1
23+
24+
type Input = (Values, Connections)
25+
26+
final case class Values private (map: Map[Wire, Boolean]) {
27+
def getOrFalse(wire: Wire): Boolean = map.getOrElse(wire, false)
28+
def contains(wire: Wire): Boolean = map.contains(wire)
29+
def +(pair: (Wire, Boolean)): Values = new Values(map + pair)
30+
def ++(other: Values): Values = new Values(map ++ other.map)
31+
32+
def zValue: Long = {
33+
val z = map.collect { case (Wire.Z(zIdx), v) => (zIdx, v) }.toList
34+
val zBits =
35+
z.sorted.map { case (_, b) => if (b) "1" else "0" }.mkString.reverse
36+
java.lang.Long.parseLong(zBits, 2)
37+
}
38+
}
39+
40+
private object Values {
41+
val Zero: Values = Values {
42+
(0 until InputBits).flatMap { b =>
43+
List(
44+
Wire.X(b) -> false,
45+
Wire.Y(b) -> false,
46+
)
47+
}.toMap
48+
}
49+
50+
def apply(pairs: (Wire, Boolean)*): Values = Values(pairs.toMap)
51+
52+
def parse(s: String): Values = {
53+
val map = s.splitLines
54+
.map(
55+
_.parsePairUnsafe(": ", Wire.parse, _.toInt.toBooleanStrict01Unsafe)
56+
)
57+
.toMap
58+
new Values(map)
59+
}
60+
}
2561

2662
sealed trait Wire extends Product with Serializable
2763
private object Wire {
@@ -50,13 +86,7 @@ object Advent24 extends IOApp.Simple {
5086
}
5187
}
5288

53-
private def replace(s: Wire, replacements: Map[Wire, Wire]): Wire =
54-
replacements.getOrElse(s, s)
55-
5689
object Connections {
57-
private val InputBits = 45
58-
private val OutputBits = InputBits + 1
59-
6090
def parse(s: String): Connections =
6191
Connections.fromIterable(s.splitLines.toSet map Connection.parse)
6292

@@ -84,32 +114,24 @@ object Advent24 extends IOApp.Simple {
84114

85115
// TODO: This doesn't do a sufficient test, as these bit-by-bit tests don't catch all issues that could happen. Consider adding random numbers.
86116
private def errorsOnAddition: Int = {
87-
def errorsAddingBit(bit: Int): Int = {
88-
def zeroWires: Values =
89-
(0 until InputBits).flatMap { b =>
90-
List(
91-
Wire.X(b) -> false,
92-
Wire.Y(b) -> false,
93-
)
94-
}.toMap
95-
117+
def errorsAddingBit(bit: Int): Int =
96118
List(
97119
(false, false, false, false),
98120
(false, true, true, false),
99121
(true, false, true, false),
100122
(true, true, false, true),
101123
).map { case (x, y, r, c) =>
102-
val values = zeroWires ++ Map(Wire.X(bit) -> x, Wire.Y(bit) -> y)
124+
val values = Values.Zero ++ Values(Wire.X(bit) -> x, Wire.Y(bit) -> y)
103125
val output = propagate(values).orFail("Failed to propagate")
104-
val invalidR = output.getOrElse(Wire.Z(bit), false) != r
126+
val invalidR = output.getOrFalse(Wire.Z(bit)) != r
105127
val carryBit = bit + 1
106-
val invalidC = output.getOrElse(Wire.Z(carryBit), false) != c
128+
val invalidC = output.getOrFalse(Wire.Z(carryBit)) != c
107129
val extraBits = (0 until OutputBits)
108130
.filter { b =>
109131
b != bit && b != carryBit
110132
}
111133
.count { i =>
112-
output.getOrElse(Wire.Z(i), false)
134+
output.getOrFalse(Wire.Z(i))
113135
}
114136
val DebugPrint = false
115137
if (DebugPrint && (invalidR || invalidC || extraBits > 0)) {
@@ -118,7 +140,6 @@ object Advent24 extends IOApp.Simple {
118140
}
119141
invalidR.toInt + invalidC.toInt + extraBits
120142
}.sum
121-
}
122143

123144
(0 until InputBits).map { bit =>
124145
errorsAddingBit(bit)
@@ -211,8 +232,8 @@ object Advent24 extends IOApp.Simple {
211232

212233
final case class Connection(a: Wire, b: Wire, op: Operation) {
213234
def result(values: Values): Boolean = {
214-
val aV = values.getOrElse(a, false)
215-
val bV = values.getOrElse(b, false)
235+
val aV = values.getOrFalse(a)
236+
val bV = values.getOrFalse(b)
216237
op match {
217238
case And => aV && bV
218239
case Or => aV || bV
@@ -265,21 +286,14 @@ object Advent24 extends IOApp.Simple {
265286

266287
def parse(input: String): Input =
267288
input.parsePairByDoubleNewline(
268-
_.splitLines
269-
.map(
270-
_.parsePairUnsafe(": ", Wire.parse, _.toInt.toBooleanStrict01Unsafe)
271-
)
272-
.toMap,
289+
Values.parse,
273290
Connections.parse,
274291
)
275292

276-
def part1(data: Input): BigInt = {
293+
def part1(data: Input): Long = {
277294
val (wires, connections) = data
278295
val results = connections.propagate(wires).orFail("Failed to propagate")
279-
val z = results.collect { case (Wire.Z(zIdx), v) => (zIdx, v) }.toList
280-
val zBits =
281-
z.sorted.map { case (_, b) => if (b) "1" else "0" }.mkString.reverse
282-
BigInt(zBits, 2)
296+
results.zValue
283297
}
284298

285299
private def debugWrite(connections: Connections): IO[Unit] = {

0 commit comments

Comments
 (0)