From c366a5b8bdebf3705c4f56e78d43a6978c331ba4 Mon Sep 17 00:00:00 2001 From: Taras Mychaskiw Date: Wed, 4 Dec 2024 10:37:27 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20day=204?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/year2024/day04.txt | Bin 0 -> 19762 bytes .../scala/org/lemon/advent/lib/2d/Area.scala | 16 +++++++ .../scala/org/lemon/advent/lib/2d/Coord.scala | 5 ++- .../org/lemon/advent/year2024/Day04.scala | 34 ++++++++++++++ .../org/lemon/advent/year2024/Day04Test.scala | 42 ++++++++++++++++++ 5 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/year2024/day04.txt create mode 100644 src/main/scala/org/lemon/advent/year2024/Day04.scala create mode 100644 src/test/scala/org/lemon/advent/year2024/Day04Test.scala diff --git a/src/main/resources/year2024/day04.txt b/src/main/resources/year2024/day04.txt new file mode 100644 index 0000000000000000000000000000000000000000..74af9ad45894bcc11082bb04c673fa302a92242b GIT binary patch literal 19762 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 upDiagonal((x, bottom))) ++ yRange.reverseIterator.drop(1).map(y => upDiagonal((left, y))) + def downDiagonals: Iterator[Iterator[Coord]] = + xRange.iterator.map(x => downDiagonal((x, top))) ++ yRange.iterator.drop(1).map(y => downDiagonal((left, y))) + def diagonals: Iterator[Iterator[Coord]] = upDiagonals ++ downDiagonals + def encloses(area: Area): Boolean = left <= area.left && right >= area.right && top <= area.top && bottom >= area.bottom diff --git a/src/main/scala/org/lemon/advent/lib/2d/Coord.scala b/src/main/scala/org/lemon/advent/lib/2d/Coord.scala index a4a8899..b7c4df7 100644 --- a/src/main/scala/org/lemon/advent/lib/2d/Coord.scala +++ b/src/main/scala/org/lemon/advent/lib/2d/Coord.scala @@ -19,7 +19,10 @@ object Coord: def hasCoord(coord: Coord): Boolean = seq.indices.contains(coord.row) && seq(coord.row).indices.contains(coord.col) - + + extension (seq: Seq[String]) + def apply(coord: Coord): Char = seq(coord.row)(coord.col) + extension [V](grid: Map[Coord, V]) def toGridAdjacencyList: UnitGraph[Coord] = grid.map((coord, _) => (coord, coord.adjacent.filter(grid.contains))) diff --git a/src/main/scala/org/lemon/advent/year2024/Day04.scala b/src/main/scala/org/lemon/advent/year2024/Day04.scala new file mode 100644 index 0000000..f35f06e --- /dev/null +++ b/src/main/scala/org/lemon/advent/year2024/Day04.scala @@ -0,0 +1,34 @@ +package org.lemon.advent.year2024 + +import org.lemon.advent.lib.`2d`._ + +private object Day04: + + def phrase(wordsearch: Seq[String], coords: Seq[Coord]) = coords.map(wordsearch(_)).mkString + + def part1(input: String) = + val lines = input.linesIterator.toSeq + val area = Area(lines) + + (area.rows ++ area.cols ++ area.diagonals) + .map( + _.sliding(4) + .map(phrase(lines, _)) + .count(s => s == "XMAS" || s == "XMAS".reverse) + ) + .sum + + def part2(input: String) = + val lines = input.linesIterator.toSeq + val area = Area(lines) + val mas = Set("MAS", "MAS".reverse) + + area.upDiagonals + .map( + _.sliding(3) + .map(coords => (coords.head, phrase(lines, coords))) + .filter((_, s) => mas.contains(s)) + .filter((start, _) => mas.contains(phrase(lines, area.downDiagonal(start.up.up).take(3).toSeq))) + .size + ) + .sum diff --git a/src/test/scala/org/lemon/advent/year2024/Day04Test.scala b/src/test/scala/org/lemon/advent/year2024/Day04Test.scala new file mode 100644 index 0000000..3f562f1 --- /dev/null +++ b/src/test/scala/org/lemon/advent/year2024/Day04Test.scala @@ -0,0 +1,42 @@ +package org.lemon.advent.year2024 + +import org.lemon.advent._ +import org.lemon.advent.year2024.Day04._ + +class Day04Test extends UnitTest: + + test("part 1 example") { + val in = """|MMMSXXMASM + |MSAMXMSMSA + |AMXSXMAAMM + |MSAMASMSMX + |XMASAMXAMM + |XXAMMXXAMA + |SMSMSASXSS + |SAXAMASAAA + |MAMMMXMMMM + |MXMXAXMASX""".stripMargin + part1(in) shouldBe 18 + } + + test("part 1") { + part1(read(file(2024)(4))) shouldBe 2514 + } + + test("part 2 example") { + val in = """|MMMSXXMASM + |MSAMXMSMSA + |AMXSXMAAMM + |MSAMASMSMX + |XMASAMXAMM + |XXAMMXXAMA + |SMSMSASXSS + |SAXAMASAAA + |MAMMMXMMMM + |MXMXAXMASX""".stripMargin + part2(in) shouldBe 9 + } + + test("part 2") { + part2(read(file(2024)(4))) shouldBe 1888 + }