This commit is contained in:
Aly 2020-12-04 17:26:20 -08:00
parent b9bf5023eb
commit 457f034d73
6 changed files with 60 additions and 12 deletions

View file

@ -5,5 +5,5 @@ import cats.effect._
import fs2._ import fs2._
trait Day: trait Day:
def part1[F[_]: Sync]: Pipe[F, String, String] def part1[F[_]: Async]: Pipe[F, String, String]
def part2[F[_]: Sync]: Pipe[F, String, String] def part2[F[_]: Async]: Pipe[F, String, String]

View file

@ -1,5 +1,6 @@
package tf.bug.aoc package tf.bug.aoc
import cats._
import cats.effect._ import cats.effect._
import cats.effect.std.Console import cats.effect.std.Console
import cats.syntax.all._ import cats.syntax.all._
@ -25,8 +26,8 @@ object Main extends IOApp:
.compile.drain .compile.drain
}.as(ExitCode.Success) }.as(ExitCode.Success)
def selectYear[F[_]: Sync: Console]: F[Year] = def selectYear[F[_]: Monad: Console]: F[Year] =
val ask = Sync[F].delay(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)
year.flatMap { year.flatMap {
@ -34,8 +35,8 @@ object Main extends IOApp:
case None => selectYear[F] case None => selectYear[F]
} }
def selectDay[F[_]: Sync: Console](year: Year): F[Day] = def selectDay[F[_]: Monad: Console](year: Year): F[Day] =
val ask = Sync[F].delay(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)
day.flatMap { day.flatMap {
@ -43,8 +44,8 @@ object Main extends IOApp:
case None => selectDay[F](year) case None => selectDay[F](year)
} }
def selectPart[F[_]: Sync: Console](day: Day): F[Pipe[F, String, String]] = def selectPart[F[_]: Async: Console](day: Day): F[Pipe[F, String, String]] =
val ask = Sync[F].delay(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)
part.flatMap { part.flatMap {

View file

@ -10,10 +10,10 @@ import tf.bug.aoc.Day
object Day1 extends Day: object Day1 extends Day:
override def part1[F[_]: Sync]: Pipe[F, String, String] = override def part1[F[_]: Async]: Pipe[F, String, String] =
parts[F](2) parts[F](2)
override def part2[F[_]: Sync]: Pipe[F, String, String] = override def part2[F[_]: Async]: Pipe[F, String, String] =
parts[F](3) parts[F](3)
def parts[F[_]: Sync](nums: Int): Pipe[F, String, String] = def parts[F[_]: Sync](nums: Int): Pipe[F, String, String] =

View file

@ -23,13 +23,13 @@ object Day2 extends Day:
Entry(policy, password) Entry(policy, password)
} }
override def part1[F[_]: Sync]: Pipe[F, String, String] = override def part1[F[_]: Async]: Pipe[F, String, String] =
parts[F] { ent => parts[F] { ent =>
val charCount = ent.password.count(_ == ent.policy.letter) val charCount = ent.password.count(_ == ent.policy.letter)
ent.policy.min <= charCount && charCount <= ent.policy.max ent.policy.min <= charCount && charCount <= ent.policy.max
} }
override def part2[F[_]: Sync]: Pipe[F, String, String] = override def part2[F[_]: Async]: Pipe[F, String, String] =
parts[F] { ent => parts[F] { ent =>
val a = ent.policy.min <= ent.password.length && ent.password.charAt(ent.policy.min - 1) == ent.policy.letter val a = ent.policy.min <= ent.password.length && ent.password.charAt(ent.policy.min - 1) == ent.policy.letter
val b = ent.policy.max <= ent.password.length && ent.password.charAt(ent.policy.max - 1) == ent.policy.letter val b = ent.policy.max <= ent.password.length && ent.password.charAt(ent.policy.max - 1) == ent.policy.letter

View file

@ -0,0 +1,46 @@
package tf.bug.aoc.y2020
import cats.effect._
import cats.syntax.all._
import fs2._
import tf.bug.aoc.Day
object Day3 extends Day:
case class Path(x: Int, treeCount: Long)
override def part1[F[_]: Async]: Pipe[F, String, String] =
_.through(checkSlope[F](3, 1)).map(_.show)
override def part2[F[_]: Async]: Pipe[F, String, String] =
(lines: Stream[F, String]) => {
val pipes: Vector[Pipe[F, String, Long]] = Vector(
checkSlope[F](1, 1),
checkSlope[F](3, 1),
checkSlope[F](5, 1),
checkSlope[F](7, 1),
checkSlope[F](1, 2),
)
val broadcast: Stream[F, String] => Stream[F, Stream[F, String]] = concurrent.Broadcast[F, String](pipes.size)
val channels: Stream[F, Stream[F, String]] = lines.through(broadcast).take(pipes.size)
val results: Stream[F, Long] = channels.zipWithIndex.map {
case (channel, ind) =>
val pipe = pipes(ind.toInt)
channel.through(pipe)
}.parJoin(pipes.size)
results.fold(1L)(_ * _).map(_.show)
}
def checkSlope[F[_]](right: Int, down: Int): Pipe[F, String, Long] =
(lines: Stream[F, String]) => {
lines.chunkN(down, true).fold(Path(0, 0L)) {
case (Path(x, numTrees), group) =>
group.head match {
case Some(line) =>
val isTree = line.charAt(x % line.length) == '#'
Path(x + right, if(isTree) numTrees + 1L else numTrees)
case None =>
Path(x, numTrees)
}
}.map(_.treeCount)
}

View file

@ -6,4 +6,5 @@ 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,
) )