Skip to content

Instantly share code, notes, and snippets.

@waynejo
Last active February 26, 2021 12:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save waynejo/d97585f8134cb6dde831033793f89feb to your computer and use it in GitHub Desktop.
Save waynejo/d97585f8134cb6dde831033793f89feb to your computer and use it in GitHub Desktop.
import java.io.FileInputStream
import scala.io.StdIn
@main def solve12() =
enum Direction(val degree: Int, val dx: Int, val dy: Int) {
case north extends Direction(0, 0, 1)
case south extends Direction(180, 0, -1)
case east extends Direction(90, 1, 0)
case west extends Direction(270, -1, 0)
def rotate(degree: Int): Direction = {
val rotatedDegree = (this.degree + (degree + 360)) % 360
rotatedDegree match {
case 0 =>
Direction.north
case 90 =>
Direction.east
case 180 =>
Direction.south
case 270 =>
Direction.west
}
}
}
enum Code {
case north
case south
case east
case west
case left
case right
case forward
}
case class Command(code: Code, operand: Int)
case class Ship(direction: Direction = Direction.east, x: Int = 0, y: Int = 0)
case class Waypoint(x: Int = 10, y: Int = 1) {
def rotate(degree: Int): Waypoint = {
(degree + 360) % 360 match {
case 0 =>
this
case 90 =>
Waypoint(x = y, y = -x)
case 180 =>
Waypoint(x = -x, y = -y)
case 270 =>
Waypoint(x = -y, y = x)
}
}
}
object Command {
def apply(line: String): Command = {
val code = line.head match {
case 'N' =>
Code.north
case 'S' =>
Code.south
case 'E' =>
Code.east
case 'W' =>
Code.west
case 'L' =>
Code.left
case 'R' =>
Code.right
case 'F' =>
Code.forward
}
val operand = line.tail.toInt
Command(code, operand)
}
}
def solve1(ship: Ship, commands: Vector[Command]): Int = {
commands.headOption match {
case Some(command) =>
command.code match {
case Code.north =>
solve1(ship.copy(y = ship.y + command.operand), commands.tail)
case Code.south =>
solve1(ship.copy(y = ship.y - command.operand), commands.tail)
case Code.east =>
solve1(ship.copy(x = ship.x + command.operand), commands.tail)
case Code.west =>
solve1(ship.copy(x = ship.x - command.operand), commands.tail)
case Code.left =>
solve1(ship.copy(direction = ship.direction.rotate(-command.operand)), commands.tail)
case Code.right =>
solve1(ship.copy(direction = ship.direction.rotate(command.operand)), commands.tail)
case Code.forward =>
val x = ship.x + ship.direction.dx * command.operand
val y = ship.y + ship.direction.dy * command.operand
solve1(ship.copy(x = x, y = y), commands.tail)
}
case _ =>
ship.x.abs + ship.y.abs
}
}
def solve2(ship: Ship, waypoint: Waypoint, commands: Vector[Command]): Int = {
commands.headOption match {
case Some(command) =>
command.code match {
case Code.north =>
solve2(ship, waypoint.copy(y = waypoint.y + command.operand), commands.tail)
case Code.south =>
solve2(ship, waypoint.copy(y = waypoint.y - command.operand), commands.tail)
case Code.east =>
solve2(ship, waypoint.copy(x = waypoint.x + command.operand), commands.tail)
case Code.west =>
solve2(ship, waypoint.copy(x = waypoint.x - command.operand), commands.tail)
case Code.left =>
solve2(ship, waypoint.rotate(-command.operand), commands.tail)
case Code.right =>
solve2(ship, waypoint.rotate(command.operand), commands.tail)
case Code.forward =>
val x = ship.x + waypoint.x * command.operand
val y = ship.y + waypoint.y * command.operand
solve2(ship.copy(x = x, y = y), waypoint, commands.tail)
}
case _ =>
ship.x.abs + ship.y.abs
}
}
val in = new FileInputStream("example12-1.in")
System.setIn(in)
val inputs = Iterator.continually(StdIn.readLine()).takeWhile(_ != null).toVector
val commands = inputs.map { line => Command(line) }
val answer1 = solve1(Ship(), commands)
println(answer1)
val answer2 = solve2(Ship(), Waypoint(), commands)
println(answer2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment