Skip to content

Commit

Permalink
✨ day 4
Browse files Browse the repository at this point in the history
  • Loading branch information
twentylemon committed Dec 4, 2024
1 parent c2fdec9 commit c366a5b
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 1 deletion.
Binary file added src/main/resources/year2024/day04.txt
Binary file not shown.
16 changes: 16 additions & 0 deletions src/main/scala/org/lemon/advent/lib/2d/Area.scala
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,22 @@ case class Area(xRange: Range, yRange: Range):
def topRow: Iterator[Coord] = row(top)
def bottomRow: Iterator[Coord] = row(bottom)

def upDiagonal(startAt: Coord): Iterator[Coord] =
assert(contains(startAt), s"$this does not contain startAt $startAt")
Iterator.iterate(startAt)(_.up.right).takeWhile(contains)

def downDiagonal(startAt: Coord): Iterator[Coord] =
assert(contains(startAt), s"$this does not contain startAt $startAt")
Iterator.iterate(startAt)(_.down.right).takeWhile(contains)

def rows: Iterator[Iterator[Coord]] = yRange.iterator.map(row)
def cols: Iterator[Iterator[Coord]] = xRange.iterator.map(col)
def upDiagonals: Iterator[Iterator[Coord]] =
xRange.iterator.map(x => 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

Expand Down
5 changes: 4 additions & 1 deletion src/main/scala/org/lemon/advent/lib/2d/Coord.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
Expand Down
34 changes: 34 additions & 0 deletions src/main/scala/org/lemon/advent/year2024/Day04.scala
Original file line number Diff line number Diff line change
@@ -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
42 changes: 42 additions & 0 deletions src/test/scala/org/lemon/advent/year2024/Day04Test.scala
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit c366a5b

Please sign in to comment.