Skip to content

Commit

Permalink
Deduplicate 2023 day 17
Browse files Browse the repository at this point in the history
  • Loading branch information
sim642 committed Dec 17, 2023
1 parent 61986c0 commit 8e5a029
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 48 deletions.
79 changes: 36 additions & 43 deletions src/main/scala/eu/sim642/adventofcode2023/Day17.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,55 @@ package eu.sim642.adventofcode2023
import eu.sim642.adventofcode2018.Day13.DirectionPos
import eu.sim642.adventofcodelib.Grid
import eu.sim642.adventofcodelib.GridImplicits.*
import eu.sim642.adventofcodelib.graph.{BFS, Dijkstra, GraphSearch, GraphTraversal, UnitNeighbors}
import eu.sim642.adventofcodelib.graph.*
import eu.sim642.adventofcodelib.pos.Pos

object Day17 {

case class Crucible(pos: Pos, direction: Pos, directionCount: Int)

def leastHeatLoss(grid: Grid[Int]): Int = {

val graphSearch = new GraphSearch[Crucible] {
override val startNode: Crucible = Crucible(Pos.zero, Pos.zero, 0)

override def neighbors(crucible: Crucible): IterableOnce[(Crucible, Int)] = {
val Crucible(pos, direction, directionCount) = crucible
for {
offset <- Pos.axisOffsets
if offset != -direction
if !(directionCount == 3 && offset == direction)
newPos = pos + offset
if grid.containsPos(newPos)
newDirectionCount = if (offset == direction) directionCount + 1 else 1
} yield Crucible(newPos, offset, newDirectionCount) -> grid(newPos)
}
trait Part {
protected def canMove(crucible: Crucible, offset: Pos): Boolean
protected def canStop(crucible: Crucible): Boolean = true

private val targetPos = Pos(grid(0).size - 1, grid.size - 1)
def leastHeatLoss(grid: Grid[Int]): Int = {

override def isTargetNode(crucible: Crucible, dist: Int): Boolean = crucible.pos == targetPos
}
val graphSearch = new GraphSearch[Crucible] {
override val startNode: Crucible = Crucible(Pos.zero, Pos.zero, 0)

Dijkstra.search(graphSearch).target.get._2
}
override def neighbors(crucible: Crucible): IterableOnce[(Crucible, Int)] = {
val Crucible(pos, direction, directionCount) = crucible
for {
offset <- Pos.axisOffsets
if offset != -direction
if canMove(crucible, offset)
newPos = pos + offset
if grid.containsPos(newPos)
newDirectionCount = if (offset == direction) directionCount + 1 else 1
} yield Crucible(newPos, offset, newDirectionCount) -> grid(newPos)
}

private val targetPos = Pos(grid(0).size - 1, grid.size - 1)

// TODO: deduplicate
def leastHeatLossUltra(grid: Grid[Int]): Int = {

val graphSearch = new GraphSearch[Crucible] {
override val startNode: Crucible = Crucible(Pos.zero, Pos.zero, 0)

override def neighbors(crucible: Crucible): IterableOnce[(Crucible, Int)] = {
val Crucible(pos, direction, directionCount) = crucible
for {
offset <- Pos.axisOffsets
if offset != -direction
if direction == Pos.zero || (offset == direction && directionCount < 10) || (offset != direction && directionCount >= 4)
newPos = pos + offset
if grid.containsPos(newPos)
newDirectionCount = if (offset == direction) directionCount + 1 else 1
} yield Crucible(newPos, offset, newDirectionCount) -> grid(newPos)
override def isTargetNode(crucible: Crucible, dist: Int): Boolean = crucible.pos == targetPos && canStop(crucible)
}

private val targetPos = Pos(grid(0).size - 1, grid.size - 1)
Dijkstra.search(graphSearch).target.get._2
}
}

object Part1 extends Part {
override protected def canMove(crucible: Crucible, offset: Pos): Boolean =
crucible.directionCount < 3 || offset != crucible.direction
}

override def isTargetNode(crucible: Crucible, dist: Int): Boolean = crucible.pos == targetPos && crucible.directionCount >= 4
object Part2 extends Part {
override protected def canMove(crucible: Crucible, offset: Pos): Boolean = {
val Crucible(pos, direction, directionCount) = crucible
direction == Pos.zero || (offset == direction && directionCount < 10) || (offset != direction && directionCount >= 4)
}

Dijkstra.search(graphSearch).target.get._2
override protected def canStop(crucible: Crucible): Boolean = crucible.directionCount >= 4
}


Expand All @@ -67,7 +60,7 @@ object Day17 {
lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day17.txt")).mkString.trim

def main(args: Array[String]): Unit = {
println(leastHeatLoss(parseGrid(input)))
println(leastHeatLossUltra(parseGrid(input)))
println(Part1.leastHeatLoss(parseGrid(input)))
println(Part2.leastHeatLoss(parseGrid(input)))
}
}
10 changes: 5 additions & 5 deletions src/test/scala/eu/sim642/adventofcode2023/Day17Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ class Day17Test extends AnyFunSuite {
|999999999991""".stripMargin

test("Part 1 examples") {
assert(leastHeatLoss(parseGrid(exampleInput)) == 102)
assert(Part1.leastHeatLoss(parseGrid(exampleInput)) == 102)
}

test("Part 1 input answer") {
assert(leastHeatLoss(parseGrid(input)) == 1110)
assert(Part1.leastHeatLoss(parseGrid(input)) == 1110)
}

test("Part 2 examples") {
assert(leastHeatLossUltra(parseGrid(exampleInput)) == 94)
assert(leastHeatLossUltra(parseGrid(exampleInput2)) == 71)
assert(Part2.leastHeatLoss(parseGrid(exampleInput)) == 94)
assert(Part2.leastHeatLoss(parseGrid(exampleInput2)) == 71)
}

test("Part 2 input answer") {
assert(leastHeatLossUltra(parseGrid(input)) == 1294)
assert(Part2.leastHeatLoss(parseGrid(input)) == 1294)
}
}

0 comments on commit 8e5a029

Please sign in to comment.