123 lines
2.9 KiB
Scala
123 lines
2.9 KiB
Scala
package aoc
|
|
package day14
|
|
|
|
import scala.annotation.tailrec
|
|
import scala.collection.mutable
|
|
|
|
val dayNumber = "14"
|
|
|
|
@main def part1: Unit =
|
|
println(part1(loadInput(dayNumber)))
|
|
|
|
@main def part2: Unit =
|
|
println(part2(loadInput(dayNumber)))
|
|
|
|
def part1(input: String): String =
|
|
val lines = input.split('\n')
|
|
val border = lines.head.map(_ => '#').mkString + "##"
|
|
val grid = lines
|
|
.map(l => s"#$l#")
|
|
.prepended(border)
|
|
.appended(border)
|
|
.map(_.to(mutable.ArraySeq))
|
|
for
|
|
y <- grid.indices
|
|
x <- grid.head.indices
|
|
do
|
|
if grid(y)(x) != 'O' then ()
|
|
else
|
|
(y - 1 to (0, -1))
|
|
.takeWhile(grid(_)(x) == '.')
|
|
.lastOption
|
|
.foreach(newY =>
|
|
grid(y)(x) = '.'
|
|
grid(newY)(x) = 'O'
|
|
)
|
|
|
|
grid
|
|
.map(_.count(_ == 'O'))
|
|
.reverse
|
|
.zipWithIndex
|
|
.map((count, row) => count * row)
|
|
.sum
|
|
.toString
|
|
|
|
def part2(input: String): String =
|
|
val lines = input.split('\n')
|
|
val border = lines.head.map(_ => '#').mkString + "##"
|
|
val grid = lines
|
|
.map(l => s"#$l#")
|
|
.prepended(border)
|
|
.appended(border)
|
|
.map(_.to(mutable.ArraySeq))
|
|
|
|
val coords =
|
|
for
|
|
y <- grid.indices
|
|
x <- grid.head.indices
|
|
yield (x, y)
|
|
|
|
enum Directions(
|
|
val coordinates: Seq[(Int, Int)],
|
|
val rangeToEdge: (Int, Int) => Seq[(Int, Int)]
|
|
):
|
|
case North
|
|
extends Directions(
|
|
coords,
|
|
(x, y) => (y - 1 to (0, -1)).map((x, _))
|
|
)
|
|
case West
|
|
extends Directions(
|
|
coords.sortBy(_._1),
|
|
(x, y) => (x - 1 to (0, -1)).map((_, y))
|
|
)
|
|
case South
|
|
extends Directions(
|
|
coords.reverse,
|
|
(x, y) => (y + 1 until grid.length).map((x, _))
|
|
)
|
|
case East
|
|
extends Directions(
|
|
coords.sortBy(_._1).reverse,
|
|
(x, y) => (x + 1 until grid.length).map((_, y))
|
|
)
|
|
|
|
def cycle =
|
|
for d <- Directions.values do
|
|
for (x, y) <- d.coordinates do
|
|
if grid(y)(x) != 'O' then ()
|
|
else
|
|
d.rangeToEdge(x, y)
|
|
.takeWhile((xR, yR) => grid(yR)(xR) == '.')
|
|
.lastOption
|
|
.foreach((xR, yR) =>
|
|
grid(y)(x) = '.'
|
|
grid(yR)(xR) = 'O'
|
|
)
|
|
|
|
def cycleUntilRepeat: (Int, Int) =
|
|
val seen = mutable.Map.empty[String, Int]
|
|
|
|
@tailrec def aux(iter: Int): (Int, Int) =
|
|
cycle
|
|
val gridString = grid.map(_.mkString).mkString("\n")
|
|
seen.get(gridString) match
|
|
case Some(prevIterations) => (iter, iter - prevIterations)
|
|
case None =>
|
|
seen.put(gridString, iter)
|
|
aux(iter + 1)
|
|
|
|
aux(1)
|
|
|
|
val (repeatedIndex, repeatedLength) = cycleUntilRepeat
|
|
val cyclesLeft = (1_000_000_000 - repeatedIndex) % repeatedLength
|
|
|
|
for _ <- (0 until cyclesLeft) do cycle
|
|
|
|
grid
|
|
.map(_.count(_ == 'O'))
|
|
.reverse
|
|
.zipWithIndex
|
|
.map((count, row) => count * (row))
|
|
.sum
|
|
.toString
|