Big Refactor
This commit is contained in:
parent
02d49f7dd6
commit
6ba1c0a451
9 changed files with 274 additions and 184 deletions
|
@ -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!"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -5,7 +5,7 @@ import scala.io.StdIn
|
||||||
object Main {
|
object Main {
|
||||||
|
|
||||||
val years = Map(
|
val years = Map(
|
||||||
"2017" -> AoC2017
|
"2017" -> y2017.get
|
||||||
)
|
)
|
||||||
|
|
||||||
def main(args: Array[String]): Unit = {
|
def main(args: Array[String]): Unit = {
|
||||||
|
@ -18,7 +18,7 @@ object Main {
|
||||||
}
|
}
|
||||||
|
|
||||||
def askForYear(): Year = {
|
def askForYear(): Year = {
|
||||||
println(s"Years: ${years.keys.mkString(", ")}")
|
println(s"Years: ${years.keys.toList.sortBy(_.toInt).mkString(", ")}")
|
||||||
print("Year? ")
|
print("Year? ")
|
||||||
val input = StdIn.readLine()
|
val input = StdIn.readLine()
|
||||||
years.get(input) match {
|
years.get(input) match {
|
||||||
|
@ -30,7 +30,7 @@ object Main {
|
||||||
}
|
}
|
||||||
|
|
||||||
def askForDay(y: Year): Day = {
|
def askForDay(y: Year): Day = {
|
||||||
println(s"Days: ${y.days.keys.mkString(", ")}")
|
println(s"Days: ${y.days.keys.toList.sortBy(_.toInt).mkString(", ")}")
|
||||||
print("Day? ")
|
print("Day? ")
|
||||||
val input = StdIn.readLine()
|
val input = StdIn.readLine()
|
||||||
y.days.get(input) match {
|
y.days.get(input) match {
|
||||||
|
|
25
aoc/src/main/scala/aoc/y2017/Day01.scala
Normal file
25
aoc/src/main/scala/aoc/y2017/Day01.scala
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
35
aoc/src/main/scala/aoc/y2017/Day02.scala
Normal file
35
aoc/src/main/scala/aoc/y2017/Day02.scala
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
25
aoc/src/main/scala/aoc/y2017/Day03.scala
Normal file
25
aoc/src/main/scala/aoc/y2017/Day03.scala
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
19
aoc/src/main/scala/aoc/y2017/Day04.scala
Normal file
19
aoc/src/main/scala/aoc/y2017/Day04.scala
Normal file
|
@ -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
|
||||||
|
|
||||||
|
}
|
55
aoc/src/main/scala/aoc/y2017/Day05.scala
Normal file
55
aoc/src/main/scala/aoc/y2017/Day05.scala
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
96
aoc/src/main/scala/aoc/y2017/Day25.scala
Normal file
96
aoc/src/main/scala/aoc/y2017/Day25.scala
Normal file
|
@ -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!"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
16
aoc/src/main/scala/aoc/y2017/package.scala
Normal file
16
aoc/src/main/scala/aoc/y2017/package.scala
Normal file
|
@ -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
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue