Day 6
This commit is contained in:
parent
5dde3b6445
commit
ba564dc7e1
10 changed files with 66 additions and 15 deletions
|
@ -4,6 +4,7 @@ import cats._
|
||||||
import cats.effect._
|
import cats.effect._
|
||||||
import fs2._
|
import fs2._
|
||||||
|
|
||||||
trait Day:
|
trait Day {
|
||||||
def part1[F[_]: Async]: Pipe[F, String, String]
|
def part1[F[_]: Async]: Pipe[F, String, String]
|
||||||
def part2[F[_]: Async]: Pipe[F, String, String]
|
def part2[F[_]: Async]: Pipe[F, String, String]
|
||||||
|
}
|
||||||
|
|
|
@ -7,13 +7,13 @@ import cats.syntax.all._
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
import fs2._
|
import fs2._
|
||||||
|
|
||||||
object Main extends IOApp:
|
object Main extends IOApp {
|
||||||
|
|
||||||
def years: Map[Int, Year] = Map(
|
def years: Map[Int, Year] = Map(
|
||||||
2020 -> y2020.y2020,
|
2020 -> y2020.y2020,
|
||||||
)
|
)
|
||||||
|
|
||||||
override def run(args: List[String]): IO[ExitCode] =
|
override def run(args: List[String]): IO[ExitCode] = {
|
||||||
val year: IO[Year] = selectYear[IO]
|
val year: IO[Year] = selectYear[IO]
|
||||||
val day: IO[Day] = year >>= selectDay[IO]
|
val day: IO[Day] = year >>= selectDay[IO]
|
||||||
val part: IO[Pipe[IO, String, String]] = day >>= selectPart[IO]
|
val part: IO[Pipe[IO, String, String]] = day >>= selectPart[IO]
|
||||||
|
@ -24,8 +24,9 @@ object Main extends IOApp:
|
||||||
.through(io.stdoutLines(StandardCharsets.UTF_8))
|
.through(io.stdoutLines(StandardCharsets.UTF_8))
|
||||||
.compile.drain
|
.compile.drain
|
||||||
}.as(ExitCode.Success)
|
}.as(ExitCode.Success)
|
||||||
|
}
|
||||||
|
|
||||||
def selectYear[F[_]: Monad: Console]: F[Year] =
|
def selectYear[F[_]: Monad: Console]: F[Year] = {
|
||||||
val ask = Console[F].print("Select year: ")
|
val ask = Console[F].print("Select year: ")
|
||||||
val receive = Console[F].readLine
|
val receive = Console[F].readLine
|
||||||
val year: F[Option[Year]] = (ask >> receive).map(_.toIntOption >>= years.get)
|
val year: F[Option[Year]] = (ask >> receive).map(_.toIntOption >>= years.get)
|
||||||
|
@ -33,8 +34,9 @@ object Main extends IOApp:
|
||||||
case Some(year) => year.pure[F]
|
case Some(year) => year.pure[F]
|
||||||
case None => selectYear[F]
|
case None => selectYear[F]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def selectDay[F[_]: Monad: Console](year: Year): F[Day] =
|
def selectDay[F[_]: Monad: Console](year: Year): F[Day] = {
|
||||||
val ask = Console[F].print("Select day: ")
|
val ask = Console[F].print("Select day: ")
|
||||||
val receive = Console[F].readLine
|
val receive = Console[F].readLine
|
||||||
val day: F[Option[Day]] = (ask >> receive).map(_.toIntOption >>= year.days.get)
|
val day: F[Option[Day]] = (ask >> receive).map(_.toIntOption >>= year.days.get)
|
||||||
|
@ -42,8 +44,9 @@ object Main extends IOApp:
|
||||||
case Some(day) => day.pure[F]
|
case Some(day) => day.pure[F]
|
||||||
case None => selectDay[F](year)
|
case None => selectDay[F](year)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def selectPart[F[_]: Async: Console](day: Day): F[Pipe[F, String, String]] =
|
def selectPart[F[_]: Async: Console](day: Day): F[Pipe[F, String, String]] = {
|
||||||
val ask = Console[F].print("Select part: ")
|
val ask = Console[F].print("Select part: ")
|
||||||
val receive = Console[F].readLine
|
val receive = Console[F].readLine
|
||||||
val part: F[Option[Int]] = (ask >> receive).map(_.toIntOption)
|
val part: F[Option[Int]] = (ask >> receive).map(_.toIntOption)
|
||||||
|
@ -52,3 +55,6 @@ object Main extends IOApp:
|
||||||
case Some(2) => day.part2[F].pure[F]
|
case Some(2) => day.part2[F].pure[F]
|
||||||
case _ => selectPart[F](day)
|
case _ => selectPart[F](day)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package tf.bug.aoc
|
package tf.bug.aoc
|
||||||
|
|
||||||
trait Year:
|
trait Year {
|
||||||
def days: Map[Int, Day]
|
def days: Map[Int, Day]
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets
|
||||||
import scala.util.Try
|
import scala.util.Try
|
||||||
import tf.bug.aoc.Day
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
object Day1 extends Day:
|
object Day1 extends Day {
|
||||||
|
|
||||||
override def part1[F[_]: Async]: Pipe[F, String, String] =
|
override def part1[F[_]: Async]: Pipe[F, String, String] =
|
||||||
parts[F](2)
|
parts[F](2)
|
||||||
|
@ -29,3 +29,5 @@ object Day1 extends Day:
|
||||||
ints.combinations(num).collectFirst {
|
ints.combinations(num).collectFirst {
|
||||||
case v if v.sum == target => v.product
|
case v if v.sum == target => v.product
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import cats.syntax.all._
|
||||||
import fs2._
|
import fs2._
|
||||||
import tf.bug.aoc.Day
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
object Day2 extends Day:
|
object Day2 extends Day {
|
||||||
|
|
||||||
case class Policy(min: Int, max: Int, letter: Char)
|
case class Policy(min: Int, max: Int, letter: Char)
|
||||||
case class Entry(policy: Policy, password: String)
|
case class Entry(policy: Policy, password: String)
|
||||||
|
@ -45,3 +45,5 @@ object Day2 extends Day:
|
||||||
.foldMap(ent => if(validation(ent)) 1 else 0)
|
.foldMap(ent => if(validation(ent)) 1 else 0)
|
||||||
.map(_.show)
|
.map(_.show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import cats.syntax.all._
|
||||||
import fs2._
|
import fs2._
|
||||||
import tf.bug.aoc.Day
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
object Day3 extends Day:
|
object Day3 extends Day {
|
||||||
|
|
||||||
case class Path(x: Int, treeCount: Long)
|
case class Path(x: Int, treeCount: Long)
|
||||||
|
|
||||||
|
@ -44,3 +44,5 @@ object Day3 extends Day:
|
||||||
}
|
}
|
||||||
}.map(_.treeCount)
|
}.map(_.treeCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import cats.syntax.all._
|
||||||
import fs2._
|
import fs2._
|
||||||
import tf.bug.aoc.Day
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
object Day4 extends Day:
|
object Day4 extends Day {
|
||||||
|
|
||||||
val whitespace: Parser1[Unit] = P.charIn(" ").void
|
val whitespace: Parser1[Unit] = P.charIn(" ").void
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ object Day4 extends Day:
|
||||||
|
|
||||||
val parseMap: P[Map[String, String]] = (P.repSep(parseEntry, min = 0, sep = whitespace) <* P.until(P.end)).map(_.toMap)
|
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] =
|
override def part1[F[_]: Async]: Pipe[F, String, String] = {
|
||||||
val requiredKeys = Set(
|
val requiredKeys = Set(
|
||||||
"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"
|
"byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"
|
||||||
)
|
)
|
||||||
|
@ -25,8 +25,9 @@ object Day4 extends Day:
|
||||||
val keySet = m.keySet
|
val keySet = m.keySet
|
||||||
requiredKeys.forall(keySet.contains)
|
requiredKeys.forall(keySet.contains)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override def part2[F[_]: Async]: Pipe[F, String, String] =
|
override def part2[F[_]: Async]: Pipe[F, String, String] = {
|
||||||
val hexChar: P[Unit] = P.charIn(('0' to '9') ++ ('a' to 'f')).void
|
val hexChar: P[Unit] = P.charIn(('0' to '9') ++ ('a' to 'f')).void
|
||||||
val validateColor: P[Unit] = P.char('#') *> hexChar.replicateA(6).void
|
val validateColor: P[Unit] = P.char('#') *> hexChar.replicateA(6).void
|
||||||
val eyeColors: Set[String] = Set(
|
val eyeColors: Set[String] = Set(
|
||||||
|
@ -56,6 +57,7 @@ object Day4 extends Day:
|
||||||
lazy val validPid = m.get("pid").fold(false)(validatePid.parseAll(_).isRight)
|
lazy val validPid = m.get("pid").fold(false)(validatePid.parseAll(_).isRight)
|
||||||
validByr && validIyr && validEyr && validHgt && validHcl && validEcl && validPid
|
validByr && validIyr && validEyr && validHgt && validHcl && validEcl && validPid
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def parts[F[_]: Async](validator: Map[String, String] => Boolean): Pipe[F, String, String] =
|
def parts[F[_]: Async](validator: Map[String, String] => Boolean): Pipe[F, String, String] =
|
||||||
(lines: Stream[F, String]) => {
|
(lines: Stream[F, String]) => {
|
||||||
|
@ -70,3 +72,5 @@ object Day4 extends Day:
|
||||||
.foldMap(if(_) 1 else 0)
|
.foldMap(if(_) 1 else 0)
|
||||||
.map(_.show)
|
.map(_.show)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import fs2._
|
||||||
import scala.collection.SortedSet
|
import scala.collection.SortedSet
|
||||||
import tf.bug.aoc.Day
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
object Day5 extends Day:
|
object Day5 extends Day {
|
||||||
|
|
||||||
override def part1[F[_]: Async]: Pipe[F, String, String] =
|
override def part1[F[_]: Async]: Pipe[F, String, String] =
|
||||||
(lines: Stream[F, String]) => {
|
(lines: Stream[F, String]) => {
|
||||||
|
@ -44,3 +44,5 @@ object Day5 extends Day:
|
||||||
val newBit = ((ch & 4) >>> 2) ^ 1
|
val newBit = ((ch & 4) >>> 2) ^ 1
|
||||||
(id * 2) + newBit
|
(id * 2) + newBit
|
||||||
})
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
27
core/src/main/scala/tf/bug/aoc/y2020/Day6.scala
Normal file
27
core/src/main/scala/tf/bug/aoc/y2020/Day6.scala
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package tf.bug.aoc.y2020
|
||||||
|
|
||||||
|
import cats.effect._
|
||||||
|
import cats.syntax.all._
|
||||||
|
import fs2._
|
||||||
|
import tf.bug.aoc.Day
|
||||||
|
|
||||||
|
object Day6 extends Day {
|
||||||
|
|
||||||
|
override def part1[F[_]: Async]: Pipe[F, String, String] =
|
||||||
|
parts(_ | _)
|
||||||
|
|
||||||
|
override def part2[F[_]: Async]: Pipe[F, String, String] =
|
||||||
|
parts(_ & _)
|
||||||
|
|
||||||
|
def parts[F[_]: Async](reduction: (Set[Char], Set[Char]) => Set[Char]): Pipe[F, String, String] =
|
||||||
|
(lines: Stream[F, String]) => {
|
||||||
|
lines.groupAdjacentBy(_.nonEmpty).collect {
|
||||||
|
case (true, strings) =>
|
||||||
|
strings
|
||||||
|
.map(_.toSet)
|
||||||
|
.reduceLeftOption(reduction)
|
||||||
|
.getOrElse(Set.empty[Char])
|
||||||
|
}.map(_.size).foldMonoid.map(_.show)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,11 +2,15 @@ package tf.bug.aoc.y2020
|
||||||
|
|
||||||
import tf.bug.aoc.{Day, Year}
|
import tf.bug.aoc.{Day, Year}
|
||||||
|
|
||||||
object y2020 extends Year:
|
object y2020 extends Year {
|
||||||
|
|
||||||
override def days: Map[Int, Day] = Map(
|
override def days: Map[Int, Day] = Map(
|
||||||
1 -> Day1,
|
1 -> Day1,
|
||||||
2 -> Day2,
|
2 -> Day2,
|
||||||
3 -> Day3,
|
3 -> Day3,
|
||||||
4 -> Day4,
|
4 -> Day4,
|
||||||
5 -> Day5,
|
5 -> Day5,
|
||||||
|
6 -> Day6,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue