Commit eff6e7ff authored by Alexander Gehrke's avatar Alexander Gehrke
Browse files

[day12] solution

parent 4ba6b81a
package aoc2020
import aoc2020.lib._
import Vectors._
type Pos = Vec2D[Int]
def day12(input: List[String]): String =
val directions = input.map(s => (s(0), s.substr(1).toInt))
val finalPos1 = moveShip(directions)
val part1 = s"Final position: ${finalPos1.pos}, facing ${finalPos1.dir.str}\nManhattan: ${finalPos1.pos.manhattan}"
val finalPos2 = moveWaypoint(directions)
val part2 = s"Final position: ${finalPos2.ship}, waypoint at ${finalPos2.waypoint}\nManhattan: ${finalPos2.ship.manhattan}"
part1 + "\n\n" + part2
case class Ship(dir: Dir, pos: Pos)
case class WaypointShip(ship: Pos, waypoint: Pos)
def moveShip(directions: List[(Char, Int)]): Ship =
directions.foldLeft(Ship(East, Vec2D(0,0)))((ship, command) => {
command match {
case ('L', deg) => ship.copy(dir = ship.dir + deg)
case ('R', deg) => ship.copy(dir = ship.dir - deg)
case ('F', dist) => ship.copy(pos = ship.pos.move(ship.dir, dist))
case (dir, dist) => ship.copy(pos = ship.pos.move(dir.cardinal, dist))
}
})
def moveWaypoint(directions: List[(Char, Int)]): WaypointShip =
directions.foldLeft(WaypointShip(Vec2D(0,0), Vec2D(10,1)))((state, command) => {
command match {
case ('L', deg) => state.copy(waypoint = state.waypoint.rot(deg))
case ('R', deg) => state.copy(waypoint = state.waypoint.rot(-deg))
case ('F', dist) => state.copy(ship = state.ship + state.waypoint * dist)
case (dir, dist) => state.copy(waypoint = state.waypoint.move(dir.cardinal, dist))
}
})
object Vectors {
import scala.Numeric.Implicits.given
opaque type Vec2D[T] = (T, T)
opaque type Dir = Int
val East: Dir = 0
val North: Dir = 90
val West: Dir = 180
val South: Dir = 270
extension (c: Char)
def cardinal: Dir = c match {
case 'E' => East
case 'N' => North
case 'W' => West
case 'S' => South
}
extension (dir: Dir)
def +(deg: Int): Dir = (dir + deg) % 360
def -(deg: Int): Dir = ((dir - deg) % 360 + 360) % 360
def unary_- : Dir = 360 - dir
def str: String = dir match {
case East => "East"
case North => "North"
case West => "West"
case South => "South"
}
extension [T: Numeric](v: Vec2D[T])
def +(w: Vec2D[T]): Vec2D[T] = (v._1 + w._1, v._2 + w._2)
def -(w: Vec2D[T]): Vec2D[T] = (v._1 - w._1, v._2 - w._2)
def *(x: T): Vec2D[T] = (v._1 * x, v._2 * x)
def rot(deg: Int): Vec2D[T] = (deg % 360 + 360) % 360 match {
case 90 => (-v._2, v._1)
case 180 => (-v._1, -v._2)
case 270 => (v._2, -v._1)
case 0 => v
}
def left(deg: Int): Vec2D[T] = repeat[Vec2D[T]](deg / 90)(_.rotLeft)(v)
def right(deg: Int): Vec2D[T] = repeat[Vec2D[T]](deg / 90)(_.rotRight)(v)
def rotLeft: Vec2D[T] = (-v._2, v._1)
def rotRight: Vec2D[T] = (v._2, -v._1)
def move(dir: Dir, dist: T): Vec2D[T] = dir match {
case North => (v._1, v._2 + dist)
case South => (v._1, v._2 - dist)
case East => (v._1 + dist, v._2)
case West => (v._1 - dist, v._2)
}
def manhattan: T = v._1.abs + v._2.abs
def Vec2D[T](x: T, y: T): Vec2D[T] = (x,y)
}
......@@ -14,6 +14,7 @@ package aoc2020
case 9 => input(_.toLong)(day9)
case 10 => input(_.toInt)(day10)
case 11 => inputF(boolChar('L'))(Vector)(day11)
case 12 => input()(day12)
case _ => "No such day implemented"
}
println(out)
......
......@@ -5,3 +5,5 @@ import scala.collection.mutable
def memoize[I, O](f: I => O): I => O = new mutable.HashMap[I, O]() {self =>
override def apply(key: I) = self.synchronized(getOrElseUpdate(key, f(key)))
}
def repeat[T](n: Int)(f: T => T): T => T = Function.chain(Seq.fill(n)(f))
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment