package tf.bug.aoc.y2020 import cats.effect._ import cats.syntax.all._ import fs2._ import scala.collection.SortedSet import tf.bug.aoc.Day object Day5 extends Day: case class Seat(row: Int, col: Int) { def id = row * 8 + col } object Seat { implicit val seatOrdering: Ordering[Seat] = Ordering.by(_.id) } override def part1[F[_]: Async]: Pipe[F, String, String] = (lines: Stream[F, String]) => { lines.through(seats[F]) .map(_.id) .fold1(_.max(_)) .map(_.show) } override def part2[F[_]: Async]: Pipe[F, String, String] = (lines: Stream[F, String]) => { val sortedSeats: F[SortedSet[Seat]] = lines.through(seats[F]) .compile.to(Collector.supportsFactory(SortedSet.evidenceIterableFactory[Seat])) val pairs: Stream[F, (Seat, Seat)] = Stream.eval(sortedSeats) .flatMap(seats => Stream.fromIterator[F](seats.sliding(2).map(set => (set.min, set.max)), 1)) val gaps: Stream[F, Int] = pairs.collect { case (a, b) if a.id + 1 == b.id - 1 => a.id + 1 } gaps.map(_.show) } def seats[F[_]: Async]: Pipe[F, String, Seat] = (lines: Stream[F, String]) => { lines .map { s => val (row, col) = s.splitAt(7) val rowN = row.zipWithIndex.foldLeft(0) { case (n, ('F', _)) => n case (n, ('B', i)) => val range = 1 << (6 - i) n + range } val colN = col.zipWithIndex.foldLeft(0) { case (n, ('L', _)) => n case (n, ('R', i)) => val range = 1 << (2 - i) n + range } Seat(rowN, colN) } }