mirror of
https://github.com/mx42/aoc2024.scala.git
synced 2026-01-14 05:49:51 +01:00
feat: add day 4
This commit is contained in:
@@ -5,6 +5,7 @@ import days._
|
||||
case 1 => Day1.solve()
|
||||
case 2 => Day2.solve()
|
||||
case 3 => Day3.solve()
|
||||
case 4 => Day4.solve()
|
||||
case _ => println(s"Day $dayNumber is not yet implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,116 @@
|
||||
package days
|
||||
|
||||
case class Pos(x: Int, y: Int) {
|
||||
def upLeft: Pos = Pos(x - 1, y - 1)
|
||||
def up: Pos = Pos(x, y - 1)
|
||||
def upRight: Pos = Pos(x + 1, y - 1)
|
||||
def left: Pos = Pos(x - 1, y)
|
||||
def right: Pos = Pos(x + 1, y)
|
||||
def downLeft: Pos = Pos(x - 1, y + 1)
|
||||
def down: Pos = Pos(x, y + 1)
|
||||
def downRight: Pos = Pos(x + 1, y + 1)
|
||||
|
||||
def cross: List[Pos] = List(
|
||||
this.upLeft,
|
||||
this.downRight,
|
||||
this.upRight,
|
||||
this.downLeft
|
||||
)
|
||||
|
||||
def inThreshold(geo: Pos): Boolean =
|
||||
x >= 0 && x < geo.x && y >= 0 && y < geo.y
|
||||
}
|
||||
|
||||
object Pos {
|
||||
def getNeighbors(): List[Pos => Pos] = List(
|
||||
_.upLeft,
|
||||
_.up,
|
||||
_.upRight,
|
||||
_.left,
|
||||
_.right,
|
||||
_.downLeft,
|
||||
_.down,
|
||||
_.downRight
|
||||
)
|
||||
}
|
||||
|
||||
object Day4 extends Day {
|
||||
val number: Int = 4;
|
||||
|
||||
def part1(input: String) = "pouet"
|
||||
def getPositions(p: Pos, geo: Pos, size: Int): List[List[Pos]] =
|
||||
// Get neighbors positions around a position (if matching the geometry)
|
||||
Pos
|
||||
// For each neighbor direction (up-left, up, up-right, etc)
|
||||
.getNeighbors()
|
||||
.map(f =>
|
||||
Iterator
|
||||
// Build an iterator going from [P] to the direction's neighbor [P]
|
||||
.iterate(p)(f)
|
||||
// Do it [size] time
|
||||
.take(size)
|
||||
// Drop positions getting outside the designed dimensions
|
||||
.filter(_.inThreshold(geo))
|
||||
.toList
|
||||
)
|
||||
// Only take the list of positions exactly matching the expected length
|
||||
.filter(_.length == size)
|
||||
|
||||
def part2(input: String) = "pouet"
|
||||
def getCross(p: Pos, geo: Pos): Option[List[Pos]] =
|
||||
// Get surrounding cross around a position (if matching the geometry)
|
||||
p.cross.filter(_.inThreshold(geo)) match {
|
||||
case l if l.length == 4 => Some(l)
|
||||
case _ => None
|
||||
}
|
||||
|
||||
def getString(lines: List[String])(ps: List[Pos]): String =
|
||||
// Convert list of positions to matching letters
|
||||
ps.map {
|
||||
case Pos(x, y) => {
|
||||
lines(y)(x)
|
||||
}
|
||||
}.mkString
|
||||
|
||||
def isCrossedMAS(s: String): Boolean =
|
||||
// Verify if a string is a crossed MAS
|
||||
s.length == 4
|
||||
&& s.forall("MS".contains)
|
||||
&& s(0) != s(1)
|
||||
&& s(2) != s(3)
|
||||
|
||||
// Verify if a string is a XMAS
|
||||
def isXMAS: String => Boolean = _ == "XMAS"
|
||||
|
||||
def part1(input: String) = {
|
||||
val lines: List[String] = input.linesIterator.toList
|
||||
val geom: Pos = Pos(lines(0).length, lines.length)
|
||||
lines.zipWithIndex
|
||||
.flatMap { case (s, y) =>
|
||||
s.iterator.zipWithIndex.toList
|
||||
.filter(_._1 == 'X')
|
||||
.flatMap { case (_, x) =>
|
||||
getPositions(Pos(x, y), geom, 4)
|
||||
.map(getString(lines))
|
||||
.filter(isXMAS)
|
||||
}
|
||||
}
|
||||
.length
|
||||
.toString
|
||||
}
|
||||
|
||||
def part2(input: String) = {
|
||||
val lines: List[String] = input.linesIterator.toList
|
||||
val geom: Pos = Pos(lines(0).length, lines.length)
|
||||
lines.zipWithIndex
|
||||
.flatMap { case (s, y) =>
|
||||
s.iterator.zipWithIndex.toList
|
||||
.filter(_._1 == 'A')
|
||||
.flatMap { case (_, x) =>
|
||||
getCross(Pos(x, y), geom)
|
||||
.map(getString(lines))
|
||||
.filter(isCrossedMAS)
|
||||
}
|
||||
}
|
||||
.length
|
||||
.toString
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user