90 lines
2.2 KiB
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
|
|
}
|
|
|
|
}
|