Skip to content

Commit 6bb7b27

Browse files
committed
Refactoring 2024-06 Scala 2
1 parent 961324f commit 6bb7b27

File tree

3 files changed

+64
-5
lines changed

3 files changed

+64
-5
lines changed

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

+39-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import cats.implicits._
44
import jurisk.adventofcode.y2024.Advent06.Block.Empty
55
import jurisk.adventofcode.y2024.Advent06.Block.Wall
66
import jurisk.collections.mutable.BitSetKey
7+
import jurisk.collections.mutable.BitSetKeySyntax._
78
import jurisk.collections.mutable.MutableBitSet
89
import jurisk.geometry.Coords2D
910
import jurisk.geometry.Direction2D
@@ -86,12 +87,48 @@ object Advent06 {
8687
private def wouldLoop(
8788
location: Coords2D,
8889
field: Field2D[Block],
89-
): Boolean =
90+
): Boolean = {
91+
implicit val coordsBitSetKey: BitSetKey[Coords2D] =
92+
new BitSetKey[Coords2D] {
93+
def toInt(value: Coords2D): Int = value.x + value.y * field.width
94+
def fromInt(value: Int): Coords2D =
95+
Coords2D(value % field.width, value / field.width)
96+
}
97+
98+
implicit val directionBitSetKey: BitSetKey[CardinalDirection2D] =
99+
new BitSetKey[CardinalDirection2D] {
100+
def toInt(value: CardinalDirection2D): Int = value match {
101+
case Direction2D.N => 0
102+
case Direction2D.E => 1
103+
case Direction2D.S => 2
104+
case Direction2D.W => 3
105+
}
106+
def fromInt(value: Int): CardinalDirection2D = value match {
107+
case 0 => Direction2D.N
108+
case 1 => Direction2D.E
109+
case 2 => Direction2D.S
110+
case 3 => Direction2D.W
111+
case _ => s"Invalid value: $value".fail
112+
}
113+
}
114+
115+
implicit val guardBitSetKey: BitSetKey[Guard] = new BitSetKey[Guard] {
116+
def toInt(guard: Guard): Int =
117+
guard.location.toInt * 4 + guard.direction.toInt
118+
119+
def fromInt(value: Int): Guard = {
120+
val location = (value / 4).fromInt[Coords2D]
121+
val direction = (value % 4).fromInt[CardinalDirection2D]
122+
Guard(location, direction)
123+
}
124+
}
125+
90126
Simulation
91-
.detectLoop(Guard(location, Direction2D.N)) { case (s, _) =>
127+
.detectLoopUsingBitSet(Guard(location, Direction2D.N)) { case (s, _) =>
92128
s.next(field).toRight(())
93129
}
94130
.isRight
131+
}
95132

96133
def part2(data: Input): Int = {
97134
val (location, field) = data

scala2/src/main/scala/jurisk/collections/mutable/MutableBitSet.scala

+8-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ object BitSetKeySyntax {
2222
def toInt: Int = ev.toInt(value)
2323
}
2424

25-
implicit class BitSetKeyOps2[T](value: Int)(implicit ev: BitSetKey[T]) {
26-
def fromInt: T = ev.fromInt(value)
25+
implicit class BitSetKeyOps2(value: Int) {
26+
def fromInt[T](implicit ev: BitSetKey[T]): T = ev.fromInt(value)
2727
}
2828
}
2929

@@ -48,9 +48,15 @@ final class MutableBitSet[T: BitSetKey](
4848
predicate: T => Boolean
4949
): Int =
5050
underlying.count(x => predicate(x.fromInt))
51+
52+
def contains(value: T): Boolean =
53+
underlying.contains(value.toInt)
5154
}
5255

5356
object MutableBitSet {
57+
def empty[T: BitSetKey]: MutableBitSet[T] =
58+
new MutableBitSet[T]()
59+
5460
def apply[T: BitSetKey](values: T*): MutableBitSet[T] = {
5561
val result = new MutableBitSet[T]()
5662
values.foreach(result.add)

scala2/src/main/scala/jurisk/utils/Simulation.scala

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package jurisk.utils
22

33
import cats.implicits._
4+
import jurisk.collections.mutable.BitSetKey
5+
import jurisk.collections.mutable.MutableBitSet
46

57
import scala.annotation.tailrec
68
import scala.collection.mutable
@@ -115,7 +117,7 @@ object Simulation {
115117
def detectLoop[State, Result](initial: State)(
116118
f: (State, Counter) => Either[Result, State]
117119
): Either[Result, (Counter, Counter)] = {
118-
val alreadySeen: mutable.HashMap[State, Counter] = mutable.HashMap.empty
120+
val alreadySeen: mutable.Map[State, Counter] = mutable.HashMap.empty
119121
runWithIterationCount(initial) { case (state, iteration) =>
120122
alreadySeen.get(state) match {
121123
case Some(iterationWeSawThisBefore) =>
@@ -126,4 +128,18 @@ object Simulation {
126128
}
127129
}
128130
}
131+
132+
def detectLoopUsingBitSet[State: BitSetKey, Result](initial: State)(
133+
f: (State, Counter) => Either[Result, State]
134+
): Either[Result, Counter] = {
135+
val alreadySeen = MutableBitSet.empty[State]
136+
runWithIterationCount(initial) { case (state, iteration) =>
137+
if (alreadySeen.contains(state)) {
138+
iteration.asRight.asLeft
139+
} else {
140+
alreadySeen.add(state)
141+
f(state, iteration).leftMap(_.asLeft)
142+
}
143+
}
144+
}
129145
}

0 commit comments

Comments
 (0)