Skip to content

Commit 30488a3

Browse files
committed
2024-06 Scala 2 - Refactoring
1 parent 926a5d5 commit 30488a3

File tree

5 files changed

+68
-69
lines changed

5 files changed

+68
-69
lines changed

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

+16-38
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@ package jurisk.adventofcode.y2024
33
import cats.implicits._
44
import jurisk.adventofcode.y2024.Advent06.Block.Empty
55
import jurisk.adventofcode.y2024.Advent06.Block.Wall
6-
import jurisk.collections.mutable.BitSetKey
7-
import jurisk.collections.mutable.BitSetKeySyntax._
86
import jurisk.collections.mutable.MutableBitSet
97
import jurisk.geometry.Coords2D
108
import jurisk.geometry.Direction2D
119
import jurisk.geometry.Direction2D.CardinalDirection2D
1210
import jurisk.geometry.Field2D
11+
import jurisk.geometry.Field2D.coordsToInt
12+
import jurisk.geometry.Field2D.intToCoords
1313
import jurisk.geometry.Rotation
1414
import jurisk.utils.FileInput._
15+
import jurisk.utils.FromInt
1516
import jurisk.utils.Parsing.StringOps
1617
import jurisk.utils.Simulation
18+
import jurisk.utils.ToInt
19+
import jurisk.utils.conversions.syntax._
1720

