I hate day 4 with a passion.
This commit is contained in:
parent
d90152d660
commit
3a4b38f80f
2 changed files with 169 additions and 0 deletions
168
aoc/src/main/scala/aoc/y2018/Day04.scala
Normal file
168
aoc/src/main/scala/aoc/y2018/Day04.scala
Normal file
|
@ -0,0 +1,168 @@
|
|||
package aoc.y2018
|
||||
import aoc.Day
|
||||
|
||||
// Todo: Seriously. Rewrite this. This is garbage.
|
||||
object Day04 extends Day {
|
||||
|
||||
import fastparse._, NoWhitespace._
|
||||
|
||||
def padNum(n: Int, l: Int): String = {
|
||||
n.toString.reverse.padTo(l, '0').reverse
|
||||
}
|
||||
|
||||
case class Date(year: Int, month: Int, day: Int) {
|
||||
def di: Int = year * 10000 + month * 100 + day
|
||||
}
|
||||
|
||||
case class Time(hour: Int, minute: Int) {
|
||||
def mi: Int = hour * 60 + minute
|
||||
}
|
||||
|
||||
case class DateTime(d: Date, t: Time) {
|
||||
override def toString: String =
|
||||
s"${padNum(d.year, 4)}-${padNum(d.month, 2)}-${padNum(d.day, 2)} ${padNum(t.hour, 2)}:${padNum(t.minute, 2)}"
|
||||
}
|
||||
|
||||
sealed trait Event {
|
||||
def wake: Boolean
|
||||
}
|
||||
case class Shift(g: Int) extends Event {
|
||||
override def wake: Boolean = true
|
||||
}
|
||||
case object Sleep extends Event {
|
||||
override def wake: Boolean = false
|
||||
}
|
||||
case object Wake extends Event {
|
||||
override def wake: Boolean = true
|
||||
}
|
||||
|
||||
case class Action(t: DateTime, e: Event)
|
||||
|
||||
def digits[_: P]: P[Int] = P(CharIn("0-9").rep(1).!).map(_.toInt)
|
||||
|
||||
def dateParser[_: P]: P[Date] = P(digits ~ "-" ~ digits ~ "-" ~ digits).map {
|
||||
case (y, m, d) => Date(y, m, d)
|
||||
}
|
||||
|
||||
def timeParser[_: P]: P[Time] = P(digits ~ ":" ~ digits).map {
|
||||
case (h, m) => Time(h, m)
|
||||
}
|
||||
|
||||
def dateTimeParser[_: P]: P[DateTime] = P("[" ~ dateParser ~ " " ~/ timeParser ~ "]").map {
|
||||
case (d, t) => shiftByHours(DateTime(d, t), 12)
|
||||
}
|
||||
def shiftParser[_: P]: P[Shift] = P("Guard #" ~ digits ~ " begins shift").map(Shift)
|
||||
def sleepParser[_: P]: P[Sleep.type] = P("falls asleep").map(_ => Sleep)
|
||||
def wakeParser[_: P]: P[Wake.type] = P("wakes up").map(_ => Wake)
|
||||
def eventParser[_: P]: P[Event] = P(shiftParser | sleepParser | wakeParser)
|
||||
|
||||
def actionParser[_: P]: P[Action] = P(dateTimeParser ~ " " ~ eventParser).map {
|
||||
case (d, e) => Action(d, e)
|
||||
}
|
||||
def actionsParser[_: P]: P[List[Action]] = P(actionParser.rep(1, "\n"./)).map(_.toList)
|
||||
|
||||
def getActions(input: String): List[Action] = {
|
||||
val Parsed.Success(l, _) = parse(input, actionsParser(_))
|
||||
l.sortBy(_.t.toString)
|
||||
}
|
||||
|
||||
def shiftByHours(d: DateTime, n: Int): DateTime = {
|
||||
val h = d.t.hour
|
||||
val (da, nh) = ((h + n) / 24, (h + n) % 24)
|
||||
d.copy(d = shiftByDays(d, da).d, t = d.t.copy(hour = nh))
|
||||
}
|
||||
|
||||
val monthDayMap = Map(
|
||||
1 -> 31,
|
||||
2 -> 28,
|
||||
3 -> 31,
|
||||
4 -> 30,
|
||||
5 -> 31,
|
||||
6 -> 30,
|
||||
7 -> 31,
|
||||
8 -> 31,
|
||||
9 -> 30,
|
||||
10 -> 31,
|
||||
11 -> 30,
|
||||
12 -> 31
|
||||
)
|
||||
|
||||
def shiftByDays(d: DateTime, n: Int): DateTime = {
|
||||
val m = monthDayMap(d.d.month)
|
||||
val a = d.d.day
|
||||
if (n > 1) throw new NotImplementedError("Month modulos not accounted for yet!")
|
||||
val (ma, nd) = ((a + n) / m, (a + n) % m)
|
||||
val nm = d.d.month + ma
|
||||
d.copy(d = d.d.copy(month = nm, day = nd))
|
||||
}
|
||||
|
||||
case class Day(d: Date, g: Option[Int], mins: List[Minute])
|
||||
case class Minute(state: Boolean) extends AnyVal
|
||||
case class State(d: List[Day] = List(), qg: List[Int] = List(), cm: Int = 0) {
|
||||
|
||||
def step(oa: Option[Action]): State = {
|
||||
print(s"\r${d.size}\t\t$cm\t\t")
|
||||
val (nqg, acdl): (List[Int], Option[Day]) = oa match {
|
||||
case Some(a) =>
|
||||
d.headOption match {
|
||||
case Some(cd) =>
|
||||
a.e match {
|
||||
case Shift(ng) => {
|
||||
cd.g match {
|
||||
case Some(_) => (qg :+ ng, Some(cd))
|
||||
case None => (qg, Some(cd.copy(g = Some(ng))))
|
||||
}
|
||||
}
|
||||
case Wake => (qg, Some(cd.copy(mins = cd.mins :+ Minute(true))))
|
||||
case Sleep => (qg, Some(cd.copy(mins = cd.mins :+ Minute(false))))
|
||||
}
|
||||
case None =>
|
||||
a.e match {
|
||||
case Shift(g) => (qg, Some(Day(a.t.d, Some(g), List.fill(a.t.t.mi)(Minute(true)))))
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
d.headOption match {
|
||||
case Some(cd) =>
|
||||
(qg, Some(cd.copy(mins = cd.mins :+ cd.mins.last)))
|
||||
case None =>
|
||||
(qg, None)
|
||||
}
|
||||
}
|
||||
val nd = if (cm == 0 || d.isEmpty) {
|
||||
acdl.fold(d)(_ :: d)
|
||||
} else {
|
||||
acdl.fold(d.tail)(_ :: d.tail)
|
||||
}
|
||||
val ncm = (cm + 1) % (24 * 60)
|
||||
State(nd, nqg, ncm)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override def part1(input: String): String = {
|
||||
return ??? // Fixme: This all sucks and is broken please send an ambulance
|
||||
val actions = getActions(input)
|
||||
println(actions.mkString("\n"))
|
||||
val dayGroups = actions.groupBy(_.t.d)
|
||||
val fleshedOut: Map[Date, List[Option[Action]]] = dayGroups.mapValues(l => {
|
||||
val zipped = l.map(_.t.t.mi).zip(l).toMap
|
||||
List.tabulate(60 * 2)(n => zipped.get(n + (60 * 11)))
|
||||
})
|
||||
val endState = fleshedOut.foldLeft(State()) {
|
||||
case (s, (_, al)) =>
|
||||
al.foldLeft(s)(_.step(_))
|
||||
}
|
||||
val days = endState.d
|
||||
println()
|
||||
val Day(_, Some(mostSleep), _) = days.maxBy(_.mins.count(!_.state))
|
||||
println(days.map(_.mins.size).mkString("\n"))
|
||||
val maxMinutes = days.map(_.mins.size).max
|
||||
val minutesToDays = days.map(_.mins.padTo(maxMinutes, Minute(true))).transpose
|
||||
val (_, mostConsistency) = minutesToDays.zipWithIndex.maxBy { case (l, _) => l.count(!_.state) }
|
||||
(mostSleep * mostConsistency).toString
|
||||
}
|
||||
|
||||
override def part2(input: String): String = ???
|
||||
|
||||
}
|
|
@ -6,6 +6,7 @@ package object y2018 extends Year {
|
|||
"1" -> Day01,
|
||||
"2" -> Day02,
|
||||
"3" -> Day03,
|
||||
"4" -> Day04,
|
||||
)
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue