Skip to content

Instantly share code, notes, and snippets.

@justinhj
Created December 27, 2016 21:00
Show Gist options
  • Select an option

  • Save justinhj/ab91c83a9b40660116a3abfffa4b7032 to your computer and use it in GitHub Desktop.

Select an option

Save justinhj/ab91c83a9b40660116a3abfffa4b7032 to your computer and use it in GitHub Desktop.
import scala.collection.{immutable, mutable}
object Xmas1 {
object Move {
def fromString(arg: String): Option[Move] = arg match {
case s if arg.startsWith("R") || arg.startsWith("L") =>
try {
val turn = if(arg.charAt(0) == 'R') Right else Left
Some(Move(arg.substring(1).toInt, turn))
}
catch {
case e: Exception =>
None
}
case _ => None
}
}
case class Move(times: Int, direction: Turn)
val testInput = "R4, R5, L5, L5, L3, R2, R1, R1, L5, R5, R2, L1, L3, L4, R3, L1, L1, R2, R3, R3, R1, L3, L5, R3, R1, L1, R1, R2, L1, L4, L5, R4, R2, L192, R5, L2, R53, R1, L5, R73, R5, L5, R186, L3, L2, R1, R3, L3, L3, R1, L4, L2, R3, L5, R4, R3, R1, L1, R5, R2, R1, R1, R1, R3, R2, L1, R5, R1, L5, R2, L2, L4, R3, L1, R4, L5, R4, R3, L5, L3, R4, R2, L5, L5, R2, R3, R5, R4, R2, R1, L1, L5, L2, L3, L4, L5, L4, L5, L1, R3, R4, R5, R3, L5, L4, L3, L1, L4, R2, R5, R5, R4, L2, L4, R3, R1, L2, R5, L5, R1, R1, L1, L5, L5, L2, L1, R5, R2, L4, L1, R4, R3, L3, R1, R5, L1, L4, R2, L3, R5, R3, R1, L3"
val turnsFromInput = movesFromString(testInput)
sealed trait Facing
object North extends Facing
object South extends Facing
object West extends Facing
object East extends Facing
sealed trait Turn
object Left extends Turn
object Right extends Turn
object Straight extends Turn
def movesFromString(input: String) = input.split(", ").flatMap { Move.fromString }
// assume an x,y grid where x runs west to east left to right
// and y is south to north bottom to top
case class Position(x: Int, y: Int, facing: Facing) {
def blocksAway = Math.abs(x) + Math.abs(y)
}
def executeTurn(currentFace: Facing, direction: Turn): Facing = direction match {
case Right =>
currentFace match {
case North => East
case East => South
case South => West
case West => North
}
case Left =>
currentFace match {
case North => West
case West => South
case South => East
case East => North
}
case Straight =>
currentFace
}
def executeMove(currentPos: Position, turn: Move): Position = {
val turned = currentPos.copy(facing = executeTurn(currentPos.facing, turn.direction))
turned.facing match {
case North =>
turned.copy(y = turned.y + turn.times)
case South =>
turned.copy(y = turned.y - turn.times)
case West =>
turned.copy(x = turned.x - turn.times)
case East =>
turned.copy(x = turned.x + turn.times)
}
}
val sampleTurns = movesFromString("R2, L3")
def blocksAwayFromTurns(moves: Seq[Move]): Int = {
val finalPos = moves.foldLeft(Position(0,0,North)){
(acc,move) =>
executeMove(acc,move)
}
finalPos.blocksAway
}
assert(blocksAwayFromTurns(sampleTurns) == 5)
// find the first location you visit twice
def firstTwice(position: Position, moves: Seq[Move], visited: immutable.Set[(Int,Int)]): Option[Int] = {
if(moves.isEmpty) {
None
}
else {
val newPos = executeMove(position, moves.head)
if(visited.contains((newPos.x, newPos.y))) {
Some(newPos.blocksAway)
}
else {
firstTwice(newPos, moves.tail, visited + ((newPos.x, newPos.y)))
}
}
}
val part2Example = movesFromString("R8, R4, R4, R8")
// convert the series of moves to single steps
// so R4 becomes R1 S1 S1 S1 and so on
def movesToSingleSteps(inMoves: Seq[Move], outMoves: Seq[Move]): Seq[Move] = {
if(inMoves.isEmpty) outMoves
else {
val next = inMoves.head
val singleStep = Seq(next.copy(times = 1))
val remainder = if(next.times > 1) Seq.fill(next.times - 1)(Move(1, Straight)) else Seq()
movesToSingleSteps(inMoves.tail, outMoves ++ singleStep ++ remainder)
}
}
def main(args: Array[String]): Unit = {
val singleSteps = movesToSingleSteps(turnsFromInput, Seq())
val first = firstTwice(Position(0,0,North), singleSteps, Set((0,0)))
val visitTwice = movesToSingleSteps(movesFromString("R4, L4, R4, R4, R4"), Seq())
val firstVisitTwice = firstTwice(Position(0,0,North), visitTwice, Set((0,0)))
val returnHome = movesToSingleSteps(movesFromString("R8, R4, R4, R8"), Seq())
val returnHomeFirstTwice = firstTwice(Position(0,0,North), returnHome, Set((0,0)))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment