package tf.bug.aoc import cats._ import cats.effect._ import cats.effect.std.Console import cats.syntax.all._ import java.nio.charset.StandardCharsets import fs2._ object Main extends IOApp { def years: Map[Int, Year] = Map( 2020 -> y2020.y2020, ) override def run(args: List[String]): IO[ExitCode] = { val year: IO[Year] = selectYear[IO] val day: IO[Day] = year >>= selectDay[IO] val part: IO[Pipe[IO, String, String]] = day >>= selectPart[IO] part.flatMap { p => io.stdinUtf8[IO](1024) .through(text.lines) .through(p) .through(io.stdoutLines(StandardCharsets.UTF_8)) .compile.drain }.as(ExitCode.Success) } def selectYear[F[_]: Monad: Console]: F[Year] = { val ask = Console[F].print("Select year: ") val receive = Console[F].readLine val year: F[Option[Year]] = (ask >> receive).map(_.toIntOption >>= years.get) year.flatMap { case Some(year) => year.pure[F] case None => selectYear[F] } } def selectDay[F[_]: Monad: Console](year: Year): F[Day] = { val ask = Console[F].print("Select day: ") val receive = Console[F].readLine val day: F[Option[Day]] = (ask >> receive).map(_.toIntOption >>= year.days.get) day.flatMap { case Some(day) => day.pure[F] case None => selectDay[F](year) } } def selectPart[F[_]: Async: Console](day: Day): F[Pipe[F, String, String]] = { val ask = Console[F].print("Select part: ") val receive = Console[F].readLine val part: F[Option[Int]] = (ask >> receive).map(_.toIntOption) part.flatMap { case Some(1) => day.part1[F].pure[F] case Some(2) => day.part2[F].pure[F] case _ => selectPart[F](day) } } }