Created
December 27, 2016 21:00
-
-
Save justinhj/ab91c83a9b40660116a3abfffa4b7032 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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