Day 4
This commit is contained in:
parent
457f034d73
commit
20656e0e95
3 changed files with 73 additions and 1 deletions
|
@ -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
|
||||
|
|
72
core/src/main/scala/tf/bug/aoc/y2020/Day4.scala
Normal file
72
core/src/main/scala/tf/bug/aoc/y2020/Day4.scala
Normal 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)
|
||||
}
|
|
@ -7,4 +7,5 @@ object y2020 extends Year:
|
|||
1 -> Day1,
|
||||
2 -> Day2,
|
||||
3 -> Day3,
|
||||
4 -> Day4,
|
||||
)
|
||||
|
|
Loading…
Reference in a new issue