diff --git a/README.md b/README.md index b6b7737..6ae39f7 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ This repo contains my attempt at this year's Advent of Code (2023) I will try and do some problems (probably not all of them) in Scala ## Progress: -#### Stars: 25 / 50 -| Mon | Tue | Wed | Thu | Fri | Sat | Sun | -|:------------------:|:-----------------:|:------------------:|:-----------------:|:-----------------:|:-----------------:|:------------------:| -| | | | | 1
:star::star: | 2
:star::star: | 3
:star::star: | -| 4
:star::star: | 5
:star::star: | 6
:star::star: | 7
:star::star: | 8
:star::star: | 9
:star::star: | 10
:star::star: | -| 11
:star::star: | 12 | 13
:star::star: | 14
:star: | 15 | 16 | 17 | -| 18 | 19 | 20 | 21 | 22 | 23 | 24 | -| 25 | | | | | | | \ No newline at end of file +#### Stars: 26 / 50 +| Mon | Tue | Wed | Thu | Fri | Sat | Sun | +|:------------------:|:-----------------:|:------------------:|:------------------:|:-----------------:|:-----------------:|:------------------:| +| | | | | 1
:star::star: | 2
:star::star: | 3
:star::star: | +| 4
:star::star: | 5
:star::star: | 6
:star::star: | 7
:star::star: | 8
:star::star: | 9
:star::star: | 10
:star::star: | +| 11
:star::star: | 12 | 13
:star::star: | 14
:star::star: | 15 | 16 | 17 | +| 18 | 19 | 20 | 21 | 22 | 23 | 24 | +| 25 | | | | | | | \ No newline at end of file diff --git a/src/day14/Puzzle2.scala b/src/day14/Puzzle2.scala new file mode 100644 index 0000000..3e838ec --- /dev/null +++ b/src/day14/Puzzle2.scala @@ -0,0 +1,153 @@ +package day14 + +import scala.collection.mutable.ArrayBuffer +import scala.io.{BufferedSource, Source} + +object Puzzle2 { + val CHARS: Array[Char] = Array('.', 'O', '#') + var platform: Array[Array[Int]] = Array.empty + var prevPlatform: Array[Array[Int]] = Array.empty + var history: ArrayBuffer[Array[Array[Int]]] = new ArrayBuffer() + var width: Int = 0 + var height: Int = 0 + + def loadInput(path: String): Unit = { + val source: BufferedSource = Source.fromFile(path) + val lines: Array[String] = source.getLines().toArray + + platform = lines.map(_.map(CHARS.indexOf(_)).toArray) + height = platform.length + width = if (height == 0) 0 else platform(0).length + prevPlatform = Array.ofDim(height, width) + + source.close() + } + + def slideUp(): Unit = { + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + if (platform(y)(x) == 1) { + slideRockUp(x, y) + } + } + } + } + + def slideRockUp(x: Int, y: Int): Unit = { + platform(y)(x) = 0 + for (y2: Int <- y-1 to 0 by -1) { + if (platform(y2)(x) != 0) { + platform(y2+1)(x) = 1 + return + } + } + platform(0)(x) = 1 + } + + def rotate(): Unit = { + val result: Array[Array[Int]] = Array.ofDim(width, height) + width += height + height = width - height + width = width - height + + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + result(y)(x) = platform(width-x-1)(y) + } + } + platform = result + } + + def cycle(): Unit = { + slideUp() + rotate() + slideUp() + rotate() + slideUp() + rotate() + slideUp() + rotate() + } + + def copyPlatform(): Array[Array[Int]] = { + val result: Array[Array[Int]] = Array.ofDim(height, width) + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + result(y)(x) = platform(y)(x) + } + } + return result + } + + def computeLoad(): Int = { + var load: Int = 0 + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + if (platform(y)(x) == 1) { + load += height-y + } + } + } + return load + } + + def getLoopStart(): Int = { + for ((prevPlatform: Array[Array[Int]], i: Int) <- history.zipWithIndex) { + if (noChange(prevPlatform)) return i + } + return -1 + } + + def noChange(prevPlatform: Array[Array[Int]]): Boolean = { + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + if (prevPlatform(y)(x) != platform(y)(x)) { + return false + } + } + } + return true + } + + def hasLooped(): Boolean = getLoopStart() != -1 + + def repeatCycle(count: Int): Unit = { + for (i: Int <- 0 until count) { + history.prepend(copyPlatform()) + cycle() + //display() + if (hasLooped()) { + val loopStart: Int = getLoopStart() + val loopOffset: Int = (count - i - 1) % (loopStart + 1) + val finalI: Int = loopStart - loopOffset + + platform = history(finalI) + return + } + } + } + + def display(): Unit = { + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + print(CHARS(platform(y)(x))) + } + println() + } + println() + } + + def solve(path: String, cycles: Int): Int = { + loadInput(path) + repeatCycle(cycles) + + val solution: Int = computeLoad() + + return solution + } + + def main(args: Array[String]): Unit = { + val solution: Int = solve("./res/day14/input1.txt", 1000000000) + println(solution) + } +} diff --git a/tests/day14/Puzzle2Test.scala b/tests/day14/Puzzle2Test.scala new file mode 100644 index 0000000..ce4a076 --- /dev/null +++ b/tests/day14/Puzzle2Test.scala @@ -0,0 +1,9 @@ +package day14 + +import org.scalatest.funsuite.AnyFunSuite + +class Puzzle2Test extends AnyFunSuite { + test("Puzzle2.solve") { + assert(Puzzle2.solve("tests_res/day14/input1.txt", 1000000000) == 64) + } +}