Skip to content

Commit

Permalink
Clean up 2023 day 18
Browse files Browse the repository at this point in the history
  • Loading branch information
sim642 committed Dec 18, 2023
1 parent 21c1140 commit 9c72fb7
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 55 deletions.
2 changes: 1 addition & 1 deletion src/main/scala/eu/sim642/adventofcode2023/Day10.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ object Day10 {
object PicksTheoremPart2Solution extends Part2Solution {
override def enclosedTiles(grid: Grid[Char]): Int = {
val loop = DFS.traverse(loopTraversal(grid)).nodeOrder
Geometry.polygonArea(loop) - loop.size / 2 + 1
Geometry.polygonArea(loop).toInt - loop.size / 2 + 1
}
}

Expand Down
75 changes: 29 additions & 46 deletions src/main/scala/eu/sim642/adventofcode2023/Day18.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,56 +19,39 @@ object Day18 {
'R' -> Pos(1, 0),
)

def digTrench(digPlan: DigPlan): Set[Pos] = {
digPlan.iterator
.flatMap(step => Iterator.fill(step.length)(step.direction))
.scanLeft(Pos.zero)((pos, direction) => pos + moveOffsets(direction))
.toSet
}

def digInterior(digPlan: DigPlan): Set[Pos] = {
val trench = digTrench(digPlan)

val graphTraversal = new GraphTraversal[Pos] with UnitNeighbors[Pos] {
override val startNode: Pos = Pos(1, 1)

override def unitNeighbors(pos: Pos): IterableOnce[Pos] = {
for {
offset <- Pos.axisOffsets
newPos = pos + offset
if !trench(newPos)
} yield newPos
}
trait Part {
def extractSteps(digPlan: DigPlan): Seq[(Char, Int)]

def lagoonSize(digPlan: DigPlan): Long = {
val steps = extractSteps(digPlan)
val vertices = steps.scanLeft(Pos.zero)({ case (pos, (direction, length)) =>
pos + length *: moveOffsets(direction)
})
val area = Geometry.polygonArea(vertices)
val boundary = steps.map(_._2.toLong).sum
val interior = area - boundary / 2 + 1 // Pick's theorem
boundary + interior
}

val interior = BFS.traverse(graphTraversal).nodes
trench ++ interior
}

def lagoonSize(digPlan: DigPlan): Int = digInterior(digPlan).size
object Part1 extends Part {
override def extractSteps(digPlan: DigPlan): Seq[(Char, Int)] =
digPlan.map(step => (step.direction, step.length))
}

def parseColor(color: String): (Char, Int) = {
val direction = color.last match {
case '0' => 'R'
case '1' => 'D'
case '2' => 'L'
case '3' => 'U'
object Part2 extends Part {
def parseColor(color: String): (Char, Int) = {
val direction = color.last match {
case '0' => 'R'
case '1' => 'D'
case '2' => 'L'
case '3' => 'U'
}
(direction, color.take(5).toIntRadix(16))
}
(direction, color.take(5).toIntRadix(16))
}

def lagoonSize2(digPlan: DigPlan): Long = {
val plan2 = digPlan
.map(step => parseColor(step.color))
val points = plan2
.scanLeft(Pos.zero)({ case (pos, (direction, length)) => pos + length *: moveOffsets(direction) })
//Geometry.polygonArea(points)
val area = (points.iterator
.zipWithTail
.map((p, q) => p.x.toLong * q.y - q.x.toLong * p.y)
.sum / 2).abs
val perim = plan2.map(_._2.toLong).sum
area + perim / 2 + 1
override def extractSteps(digPlan: DigPlan): Seq[(Char, Int)] =
digPlan.map(step => parseColor(step.color))
}


Expand All @@ -82,7 +65,7 @@ object Day18 {
lazy val input: String = scala.io.Source.fromInputStream(getClass.getResourceAsStream("day18.txt")).mkString.trim

def main(args: Array[String]): Unit = {
println(lagoonSize(parseDigPlan(input)))
println(lagoonSize2(parseDigPlan(input)))
println(Part1.lagoonSize(parseDigPlan(input)))
println(Part2.lagoonSize(parseDigPlan(input)))
}
}
2 changes: 1 addition & 1 deletion src/main/scala/eu/sim642/adventofcodelib/Geometry.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ object Geometry {
* Calculates the area of a simple polygon using the shoelace formula.
* @see [[https://en.wikipedia.org/wiki/Shoelace_formula]]
*/
def polygonArea(poss: collection.Seq[Pos]): Int = {
def polygonArea(poss: collection.Seq[Pos]): Long = { // TODO: generalize return type
((poss.last +: poss).iterator
.zipWithTail
.map(_ cross _)
Expand Down
4 changes: 2 additions & 2 deletions src/main/scala/eu/sim642/adventofcodelib/pos/Pos.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ case class Pos(x: Int, y: Int) extends BoxPosOps[Pos] {
override def max(that: Pos): Pos =
Pos(x max that.x, y max that.y)

def cross(that: Pos): Int =
x * that.y - that.x * y
def cross(that: Pos): Long =
x.toLong * that.y - that.x * y.toLong
}

object Pos extends PosFactory[Pos] {
Expand Down
10 changes: 5 additions & 5 deletions src/test/scala/eu/sim642/adventofcode2023/Day18Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@ class Day18Test extends AnyFunSuite {
|U 2 (#7a21e3)""".stripMargin

test("Part 1 examples") {
assert(lagoonSize(parseDigPlan(exampleInput)) == 62)
assert(Part1.lagoonSize(parseDigPlan(exampleInput)) == 62)
}

test("Part 1 input answer") {
assert(lagoonSize(parseDigPlan(input)) == 70026)
assert(Part1.lagoonSize(parseDigPlan(input)) == 70026)
}

test("Part 2 examples") {
assert(parseColor("70c710") == ('R', 461937))
assert(lagoonSize2(parseDigPlan(exampleInput)) == 952408144115L)
assert(Part2.parseColor("70c710") == ('R', 461937))
assert(Part2.lagoonSize(parseDigPlan(exampleInput)) == 952408144115L)
}

test("Part 2 input answer") {
assert(lagoonSize2(parseDigPlan(input)) == 68548301037382L)
assert(Part2.lagoonSize(parseDigPlan(input)) == 68548301037382L)
}
}

0 comments on commit 9c72fb7

Please sign in to comment.