112 lines
3.0 KiB
Scala
112 lines
3.0 KiB
Scala
package aoc.y2016
|
|
|
|
import aoc._
|
|
|
|
object Day01 extends Day {
|
|
|
|
import fastparse._, SingleLineWhitespace._
|
|
|
|
sealed trait Direction {
|
|
def score: (Int, Int)
|
|
}
|
|
case object MoveUp extends Direction {
|
|
override def score: (Int, Int) = (0, 1)
|
|
}
|
|
case object MoveDown extends Direction {
|
|
override def score: (Int, Int) = (0, -1)
|
|
}
|
|
case object MoveLeft extends Direction {
|
|
override def score: (Int, Int) = (-1, 0)
|
|
}
|
|
case object MoveRight extends Direction {
|
|
override def score: (Int, Int) = (1, 0)
|
|
}
|
|
case class State(currentDirection: Direction = MoveUp, distance: (Int, Int) = (0, 0))
|
|
sealed trait Turn {
|
|
def apply(d: Direction): Direction
|
|
}
|
|
case object TurnLeft extends Turn {
|
|
override def apply(d: Direction): Direction = d match {
|
|
case MoveUp => MoveLeft
|
|
case MoveLeft => MoveDown
|
|
case MoveDown => MoveRight
|
|
case MoveRight => MoveUp
|
|
}
|
|
}
|
|
case object TurnRight extends Turn {
|
|
override def apply(d: Direction): Direction = d match {
|
|
case MoveUp => MoveRight
|
|
case MoveRight => MoveDown
|
|
case MoveDown => MoveLeft
|
|
case MoveLeft => MoveUp
|
|
}
|
|
}
|
|
case class Move(t: Turn, l: Int)
|
|
|
|
val tMap = Map(
|
|
"L" -> TurnLeft,
|
|
"R" -> TurnRight
|
|
)
|
|
|
|
def timesParser[_: P]: P[Int] = P(CharIn("0-9").rep(1).!).map(_.toInt)
|
|
def directionParser[_: P]: P[Turn] = P(("L" | "R").!).map(tMap)
|
|
def moveParser[_: P]: P[Move] = P(directionParser ~ timesParser).map { case (t, l) => Move(t, l) }
|
|
def movesParser[_: P]: P[List[Move]] = P(moveParser.rep(1, ","./)).map(_.toList)
|
|
|
|
def getMoves(input: String): List[Move] = {
|
|
val Parsed.Success(moves, _) = parse(input, movesParser(_))
|
|
moves
|
|
}
|
|
|
|
def distance(s: State): Int = {
|
|
val (x, y) = s.distance
|
|
val (dx, dy) = (Math.abs(x), Math.abs(y))
|
|
dx + dy
|
|
}
|
|
|
|
override def part1(input: String): String = {
|
|
val moves = getMoves(input)
|
|
val endingState = moves.foldLeft(State())((s, m) => {
|
|
val nd = m.t(s.currentDirection)
|
|
val ns = nd.score * m.l
|
|
State(nd, s.distance + ns)
|
|
})
|
|
distance(endingState).toString
|
|
}
|
|
|
|
override def part2(input: String): String = {
|
|
val moves = getMoves(input)
|
|
def firstRepeat(
|
|
m: List[Move],
|
|
startingState: State = State(),
|
|
carryOutRotate: Boolean = true,
|
|
seen: List[(Int, Int)] = List()
|
|
): State = {
|
|
val thisMove = m.head
|
|
val nd = if (carryOutRotate) {
|
|
thisMove.t(startingState.currentDirection)
|
|
} else {
|
|
startingState.currentDirection
|
|
}
|
|
val ns = startingState.distance + nd.score
|
|
print(s"\r(${ns._1}, ${ns._2}) ")
|
|
val ss = State(nd, ns)
|
|
if (seen.contains(ns)) {
|
|
ss
|
|
} else {
|
|
val xw = thisMove.l == 1
|
|
val nm = if (xw) {
|
|
m.drop(1)
|
|
} else {
|
|
Move(thisMove.t, thisMove.l - 1) +: m.drop(1)
|
|
}
|
|
firstRepeat(nm, ss, xw, seen :+ ns)
|
|
}
|
|
}
|
|
val rs = firstRepeat(moves)
|
|
println()
|
|
distance(rs).toString
|
|
}
|
|
|
|
}
|