From 457f034d739217b83896d18ff79d4649072b6da4 Mon Sep 17 00:00:00 2001 From: Aly Date: Fri, 4 Dec 2020 17:26:20 -0800 Subject: [PATCH] Day 3 --- core/src/main/scala/tf/bug/aoc/Day.scala | 4 +- core/src/main/scala/tf/bug/aoc/Main.scala | 13 +++--- .../main/scala/tf/bug/aoc/y2020/Day1.scala | 4 +- .../main/scala/tf/bug/aoc/y2020/Day2.scala | 4 +- .../main/scala/tf/bug/aoc/y2020/Day3.scala | 46 +++++++++++++++++++ .../main/scala/tf/bug/aoc/y2020/y2020.scala | 1 + 6 files changed, 60 insertions(+), 12 deletions(-) create mode 100644 core/src/main/scala/tf/bug/aoc/y2020/Day3.scala diff --git a/core/src/main/scala/tf/bug/aoc/Day.scala b/core/src/main/scala/tf/bug/aoc/Day.scala index 8c0172a..4de0dce 100644 --- a/core/src/main/scala/tf/bug/aoc/Day.scala +++ b/core/src/main/scala/tf/bug/aoc/Day.scala @@ -5,5 +5,5 @@ import cats.effect._ import fs2._ trait Day: - def part1[F[_]: Sync]: Pipe[F, String, String] - def part2[F[_]: Sync]: Pipe[F, String, String] + def part1[F[_]: Async]: Pipe[F, String, String] + def part2[F[_]: Async]: Pipe[F, String, String] diff --git a/core/src/main/scala/tf/bug/aoc/Main.scala b/core/src/main/scala/tf/bug/aoc/Main.scala index 0fa6754..827527b 100644 --- a/core/src/main/scala/tf/bug/aoc/Main.scala +++ b/core/src/main/scala/tf/bug/aoc/Main.scala @@ -1,5 +1,6 @@ package tf.bug.aoc +import cats._ import cats.effect._ import cats.effect.std.Console import cats.syntax.all._ @@ -25,8 +26,8 @@ object Main extends IOApp: .compile.drain }.as(ExitCode.Success) - def selectYear[F[_]: Sync: Console]: F[Year] = - val ask = Sync[F].delay(print("Select year: ")) + 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 { @@ -34,8 +35,8 @@ object Main extends IOApp: case None => selectYear[F] } - def selectDay[F[_]: Sync: Console](year: Year): F[Day] = - val ask = Sync[F].delay(print("Select day: ")) + 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 { @@ -43,8 +44,8 @@ object Main extends IOApp: case None => selectDay[F](year) } - def selectPart[F[_]: Sync: Console](day: Day): F[Pipe[F, String, String]] = - val ask = Sync[F].delay(print("Select part: ")) + 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 { diff --git a/core/src/main/scala/tf/bug/aoc/y2020/Day1.scala b/core/src/main/scala/tf/bug/aoc/y2020/Day1.scala index 84ca07b..f5b2320 100644 --- a/core/src/main/scala/tf/bug/aoc/y2020/Day1.scala +++ b/core/src/main/scala/tf/bug/aoc/y2020/Day1.scala @@ -10,10 +10,10 @@ import tf.bug.aoc.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) - override def part2[F[_]: Sync]: Pipe[F, String, String] = + override def part2[F[_]: Async]: Pipe[F, String, String] = parts[F](3) def parts[F[_]: Sync](nums: Int): Pipe[F, String, String] = diff --git a/core/src/main/scala/tf/bug/aoc/y2020/Day2.scala b/core/src/main/scala/tf/bug/aoc/y2020/Day2.scala index a747041..9e027ac 100644 --- a/core/src/main/scala/tf/bug/aoc/y2020/Day2.scala +++ b/core/src/main/scala/tf/bug/aoc/y2020/Day2.scala @@ -23,13 +23,13 @@ object Day2 extends Day: Entry(policy, password) } - override def part1[F[_]: Sync]: Pipe[F, String, String] = + override def part1[F[_]: Async]: Pipe[F, String, String] = parts[F] { ent => val charCount = ent.password.count(_ == ent.policy.letter) 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 => 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 diff --git a/core/src/main/scala/tf/bug/aoc/y2020/Day3.scala b/core/src/main/scala/tf/bug/aoc/y2020/Day3.scala new file mode 100644 index 0000000..230d17f --- /dev/null +++ b/core/src/main/scala/tf/bug/aoc/y2020/Day3.scala @@ -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) + } diff --git a/core/src/main/scala/tf/bug/aoc/y2020/y2020.scala b/core/src/main/scala/tf/bug/aoc/y2020/y2020.scala index d28850c..72315a9 100644 --- a/core/src/main/scala/tf/bug/aoc/y2020/y2020.scala +++ b/core/src/main/scala/tf/bug/aoc/y2020/y2020.scala @@ -6,4 +6,5 @@ object y2020 extends Year: override def days: Map[Int, Day] = Map( 1 -> Day1, 2 -> Day2, + 3 -> Day3, )