This commit is contained in:
Aly 2020-12-04 19:41:21 -08:00
parent 457f034d73
commit 20656e0e95
3 changed files with 73 additions and 1 deletions

View file

@ -20,7 +20,6 @@ object Main extends IOApp:
part.flatMap { p =>
io.stdinUtf8[IO](1024)
.through(text.lines)
.takeWhile(_.nonEmpty)
.through(p)
.through(io.stdoutLines(StandardCharsets.UTF_8))
.compile.drain

View file

@ -0,0 +1,72 @@
package tf.bug.aoc.y2020
import cats.effect._
import cats.parse.{Parser => P, Parser1, Numbers}
import cats.syntax.all._
import fs2._
import tf.bug.aoc.Day
object Day4 extends Day:
val whitespace: Parser1[Unit] = P.charIn(" ").void
val parseEntry: Parser1[(String, String)] = (P.length1(3), P.char(':'), P.until1(whitespace)).mapN {
case (key, (), value) =>
key -> value
}
val parseMap: P[Map[String, String]] = (P.repSep(parseEntry, min = 0, sep = whitespace) <* P.until(P.end)).map(_.toMap)
override def part1[F[_]: Async]: Pipe[F, String, String] =
val requiredKeys = Set(
"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"
)
parts { m =>
val keySet = m.keySet
requiredKeys.forall(keySet.contains)
}
override def part2[F[_]: Async]: Pipe[F, String, String] =
val hexChar: P[Unit] = P.charIn(('0' to '9') ++ ('a' to 'f')).void
val validateColor: P[Unit] = P.char('#') *> hexChar.replicateA(6).void
val eyeColors: Set[String] = Set(
"amb",
"blu",
"brn",
"gry",
"grn",
"hzl",
"oth",
)
val pidChar: P[Unit] = Numbers.digit.void
val validatePid: P[Unit] = pidChar.replicateA(9).void
parts { m =>
lazy val validByr = m.get("byr").flatMap(_.toIntOption).fold(false)(x => 1920 <= x && x <= 2002)
lazy val validIyr = m.get("iyr").flatMap(_.toIntOption).fold(false)(x => 2010 <= x && x <= 2020)
lazy val validEyr = m.get("eyr").flatMap(_.toIntOption).fold(false)(x => 2020 <= x && x <= 2030)
lazy val validHgt = m.get("hgt").fold(false) {
case s"${hgtCm}cm" =>
hgtCm.toIntOption.fold(false)(x => 150 <= x && x <= 193)
case s"${hgtIn}in" =>
hgtIn.toIntOption.fold(false)(x => 59 <= x && x <= 76)
case _ => false
}
lazy val validHcl = m.get("hcl").fold(false)(validateColor.parseAll(_).isRight)
lazy val validEcl = m.get("ecl").fold(false)(eyeColors.contains)
lazy val validPid = m.get("pid").fold(false)(validatePid.parseAll(_).isRight)
validByr && validIyr && validEyr && validHgt && validHcl && validEcl && validPid
}
def parts[F[_]: Async](validator: Map[String, String] => Boolean): Pipe[F, String, String] =
(lines: Stream[F, String]) => {
val passportStrings: Stream[F, String] = lines.groupAdjacentBy(_.nonEmpty).collect {
case (true, strings) => strings.mkString_(" ")
}
val passportMaps: Stream[F, Map[String, String]] = passportStrings.map(parseMap.parseAll).collect {
case Right(map) => map
}
passportMaps
.map(validator)
.foldMap(if(_) 1 else 0)
.map(_.show)
}

View file

@ -7,4 +7,5 @@ object y2020 extends Year:
1 -> Day1,
2 -> Day2,
3 -> Day3,
4 -> Day4,
)