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 1af0dbb commit 588a279
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 24 deletions.
2 changes: 1 addition & 1 deletion rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ num-traits.workspace = true
num-derive.workspace = true
itertools.workspace = true
md5.workspace = true
bit-set.workspace = true
1 change: 0 additions & 1 deletion rust/y2024/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,3 @@ advent-of-code-common = { path = "../common" }
chumsky.workspace = true
itertools.workspace = true
regex.workspace = true
bit-set.workspace = true
9 changes: 5 additions & 4 deletions scala2/src/main/scala/jurisk/adventofcode/Advent00.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,20 @@ import org.scalatest.matchers.should.Matchers._

object Advent00 {
type Input = List[Command]
type N = Long

sealed trait Command extends Product with Serializable
object Command {
case object Noop extends Command
final case class Something(
values: List[Int]
values: List[N]
) extends Command
final case class Other(value: String) extends Command

def parse(s: String): Command =
s match {
case "noop" => Noop
case s"something $rem" => Something(rem.extractIntList)
case s"something $rem" => Something(rem.extractLongList)
case s if s.nonEmpty => Other(s)
case _ => s.failedToParse
}
Expand All @@ -29,10 +30,10 @@ object Advent00 {
def parse(input: String): Input =
input.parseLines(Command.parse)

def part1(data: Input): Int =
def part1(data: Input): N =
0

def part2(data: Input): Int =
def part2(data: Input): N =
0

def parseFile(fileName: String): Input =
Expand Down
40 changes: 22 additions & 18 deletions scala2/src/main/scala/jurisk/adventofcode/y2024/Advent06.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package jurisk.adventofcode.y2024
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.MutableBitSet
import jurisk.geometry.Coords2D
import jurisk.geometry.Direction2D
import jurisk.geometry.Direction2D.CardinalDirection2D
Expand All @@ -21,11 +23,6 @@ object Advent06 {

type Input = (Coords2D, Field2D[Block])

final private case class GuardWithVisitedLog(
guard: Guard,
visited: Set[Coords2D],
)

final private case class Guard(
location: Coords2D,
direction: CardinalDirection2D,
Expand Down Expand Up @@ -57,24 +54,30 @@ object Advent06 {
(location, field)
}

private def guardsPath(data: Input): Set[Coords2D] = {
// TODO: Try a BitSet instead of a Set?

private def guardsPath(data: Input): MutableBitSet[Coords2D] = {
val (location, field) = data
val state =
GuardWithVisitedLog(Guard(location, Direction2D.N), Set(location))

implicit val key: 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)
}

val visited = MutableBitSet[Coords2D](location)

val state = Guard(location, Direction2D.N)

Simulation.run(state) { s =>
s.guard.next(field) match {
s.next(field) match {
case Some(next) =>
s.copy(
guard = next,
visited = s.visited + next.location,
).asRight
visited.add(next.location)
next.asRight
case None =>
s.visited.asLeft
().asLeft
}
}

visited
}

def part1(data: Input): Int =
Expand All @@ -94,8 +97,9 @@ object Advent06 {
val (location, field) = data

guardsPath(data)
.filterNot(_ == location)
.count(c => wouldLoop(location, field.updatedAtUnsafe(c, Wall)))
.count(c =>
c != location && wouldLoop(location, field.updatedAtUnsafe(c, Wall))
)
}

def parseFile(fileName: String): Input =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package jurisk.collections.mutable

import jurisk.collections.mutable.BitSetKeySyntax.BitSetKeyOps1
import jurisk.collections.mutable.BitSetKeySyntax.BitSetKeyOps2

import scala.collection.mutable

trait BitSetKey[T] {
def toInt(value: T): Int
def fromInt(value: Int): T
}

object BitSetKeyInstances {
implicit val intBitSetKey: BitSetKey[Int] = new BitSetKey[Int] {
def toInt(value: Int): Int = value
def fromInt(value: Int): Int = value
}
}

object BitSetKeySyntax {
implicit class BitSetKeyOps1[T](value: T)(implicit ev: BitSetKey[T]) {
def toInt: Int = ev.toInt(value)
}

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

final class MutableBitSet[T: BitSetKey](
private val underlying: mutable.BitSet
) {
private def this() =
this(mutable.BitSet.empty)

def add(value: T): Boolean =
underlying.add(value.toInt)

def size: Int =
underlying.size

def filterNot(
predicate: T => Boolean
): MutableBitSet[T] =
new MutableBitSet(underlying.filterNot(x => predicate(x.fromInt)))

def count(
predicate: T => Boolean
): Int =
underlying.count(x => predicate(x.fromInt))
}

object MutableBitSet {
def apply[T: BitSetKey](values: T*): MutableBitSet[T] = {
val result = new MutableBitSet[T]()
values.foreach(result.add)
result
}
}

0 comments on commit 588a279

Please sign in to comment.