I hate day 4 with a passion.

This commit is contained in:
Aly 2018-12-04 20:12:06 -08:00
parent d90152d660
commit 3a4b38f80f
No known key found for this signature in database
GPG Key ID: 555B7346639DDAC3
2 changed files with 169 additions and 0 deletions

View 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 = ???
}

View File

@ -6,6 +6,7 @@ package object y2018 extends Year {
"1" -> Day01,
"2" -> Day02,
"3" -> Day03,
"4" -> Day04,
)
}