From 6ba1c0a4514205ba5b5db474eaf0ca76ce364c78 Mon Sep 17 00:00:00 2001 From: Soren Date: Sat, 24 Nov 2018 17:45:05 -0800 Subject: [PATCH] Big Refactor --- aoc/src/main/scala/aoc/AoC2017.scala | 181 --------------------- aoc/src/main/scala/aoc/Main.scala | 6 +- aoc/src/main/scala/aoc/y2017/Day01.scala | 25 +++ aoc/src/main/scala/aoc/y2017/Day02.scala | 35 ++++ aoc/src/main/scala/aoc/y2017/Day03.scala | 25 +++ aoc/src/main/scala/aoc/y2017/Day04.scala | 19 +++ aoc/src/main/scala/aoc/y2017/Day05.scala | 55 +++++++ aoc/src/main/scala/aoc/y2017/Day25.scala | 96 +++++++++++ aoc/src/main/scala/aoc/y2017/package.scala | 16 ++ 9 files changed, 274 insertions(+), 184 deletions(-) delete mode 100644 aoc/src/main/scala/aoc/AoC2017.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day01.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day02.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day03.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day04.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day05.scala create mode 100644 aoc/src/main/scala/aoc/y2017/Day25.scala create mode 100644 aoc/src/main/scala/aoc/y2017/package.scala diff --git a/aoc/src/main/scala/aoc/AoC2017.scala b/aoc/src/main/scala/aoc/AoC2017.scala deleted file mode 100644 index 00fdf7e..0000000 --- a/aoc/src/main/scala/aoc/AoC2017.scala +++ /dev/null @@ -1,181 +0,0 @@ -package aoc - -object AoC2017 extends Year { - - override def days = Map( - "1" -> Day1, - "2" -> Day2, - "3" -> Day3, - "25" -> Day25 - ) - - object Day1 extends Day { - - override def part1(input: String): String = { - val reg = """(\d)(?=\1)""".r - val matches = reg.findAllIn(input).toList - val csum = matches.map(_.toInt).sum - if (input.head == input.last) { - (csum + input.head.toString.toInt).toString - } else { - csum.toString - } - } - - override def part2(input: String): String = { - val (left, right) = input.splitAt(input.length / 2) - val zipped = left.zip(right) - val doubled = zipped.filter { case (l, r) => l == r }.map { case (c, _) => c.toString } - (doubled.map(_.toInt).sum * 2).toString - } - - } - - object Day2 extends Day { - - override def part1(input: String): String = { - val lines = input.lines.toList - val rows = lines.map(_.split("""\s+""").map(_.toInt)) - val minMax = rows.map(r => (r.min, r.max)) - val differences = minMax.map { case (min, max) => max - min } - differences.sum.toString - } - - override def part2(input: String): String = { - val lines = input.lines.toList - val rows = lines.map(_.split("""\s+""").map(_.toInt)) - rows.flatMap { r => - val q = r.zipWithIndex.flatMap { - case (e, i) => - r.drop(i + 1) - .map(f => { - val (min, max) = (Math.min(e, f), Math.max(e, f)) - if (max % min == 0) { - Some(max / min) - } else { - None - } - }) - } - q.filter(_.isDefined).map(_.get) - }.sum.toString - } - - } - - object Day3 extends Day { - - override def part1(input: String): String = { - case class Cell(num: Int, stepSize: Int, stepFrac: Int, stepped: Int, dist: (Int, Int)) - val inum = input.toInt - (inum match { - case 1 => 0 - case _ => - val layer = (Math.sqrt(inum).ceil / 2).floor.toInt - val square = ((layer + 1) * 2) - 1 - val diff = (square * square) - inum - val wave = Math.abs(layer - (diff % (layer * 2))) - layer + wave - }).toString - } - - override def part2(input: String): String = { - "Not Currently Implemented" // TODO Implement this - } - - } - - object Day25 extends Day { - - import fastparse._, MultiLineWhitespace._ - - case class State(name: String) - case class InState(state: State, whenZero: Branch, whenOne: Branch) - case class Branch(write: Int, move: Direction, stateChange: State) - sealed trait Direction { - def change: Int - } - case object MoveLeft extends Direction { - override def change: Int = -1 - } - case object MoveRight extends Direction { - override def change: Int = 1 - } - case class Program( - beginIn: State, - diagnosticCount: Int, - states: Map[State, InState], - index: Int = 0, - tape: Map[Int, Int] = Map() - ) { - - def step: Program = { - val ndc = diagnosticCount - 1 - val cs = states(beginIn) - val cc = tape.getOrElse(index, 0) - val br = cc match { - case 0 => cs.whenZero - case 1 => cs.whenOne - } - val wr = br.write - val mv = br.move - val ns = br.stateChange - val nm = tape + (index -> wr) - Program(ns, ndc, states, index + mv.change, nm) - } - - } - - def stateParser[_: P]: P[State] = P("state" ~ CharIn("A-Z").rep.!).map(State) - def writeParser[_: P]: P[Int] = P("- Write the value" ~ ("0" | "1").! ~ ".").map(_.toInt) - - def directionParser[_: P]: P[Direction] = P("- Move one slot to the" ~ ("left" | "right").! ~ ".").map { - case "left" => MoveLeft - case "right" => MoveRight - } - def stateChangeParser[_: P]: P[State] = P("- Continue with" ~ stateParser ~ ".") - - def branchParser[_: P]: P[Branch] = P(writeParser ~ directionParser ~ stateChangeParser).map { - case (write, dir, state) => Branch(write, dir, state) - } - - def inStateParser[_: P]: P[InState] = - P( - "In" ~ stateParser ~ ":" ~ "If the current value is 0:" ~ branchParser ~ "If the current value is 1:" ~ branchParser - ).map { - case (state, v0, v1) => InState(state, v0, v1) - } - - def programParser[_: P]: P[Program] = - P( - "Begin in" ~ stateParser ~ "." ~ - "Perform a diagnostic checksum after" ~ CharIn("0-9").rep(1).!.map(_.toInt) ~ "steps." ~ - inStateParser.rep.map(f => { - val z = f.map(_.state).zip(f) - z.toMap - }) - ).map { - case (begin, steps, states) => Program(begin, steps, states) - } - - override def part1(input: String): String = { - val Parsed.Success(program, _) = parse(input, programParser(_)) - def finalState(p: Program): Program = { - val np = p.step - print(s"\rInstructions Left: ${np.diagnosticCount}${" " * program.diagnosticCount.toString.length}") - np.diagnosticCount match { - case 0 => np - case _ => finalState(np) - } - } - println() - finalState(program).tape.values.count(_ == 1).toString - } - - override def part2(input: String): String = { - "You Win!" - } - - } - -} diff --git a/aoc/src/main/scala/aoc/Main.scala b/aoc/src/main/scala/aoc/Main.scala index 2ab576c..c9ba57a 100644 --- a/aoc/src/main/scala/aoc/Main.scala +++ b/aoc/src/main/scala/aoc/Main.scala @@ -5,7 +5,7 @@ import scala.io.StdIn object Main { val years = Map( - "2017" -> AoC2017 + "2017" -> y2017.get ) def main(args: Array[String]): Unit = { @@ -18,7 +18,7 @@ object Main { } def askForYear(): Year = { - println(s"Years: ${years.keys.mkString(", ")}") + println(s"Years: ${years.keys.toList.sortBy(_.toInt).mkString(", ")}") print("Year? ") val input = StdIn.readLine() years.get(input) match { @@ -30,7 +30,7 @@ object Main { } def askForDay(y: Year): Day = { - println(s"Days: ${y.days.keys.mkString(", ")}") + println(s"Days: ${y.days.keys.toList.sortBy(_.toInt).mkString(", ")}") print("Day? ") val input = StdIn.readLine() y.days.get(input) match { diff --git a/aoc/src/main/scala/aoc/y2017/Day01.scala b/aoc/src/main/scala/aoc/y2017/Day01.scala new file mode 100644 index 0000000..2c4bde5 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day01.scala @@ -0,0 +1,25 @@ +package aoc.y2017 + +import aoc.Day + +object Day01 extends Day { + + override def part1(input: String): String = { + val reg = """(\d)(?=\1)""".r + val matches = reg.findAllIn(input).toList + val csum = matches.map(_.toInt).sum + if (input.head == input.last) { + (csum + input.head.toString.toInt).toString + } else { + csum.toString + } + } + + override def part2(input: String): String = { + val (left, right) = input.splitAt(input.length / 2) + val zipped = left.zip(right) + val doubled = zipped.filter { case (l, r) => l == r }.map { case (c, _) => c.toString } + (doubled.map(_.toInt).sum * 2).toString + } + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day02.scala b/aoc/src/main/scala/aoc/y2017/Day02.scala new file mode 100644 index 0000000..12643bc --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day02.scala @@ -0,0 +1,35 @@ +package aoc.y2017 + +import aoc.Day + +object Day02 extends Day { + + override def part1(input: String): String = { + val lines = input.lines.toList + val rows = lines.map(_.split("""\s+""").map(_.toInt)) + val minMax = rows.map(r => (r.min, r.max)) + val differences = minMax.map { case (min, max) => max - min } + differences.sum.toString + } + + override def part2(input: String): String = { + val lines = input.lines.toList + val rows = lines.map(_.split("""\s+""").map(_.toInt)) + rows.flatMap { r => + val q = r.zipWithIndex.flatMap { + case (e, i) => + r.drop(i + 1) + .map(f => { + val (min, max) = (Math.min(e, f), Math.max(e, f)) + if (max % min == 0) { + Some(max / min) + } else { + None + } + }) + } + q.filter(_.isDefined).map(_.get) + }.sum.toString + } + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day03.scala b/aoc/src/main/scala/aoc/y2017/Day03.scala new file mode 100644 index 0000000..996fe99 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day03.scala @@ -0,0 +1,25 @@ +package aoc.y2017 + +import aoc.Day + +object Day03 extends Day { + + override def part1(input: String): String = { + case class Cell(num: Int, stepSize: Int, stepFrac: Int, stepped: Int, dist: (Int, Int)) + val inum = input.toInt + (inum match { + case 1 => 0 + case _ => + val layer = (Math.sqrt(inum).ceil / 2).floor.toInt + val square = ((layer + 1) * 2) - 1 + val diff = (square * square) - inum + val wave = Math.abs(layer - (diff % (layer * 2))) + layer + wave + }).toString + } + + override def part2(input: String): String = { + "Not Currently Implemented" // TODO Implement this + } + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day04.scala b/aoc/src/main/scala/aoc/y2017/Day04.scala new file mode 100644 index 0000000..a40f4e5 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day04.scala @@ -0,0 +1,19 @@ +package aoc.y2017 + +import aoc.Day + +object Day04 extends Day { + + implicit class ArrayOps[A](a: Array[A]) { + + def unique: Boolean = a.distinct.length == a.length + + } + + override def part1(input: String): String = + input.lines.map(_.split(' ')).count(_.unique).toString + + override def part2(input: String): String = + input.lines.map(_.split(' ').map(_.sorted)).count(_.unique).toString + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day05.scala b/aoc/src/main/scala/aoc/y2017/Day05.scala new file mode 100644 index 0000000..74a35f9 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day05.scala @@ -0,0 +1,55 @@ +package aoc.y2017 + +import aoc.Day + +object Day05 extends Day { + + trait Stepper { + def step(p: Program): Program + } + + case class Program(instructions: List[Int], index: Int = 0) { + + def step(implicit stepper: Stepper): Program = stepper.step(this) + + } + + def countSteps(p: Program, steps: Int = 0)(implicit stepper: Stepper): Int = { + print(s"\rCurrent Instruction: ${p.index}/${p.instructions.size}${" " * p.instructions.size.toString.length}") + if(p.index >= p.instructions.size) { + steps + } else { + countSteps(p.step, steps + 1) + } + } + + def getStartingProgram(input: String): Program = { + val lines = input.lines.map(_.toInt) + Program(lines.toList) + } + + 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) + } + } + 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) + } + } + println() + countSteps(getStartingProgram(input)).toString + } + +} diff --git a/aoc/src/main/scala/aoc/y2017/Day25.scala b/aoc/src/main/scala/aoc/y2017/Day25.scala new file mode 100644 index 0000000..3c04865 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/Day25.scala @@ -0,0 +1,96 @@ +package aoc.y2017 + +import aoc.Day + +object Day25 extends Day { + + import fastparse._, MultiLineWhitespace._ + + case class State(name: String) + case class InState(state: State, whenZero: Branch, whenOne: Branch) + case class Branch(write: Int, move: Direction, stateChange: State) + sealed trait Direction { + def change: Int + } + case object MoveLeft extends Direction { + override def change: Int = -1 + } + case object MoveRight extends Direction { + override def change: Int = 1 + } + case class Program( + beginIn: State, + diagnosticCount: Int, + states: Map[State, InState], + index: Int = 0, + tape: Map[Int, Int] = Map() + ) { + + def step: Program = { + val ndc = diagnosticCount - 1 + val cs = states(beginIn) + val cc = tape.getOrElse(index, 0) + val br = cc match { + case 0 => cs.whenZero + case 1 => cs.whenOne + } + val wr = br.write + val mv = br.move + val ns = br.stateChange + val nm = tape + (index -> wr) + Program(ns, ndc, states, index + mv.change, nm) + } + + } + + def stateParser[_: P]: P[State] = P("state" ~ CharIn("A-Z").rep.!).map(State) + def writeParser[_: P]: P[Int] = P("- Write the value" ~ ("0" | "1").! ~ ".").map(_.toInt) + + def directionParser[_: P]: P[Direction] = P("- Move one slot to the" ~ ("left" | "right").! ~ ".").map { + case "left" => MoveLeft + case "right" => MoveRight + } + def stateChangeParser[_: P]: P[State] = P("- Continue with" ~ stateParser ~ ".") + + def branchParser[_: P]: P[Branch] = P(writeParser ~ directionParser ~ stateChangeParser).map { + case (write, dir, state) => Branch(write, dir, state) + } + + def inStateParser[_: P]: P[InState] = + P( + "In" ~ stateParser ~ ":" ~ "If the current value is 0:" ~ branchParser ~ "If the current value is 1:" ~ branchParser + ).map { + case (state, v0, v1) => InState(state, v0, v1) + } + + def programParser[_: P]: P[Program] = + P( + "Begin in" ~ stateParser ~ "." ~ + "Perform a diagnostic checksum after" ~ CharIn("0-9").rep(1).!.map(_.toInt) ~ "steps." ~ + inStateParser.rep.map(f => { + val z = f.map(_.state).zip(f) + z.toMap + }) + ).map { + case (begin, steps, states) => Program(begin, steps, states) + } + + override def part1(input: String): String = { + val Parsed.Success(program, _) = parse(input, programParser(_)) + def finalState(p: Program): Program = { + val np = p.step + print(s"\rInstructions Left: ${np.diagnosticCount}${" " * program.diagnosticCount.toString.length}") + np.diagnosticCount match { + case 0 => np + case _ => finalState(np) + } + } + println() + finalState(program).tape.values.count(_ == 1).toString + } + + override def part2(input: String): String = { + "You Win!" + } + +} diff --git a/aoc/src/main/scala/aoc/y2017/package.scala b/aoc/src/main/scala/aoc/y2017/package.scala new file mode 100644 index 0000000..6ed8831 --- /dev/null +++ b/aoc/src/main/scala/aoc/y2017/package.scala @@ -0,0 +1,16 @@ +package aoc + +package object y2017 extends Year { + + def get = this + + override def days: Map[String, Day] = Map( + "1" -> Day01, + "2" -> Day02, + "3" -> Day03, + "4" -> Day04, + "5" -> Day05, + "25" -> Day25 + ) + +}