aoc-old/aoc/src/main/scala/aoc/y2017/Day11.scala

90 lines
2.2 KiB
Scala

package aoc.y2017
import aoc._
object Day11 extends Day {
import fastparse._, NoWhitespace._
sealed trait Direction {
def points: (Int, Int)
}
case object North extends Direction {
override def points: (Int, Int) = (0, 2)
}
case object NorthWest extends Direction {
override def points: (Int, Int) = (-1, 1)
}
case object NorthEast extends Direction {
override def points: (Int, Int) = (1, 1)
}
case object South extends Direction {
override def points: (Int, Int) = (0, -2)
}
case object SouthWest extends Direction {
override def points: (Int, Int) = (-1, -1)
}
case object SouthEast extends Direction {
override def points: (Int, Int) = (1, -1)
}
val strMap = Map(
"n" -> North,
"s" -> South,
"ne" -> NorthEast,
"nw" -> NorthWest,
"se" -> SouthEast,
"sw" -> SouthWest
)
def directionParser[_: P]: P[Direction] = P("ne" | "nw" | "se" | "sw" | "n" | "s").!.map(strMap)
def directionsParser[_: P]: P[List[Direction]] = P(directionParser.rep(1, ","./)).map(_.toList)
implicit class DirectionListOps(l: List[Direction]) {
def total: (Int, Int) = {
l.map(_.points).reduce(_ + _)
}
}
def getDirections(input: String): List[Direction] = {
val Parsed.Success(list, _) = parse(input, directionsParser(_))
list
}
def getDistance(directions: List[Direction]): Int = {
val (tx, ty) = directions.total
val dx = Math.abs(tx)
val dy = Math.abs(ty)
Math.abs(dy - dx) match {
case diag if dy > dx =>
val remaining = dy - diag
(diag / 2) + remaining
case _ if dx >= dy =>
dx
}
}
override def part1(input: String): String = {
val directions = getDirections(input)
val td = getDistance(directions)
td.toString
}
override def part2(input: String): String = {
val directions = getDirections(input)
def findFurthest(directions: List[Direction], step: Int = 1, max: Int = 0): Int = {
if (step > directions.length) {
max
} else {
val mds = directions.take(step)
val md = getDistance(mds)
findFurthest(directions, step + 1, Math.max(max, md))
}
}
findFurthest(directions).toString
}
}