From 56b7f06e770247c55f060674d4d888ac201a597c Mon Sep 17 00:00:00 2001 From: LordBaryhobal Date: Sat, 16 Dec 2023 21:48:32 +0100 Subject: [PATCH] day 16 puzzle 2 --- README.md | 16 ++-- src/day16/Puzzle2.scala | 136 ++++++++++++++++++++++++++++++++++ tests/day16/Puzzle2Test.scala | 9 +++ 3 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 src/day16/Puzzle2.scala create mode 100644 tests/day16/Puzzle2Test.scala diff --git a/README.md b/README.md index 2c7fb27..7b78d1b 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: 29 / 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
:star::star: | 16
:star: | 17 | -| 18 | 19 | 20 | 21 | 22 | 23 | 24 | -| 25 | | | | | | | \ No newline at end of file +#### Stars: 30 / 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
:star::star: | 16
:star::star: | 17 | +| 18 | 19 | 20 | 21 | 22 | 23 | 24 | +| 25 | | | | | | | \ No newline at end of file diff --git a/src/day16/Puzzle2.scala b/src/day16/Puzzle2.scala new file mode 100644 index 0000000..bbbab86 --- /dev/null +++ b/src/day16/Puzzle2.scala @@ -0,0 +1,136 @@ +package day16 + +import day16.Mirrors.{DIAGONAL_BL_TR, DIAGONAL_TL_BR, Mirror, NONE, SPLITTER_HOR, SPLITTER_VER} + +import scala.collection.mutable.ArrayBuffer +import scala.io.{BufferedSource, Source} + +object Puzzle2 { + var mirrors: Array[Array[Mirror]] = Array.empty + var energized: Array[Array[Boolean]] = Array.empty + var width: Int = 0 + var height: Int = 0 + val OFFSETS: Array[(Int, Int)] = Array( + (1, 0), (0, 1), (-1, 0), (0, -1) + ) + var path: ArrayBuffer[(Int, Int, Int)] = new ArrayBuffer() + + def loadInput(path: String): Unit = { + val source: BufferedSource = Source.fromFile(path) + val lines: Array[String] = source.getLines().toArray + + height = lines.length + width = if (height == 0) 0 else lines(0).length + mirrors = Array.ofDim(height, width) + + for ((line: String, y: Int) <- lines.zipWithIndex) { + for ((c: Char, x: Int) <- line.zipWithIndex) { + val mirror: Mirror = Mirrors.withName(""+c) + mirrors(y)(x) = mirror + } + } + + source.close() + } + + def shootBeam(startX: Int, startY: Int, startDir: Int): Unit = { + if (startX < 0 || startX >= width || startY < 0 || startY >= height) return + var x: Int = startX + var y: Int = startY + var dir: Int = startDir + var continue: Boolean = true + do { + if (path.contains((x, y, dir))) return + path.addOne((x, y, dir)) + + energized(y)(x) = true + + mirrors(y)(x) match { + case NONE => {} + case DIAGONAL_TL_BR => { + dir = Math.floorDiv(dir, 2)*2 + 1 - (dir % 2) + } + case DIAGONAL_BL_TR => { + dir = 3 - dir + } + case SPLITTER_HOR => { + if (dir % 2 == 1) { + continue = false + shootBeam(x+1, y, 0) + shootBeam(x-1, y, 2) + } + } + case SPLITTER_VER => { + if (dir % 2 == 0) { + continue = false + shootBeam(x, y+1, 1) + shootBeam(x, y-1, 3) + } + } + } + + if (continue) { + val offset: (Int, Int) = OFFSETS(dir) + x += offset._1 + y += offset._2 + } + + if (x < 0 || x >= width) continue = false + if (y < 0 || y >= height) continue = false + } while (continue) + } + + def countEnergized(): Int = { + var count: Int = 0 + for (y: Int <- 0 until height) { + for (x: Int <- 0 until width) { + if (energized(y)(x)) count += 1 + } + } + return count + } + + def clearEnergized(): Unit = { + energized = Array.ofDim(height, width) + path.clear() + } + + def solve(path: String): Int = { + loadInput(path) + + var solution: Int = 0 + val totalSteps: Int = (width + height)*2 + + for (y: Int <- 0 until height) { + print(f"\r${2.0*y/totalSteps*100}%.2f%%") + clearEnergized() + shootBeam(0, y, 0) + solution = Math.max(solution, countEnergized()) + + print(f"\r${(2.0*y+1)/totalSteps*100}%.2f%%") + clearEnergized() + shootBeam(width-1, y, 1) + solution = Math.max(solution, countEnergized()) + } + + for (x: Int <- 0 until width) { + print(f"\r${(2.0*x+height*2)/totalSteps*100}%.2f%%") + clearEnergized() + shootBeam(x, 0, 1) + solution = Math.max(solution, countEnergized()) + + print(f"\r${(2.0*x+height*2+1)/totalSteps*100}%.2f%%") + clearEnergized() + shootBeam(x, height-1, 3) + solution = Math.max(solution, countEnergized()) + } + println("100%") + + return solution + } + + def main(args: Array[String]): Unit = { + val solution: Int = solve("./res/day16/input1.txt") + println(solution) + } +} diff --git a/tests/day16/Puzzle2Test.scala b/tests/day16/Puzzle2Test.scala new file mode 100644 index 0000000..a9decb1 --- /dev/null +++ b/tests/day16/Puzzle2Test.scala @@ -0,0 +1,9 @@ +package day16 + +import org.scalatest.funsuite.AnyFunSuite + +class Puzzle2Test extends AnyFunSuite { + test("Puzzle2.solve") { + assert(Puzzle2.solve("tests_res/day16/input1.txt") == 51) + } +}