diff --git a/aoc/src/main/scala/aoc/Main.scala b/aoc/src/main/scala/aoc/Main.scala index c9ba57a..9330d0d 100644 --- a/aoc/src/main/scala/aoc/Main.scala +++ b/aoc/src/main/scala/aoc/Main.scala @@ -5,7 +5,8 @@ import scala.io.StdIn object Main { val years = Map( - "2017" -> y2017.get + "2016" -> y2016.!, + "2017" -> y2017.!, ) def main(args: Array[String]): Unit = { diff --git a/aoc/src/main/scala/aoc/Year.scala b/aoc/src/main/scala/aoc/Year.scala index dbe0a20..fb0d5bd 100644 --- a/aoc/src/main/scala/aoc/Year.scala +++ b/aoc/src/main/scala/aoc/Year.scala @@ -2,6 +2,8 @@ package aoc trait Year { + def !(): this.type = this + def days: Map[String, Day] } diff --git a/aoc/src/main/scala/aoc/package.scala b/aoc/src/main/scala/aoc/package.scala new file mode 100644 index 0000000..2a8be86 --- /dev/null +++ b/aoc/src/main/scala/aoc/package.scala @@ -0,0 +1,25 @@ +package object aoc { + + def rotateLeft[A](list: List[A], i: Int): List[A] = { + val size = list.size + list.drop(i % size) ++ list.take(i % size) + } + + def rotateRight[A](list: List[A], i: Int): List[A] = { + val size = list.size + list.drop(size - (i % size)) ++ list.take(size - (i % size)) + } + + implicit class TupleInt2Ops(t: (Int, Int)) { + + def +(o: (Int, Int)): (Int, Int) = (t, o) match { + case ((x1, y1), (x2, y2)) => (x1 + x2, y1 + y2) + } + + def *(m: Int): (Int, Int) = t match { + case (a, b) => (a * m, b * m) + } + + } + +} diff --git a/aoc/src/main/scala/aoc/y2016/Day01.scala b/aoc/src/main/scala/aoc/y2016/Day01.scala new file mode 100644 index 0000000..e25cea1 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2016/Day01.scala @@ -0,0 +1,111 @@ +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 + } + +} diff --git a/aoc/src/main/scala/aoc/y2016/package.scala b/aoc/src/main/scala/aoc/y2016/package.scala new file mode 100644 index 0000000..08ecb59 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2016/package.scala @@ -0,0 +1,9 @@ +package aoc + +package object y2016 extends Year { + + override def days: Map[String, Day] = Map( + "1" -> Day01 + ) + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day03.scala b/aoc/src/main/scala/aoc/y2017/Day03.scala index 5917aaa..abcce78 100644 --- a/aoc/src/main/scala/aoc/y2017/Day03.scala +++ b/aoc/src/main/scala/aoc/y2017/Day03.scala @@ -1,6 +1,6 @@ package aoc.y2017 -import aoc.Day +import aoc._ object Day03 extends Day { diff --git a/aoc/src/main/scala/aoc/y2017/Day05.scala b/aoc/src/main/scala/aoc/y2017/Day05.scala index 5c562ca..8513072 100644 --- a/aoc/src/main/scala/aoc/y2017/Day05.scala +++ b/aoc/src/main/scala/aoc/y2017/Day05.scala @@ -29,24 +29,20 @@ object Day05 extends Day { } override def part1(input: String): String = { - implicit val stepper: Stepper = new Stepper { - def step(p: Program): Program = { - val instruction = p.instructions(p.index) - val newList = p.instructions.updated(p.index, instruction + 1) - Program(newList, p.index + instruction) - } + implicit val stepper: Stepper = (p: Program) => { + val instruction = p.instructions(p.index) + val newList = p.instructions.updated(p.index, instruction + 1) + Program(newList, p.index + instruction) } println() countSteps(getStartingProgram(input)).toString } override def part2(input: String): String = { - implicit val stepper: Stepper = new Stepper { - def step(p: Program): Program = { - val instruction = p.instructions(p.index) - val newList = p.instructions.updated(p.index, if (instruction >= 3) instruction - 1 else instruction + 1) - Program(newList, p.index + instruction) - } + implicit val stepper: Stepper = (p: Program) => { + val instruction = p.instructions(p.index) + val newList = p.instructions.updated(p.index, if (instruction >= 3) instruction - 1 else instruction + 1) + Program(newList, p.index + instruction) } println() countSteps(getStartingProgram(input)).toString diff --git a/aoc/src/main/scala/aoc/y2017/Day06.scala b/aoc/src/main/scala/aoc/y2017/Day06.scala index 61ac3b5..c42f14f 100644 --- a/aoc/src/main/scala/aoc/y2017/Day06.scala +++ b/aoc/src/main/scala/aoc/y2017/Day06.scala @@ -1,6 +1,6 @@ package aoc.y2017 -import aoc.Day +import aoc._ object Day06 extends Day { diff --git a/aoc/src/main/scala/aoc/y2017/Day08.scala b/aoc/src/main/scala/aoc/y2017/Day08.scala index 04ede91..5ce255b 100644 --- a/aoc/src/main/scala/aoc/y2017/Day08.scala +++ b/aoc/src/main/scala/aoc/y2017/Day08.scala @@ -42,15 +42,15 @@ object Day08 extends Day { case class FullTest(reg: String, op: Test, v: Int) case class Line(i: FullInstruction, t: FullTest) - def registerParser[_: P] = P(CharIn("a-z").rep(1).!) - def numberParser[_: P] = P(("-".? ~ CharIn("0-9").rep(1)).!).map(_.toInt) + def registerParser[_: P]: P[String] = P(CharIn("a-z").rep(1).!) + def numberParser[_: P]: P[Int] = P(("-".? ~ CharIn("0-9").rep(1)).!).map(_.toInt) - def instructionParser[_: P] = P(("inc" | "dec").!).map { + def instructionParser[_: P]: P[Instruction] = P(("inc" | "dec").!).map { case "inc" => Inc case "dec" => Dec } - def testParser[_: P] = P(("<=" | ">=" | "<" | ">" | "==" | "!=").!).map { + def testParser[_: P]: P[Test] = P(("<=" | ">=" | "<" | ">" | "==" | "!=").!).map { case "<" => Lt case ">" => Gt case "<=" => Leq @@ -59,18 +59,19 @@ object Day08 extends Day { case "!=" => Neq } - def fullInstructionParser[_: P] = P(registerParser ~ " " ~ instructionParser ~ " " ~ numberParser).map { - case (reg, op, v) => FullInstruction(reg, op, v) - } + def fullInstructionParser[_: P]: P[FullInstruction] = + P(registerParser ~ " " ~ instructionParser ~ " " ~ numberParser).map { + case (reg, op, v) => FullInstruction(reg, op, v) + } - def fullTestParser[_: P] = P(registerParser ~ " " ~ testParser ~ " " ~ numberParser).map { + def fullTestParser[_: P]: P[FullTest] = P(registerParser ~ " " ~ testParser ~ " " ~ numberParser).map { case (reg, op, v) => FullTest(reg, op, v) } - def lineParser[_: P] = P(fullInstructionParser ~ " if " ~ fullTestParser).map { + def lineParser[_: P]: P[Line] = P(fullInstructionParser ~ " if " ~ fullTestParser).map { case (i, t) => Line(i, t) } - def listParser[_: P] = P(lineParser.rep(1, "\n")).map(_.toList) + def listParser[_: P]: P[List[Line]] = P(lineParser.rep(1, "\n")).map(_.toList) def getProgram(input: String): List[Line] = { val Parsed.Success(list, _) = parse(input, listParser(_)) diff --git a/aoc/src/main/scala/aoc/y2017/Day10.scala b/aoc/src/main/scala/aoc/y2017/Day10.scala index 8269cf9..4ba2766 100644 --- a/aoc/src/main/scala/aoc/y2017/Day10.scala +++ b/aoc/src/main/scala/aoc/y2017/Day10.scala @@ -1,6 +1,6 @@ package aoc.y2017 -import aoc.Day +import aoc._ object Day10 extends Day { diff --git a/aoc/src/main/scala/aoc/y2017/Day11.scala b/aoc/src/main/scala/aoc/y2017/Day11.scala index 9e57f5d..8a8a316 100644 --- a/aoc/src/main/scala/aoc/y2017/Day11.scala +++ b/aoc/src/main/scala/aoc/y2017/Day11.scala @@ -1,6 +1,6 @@ package aoc.y2017 -import aoc.Day +import aoc._ object Day11 extends Day { diff --git a/aoc/src/main/scala/aoc/y2017/package.scala b/aoc/src/main/scala/aoc/y2017/package.scala index 8ad233a..4536417 100644 --- a/aoc/src/main/scala/aoc/y2017/package.scala +++ b/aoc/src/main/scala/aoc/y2017/package.scala @@ -2,8 +2,6 @@ package aoc package object y2017 extends Year { - def get = this - override def days: Map[String, Day] = Map( "1" -> Day01, "2" -> Day02, @@ -20,21 +18,4 @@ package object y2017 extends Year { "25" -> Day25 ) - def rotateLeft[A](list: List[A], i: Int): List[A] = { - val size = list.size - list.drop(i % size) ++ list.take(i % size) - } - - def rotateRight[A](list: List[A], i: Int): List[A] = { - val size = list.size - list.drop(size - (i % size)) ++ list.take(size - (i % size)) - } - - implicit class TupleInt2Ops(t: (Int, Int)) { - - def +(o: (Int, Int)): (Int, Int) = (t, o) match { - case ((x1, y1), (x2, y2)) => (x1 + x2, y1 + y2) - } - } - }