1821
object Advent06 {
1922
sealed trait Block extends Product with Serializable
@@ -58,11 +61,7 @@ object Advent06 {
5861
private def guardsPath(data: Input): MutableBitSet[Coords2D] = {
5962
val (location, field) = data
6063

61-
implicit val key: BitSetKey[Coords2D] = new BitSetKey[Coords2D] {
62-
def toInt(value: Coords2D): Int = value.x + value.y * field.width
63-
def fromInt(value: Int): Coords2D =
64-
Coords2D(value % field.width, value / field.width)
65-
}
64+
implicit val c2i: ToInt[Coords2D] = coordsToInt(field)
6665

6766
val visited = MutableBitSet[Coords2D](location)
6867

@@ -88,39 +87,16 @@ object Advent06 {
8887
location: Coords2D,
8988
field: Field2D[Block],
9089
): 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-
}
90+
implicit val c2i: ToInt[Coords2D] = coordsToInt(field)
91+
implicit val g2i: ToInt[Guard] = (guard: Guard) => {
92+
val directionInt = guard.direction match {
93+
case Direction2D.N => 0
94+
case Direction2D.E => 1
95+
case Direction2D.S => 2
96+
case Direction2D.W => 3
11397
}
11498

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-
}
99+
guard.location.toInt * 4 + directionInt
124100
}
125101

126102
Simulation
@@ -133,6 +109,8 @@ object Advent06 {
133109
def part2(data: Input): Int = {
134110
val (location, field) = data
135111

112+
implicit val i2c: FromInt[Coords2D] = intToCoords(field)
113+
136114
guardsPath(data)
137115
.count(c =>
138116
c != location && wouldLoop(location, field.updatedAtUnsafe(c, Wall))

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

+8-29
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,12 @@
11
package jurisk.collections.mutable
22

3-
import jurisk.collections.mutable.BitSetKeySyntax.BitSetKeyOps1
4-
import jurisk.collections.mutable.BitSetKeySyntax.BitSetKeyOps2
3+
import jurisk.utils.FromInt
4+
import jurisk.utils.ToInt
5+
import jurisk.utils.conversions.syntax._
56

67
import scala.collection.mutable
78

8-
trait BitSetKey[T] {
9-
def toInt(value: T): Int
10-
def fromInt(value: Int): T
11-
}
12-
13-
object BitSetKeyInstances {
14-
implicit val intBitSetKey: BitSetKey[Int] = new BitSetKey[Int] {
15-
def toInt(value: Int): Int = value
16-
def fromInt(value: Int): Int = value
17-
}
18-
}
19-
20-
object BitSetKeySyntax {
21-
implicit class BitSetKeyOps1[T](value: T)(implicit ev: BitSetKey[T]) {
22-
def toInt: Int = ev.toInt(value)
23-
}
24-
25-
implicit class BitSetKeyOps2(value: Int) {
26-
def fromInt[T](implicit ev: BitSetKey[T]): T = ev.fromInt(value)
27-
}
28-
}
29-
30-
final class MutableBitSet[T: BitSetKey](
9+
final class MutableBitSet[T: ToInt](
3110
private val underlying: mutable.BitSet
3211
) {
3312
private def this() =
@@ -41,23 +20,23 @@ final class MutableBitSet[T: BitSetKey](
4120

4221
def filterNot(
4322
predicate: T => Boolean
44-
): MutableBitSet[T] =
23+
)(implicit FI: FromInt[T]): MutableBitSet[T] =
4524
new MutableBitSet(underlying.filterNot(x => predicate(x.fromInt)))
4625

4726
def count(
4827
predicate: T => Boolean
49-
): Int =
28+
)(implicit FI: FromInt[T]): Int =
5029
underlying.count(x => predicate(x.fromInt))
5130

5231
def contains(value: T): Boolean =
5332
underlying.contains(value.toInt)
5433
}
5534

5635
object MutableBitSet {
57-
def empty[T: BitSetKey]: MutableBitSet[T] =
36+
def empty[T: ToInt]: MutableBitSet[T] =
5837
new MutableBitSet[T]()
5938

60-
def apply[T: BitSetKey](values: T*): MutableBitSet[T] = {
39+
def apply[T: ToInt](values: T*): MutableBitSet[T] = {
6140
val result = new MutableBitSet[T]()
6241
values.foreach(result.add)
6342
result

scala2/src/main/scala/jurisk/geometry/Field2D.scala

+8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import jurisk.algorithms.pathfinding.Bfs
88
import jurisk.collections.immutable.BiMap
99
import jurisk.collections.immutable.graph.Graph
1010
import jurisk.geometry.Direction2D.CardinalDirection2D
11+
import jurisk.utils.FromInt
1112
import jurisk.utils.Parsing.StringOps
13+
import jurisk.utils.ToInt
1214

1315
import scala.collection.immutable.ArraySeq
1416
import scala.reflect.ClassTag
@@ -317,6 +319,12 @@ final case class Field2D[T] private (
317319
}
318320

319321
object Field2D {
322+
// Useful helpers to generate implicits used by the `jurisk.collections.mutable.MutableBitSet`
323+
def coordsToInt[S](field: Field2D[S]): ToInt[Coords2D] = (value: Coords2D) =>
324+
value.x + value.y * field.width
325+
def intToCoords[S](field: Field2D[S]): FromInt[Coords2D] = (value: Int) =>
326+
Coords2D(value % field.width, value / field.width)
327+
320328
implicit val functorInstance: Functor[Field2D] = new Functor[Field2D] {
321329
override def map[A, B](fa: Field2D[A])(f: A => B): Field2D[B] =
322330
fa.mapByCoordsWithValues { case (_, v) => f(v) }

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

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

33
import cats.implicits._
4-
import jurisk.collections.mutable.BitSetKey
54
import jurisk.collections.mutable.MutableBitSet
65

76
import scala.annotation.tailrec
@@ -129,7 +128,7 @@ object Simulation {
129128
}
130129
}
131130

132-
def detectLoopUsingBitSet[State: BitSetKey, Result](initial: State)(
131+
def detectLoopUsingBitSet[State: ToInt, Result](initial: State)(
133132
f: (State, Counter) => Either[Result, State]
134133
): Either[Result, Counter] = {
135134
val alreadySeen = MutableBitSet.empty[State]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package jurisk.utils
2+
3+
trait ToInt[T] {
4+
def toInt(value: T): Int
5+
}
6+
7+
trait FromInt[T] {
8+
def fromInt(value: Int): T
9+
}
10+
11+
object ToIntInstances {
12+
implicit val intToInt: ToInt[Int] = identity
13+
}
14+
15+
object FromIntInstances {
16+
implicit val intFromInt: FromInt[Int] = identity
17+
}
18+
19+
trait ToIntSyntax {
20+
implicit class ToIntOps[T](value: T)(implicit ev: ToInt[T]) {
21+
def toInt: Int = ev.toInt(value)
22+
}
23+
}
24+
25+
trait FromIntSyntax {
26+
implicit class FromIntOps(value: Int) {
27+
def fromInt[T](implicit ev: FromInt[T]): T = ev.fromInt(value)
28+
}
29+
}
30+
31+
abstract class AllSyntax extends ToIntSyntax with FromIntSyntax
32+
33+
object conversions {
34+
object syntax extends AllSyntax
35+
}

0 commit comments

Comments
 (0)