Skip to content

Commit

Permalink
Refactoring 2024-06 Scala 2
Browse files Browse the repository at this point in the history
  • Loading branch information
jurisk committed Dec 7, 2024
1 parent 961324f commit 6bb7b27
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 5 deletions.
41 changes: 39 additions & 2 deletions scala2/src/main/scala/jurisk/adventofcode/y2024/Advent06.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cats.implicits._
import jurisk.adventofcode.y2024.Advent06.Block.Empty
import jurisk.adventofcode.y2024.Advent06.Block.Wall
import jurisk.collections.mutable.BitSetKey
import jurisk.collections.mutable.BitSetKeySyntax._
import jurisk.collections.mutable.MutableBitSet
import jurisk.geometry.Coords2D
import jurisk.geometry.Direction2D
Expand Down Expand Up @@ -86,12 +87,48 @@ object Advent06 {
private def wouldLoop(
location: Coords2D,
field: Field2D[Block],
): Boolean =
): Boolean = {
implicit val coordsBitSetKey: BitSetKey[Coords2D] =
new BitSetKey[Coords2D] {
def toInt(value: Coords2D): Int = value.x + value.y * field.width
def fromInt(value: Int): Coords2D =
Coords2D(value % field.width, value / field.width)
}

implicit val directionBitSetKey: BitSetKey[CardinalDirection2D] =
new BitSetKey[CardinalDirection2D] {
def toInt(value: CardinalDirection2D): Int = value match {
case Direction2D.N => 0
case Direction2D.E => 1
case Direction2D.S => 2
case Direction2D.W => 3
}
def fromInt(value: Int): CardinalDirection2D = value match {
case 0 => Direction2D.N
case 1 => Direction2D.E
case 2 => Direction2D.S
case 3 => Direction2D.W
case _ => s"Invalid value: $value".fail
}
}

implicit val guardBitSetKey: BitSetKey[Guard] = new BitSetKey[Guard] {
def toInt(guard: Guard): Int =
guard.location.toInt * 4 + guard.direction.toInt

def fromInt(value: Int): Guard = {
val location = (value / 4).fromInt[Coords2D]
val direction = (value % 4).fromInt[CardinalDirection2D]
Guard(location, direction)
}
}

Simulation
.detectLoop(Guard(location, Direction2D.N)) { case (s, _) =>
.detectLoopUsingBitSet(Guard(location, Direction2D.N)) { case (s, _) =>
s.next(field).toRight(())
}
.isRight
}

def part2(data: Input): Int = {
val (location, field) = data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ object BitSetKeySyntax {
def toInt: Int = ev.toInt(value)
}

implicit class BitSetKeyOps2[T](value: Int)(implicit ev: BitSetKey[T]) {
def fromInt: T = ev.fromInt(value)
implicit class BitSetKeyOps2(value: Int) {
def fromInt[T](implicit ev: BitSetKey[T]): T = ev.fromInt(value)
}
}

Expand All @@ -48,9 +48,15 @@ final class MutableBitSet[T: BitSetKey](
predicate: T => Boolean
): Int =
underlying.count(x => predicate(x.fromInt))

def contains(value: T): Boolean =
underlying.contains(value.toInt)
}

object MutableBitSet {
def empty[T: BitSetKey]: MutableBitSet[T] =
new MutableBitSet[T]()

def apply[T: BitSetKey](values: T*): MutableBitSet[T] = {
val result = new MutableBitSet[T]()
values.foreach(result.add)
Expand Down
18 changes: 17 additions & 1 deletion scala2/src/main/scala/jurisk/utils/Simulation.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package jurisk.utils

import cats.implicits._
import jurisk.collections.mutable.BitSetKey
import jurisk.collections.mutable.MutableBitSet

import scala.annotation.tailrec
import scala.collection.mutable
Expand Down Expand Up @@ -115,7 +117,7 @@ object Simulation {
def detectLoop[State, Result](initial: State)(
f: (State, Counter) => Either[Result, State]
): Either[Result, (Counter, Counter)] = {
val alreadySeen: mutable.HashMap[State, Counter] = mutable.HashMap.empty
val alreadySeen: mutable.Map[State, Counter] = mutable.HashMap.empty
runWithIterationCount(initial) { case (state, iteration) =>
alreadySeen.get(state) match {
case Some(iterationWeSawThisBefore) =>
Expand All @@ -126,4 +128,18 @@ object Simulation {
}
}
}

def detectLoopUsingBitSet[State: BitSetKey, Result](initial: State)(
f: (State, Counter) => Either[Result, State]
): Either[Result, Counter] = {
val alreadySeen = MutableBitSet.empty[State]
runWithIterationCount(initial) { case (state, iteration) =>
if (alreadySeen.contains(state)) {
iteration.asRight.asLeft
} else {
alreadySeen.add(state)
f(state, iteration).leftMap(_.asLeft)
}
}
}
}

0 comments on commit 6bb7b27

Please sign in to comment.