Skip to main content

14 posts tagged with "ZStream"

View All Tags

· One min read

My solution for https://adventofcode.com/2022/day/3

import zio.*
import zio.stream.*

object Day3 extends ZIOAppDefault {

val source: String => ZStream[Any, Throwable, String] =
fileName =>
ZStream
.fromFileName(fileName)
.via(ZPipeline.utfDecode >>> ZPipeline.splitLines)
.filter(_.nonEmpty)

// Indexes start at 0. Avoid an extra map by prepending an element, and taking the tail.
val priorities: Map[Char, Int] =
(('a' +: ('a' to 'z')) ++ ('A' to 'Z')).zipWithIndex.tail.toMap


val data = "day-3-1.data"
override def run: ZIO[Any, Any, Any] = for {
_ <- source(data)
.map(str => str.splitAt(str.length / 2)) // Split in two
.map { case (a, b) => a.intersect(b).head } // Elfs promised there would be only one
.map(k => priorities.getOrElse(k, throw new RuntimeException("hau ruck")))
.run(ZSink.sum)
.debug("Answer pt.1")
_ <- source(data)
.grouped(3) // Get it together, Elves!!!
.map(_.reduceLeft((a, b) => a.intersect(b)).head) // Elfs promised there would be only one
.map(k => priorities.getOrElse(k, throw new RuntimeException("hau ruck")))
.run(ZSink.sum)
.debug("Answer pt.2")
} yield Exit.Success

}

· 3 min read

My solution for https://adventofcode.com/2022/day/2

import zio.*
import zio.stream.*

object Day2 extends ZIOAppDefault {

sealed trait RPS
object RPS {

case object Rock extends RPS
case object Paper extends RPS
case object Scissors extends RPS

def apply(s: String): RPS = s match {
case "A" | "X" => Rock
case "B" | "Y" => Paper
case "C" | "Z" => Scissors
case _ => throw new RuntimeException("That's cheating!")
}

extension(rps: RPS) {
def losesTo: RPS = rps match {
case Rock => Paper
case Paper => Scissors
case Scissors => Rock
}
def winsAgainst = rps match {
case Rock => Scissors
case Paper => Rock
case Scissors => Paper
}
}

def score(a: RPS, b: RPS): Int = {
val choice = b match {
case Rock => 1
case Paper => 2
case Scissors => 3
}
val outcome = (a, b) match {
case (x, y) if x == y => 3 // Draw
case (x, Rock) if x == Scissors => 6 // Winner
case (x, Paper) if x == Rock => 6 // Winner
case (x, Scissors) if x == Paper => 6 // Chicken substitute dinner
case _ => 0 // If ya ain't first, yer last
}
// A refactor of outcome, after extension methods were added for part 2
val betterOutcome = (a, b) match {
case (x, y) if x == y => 3 // Draw
case (x, y) if x.losesTo == y => 6 // Winner
case _ => 0 // If ya ain't first, yer last
}
choice + betterOutcome
}

def throwTheGame(a: RPS, b: RPS): Int = (a, b) match {
case (x, Rock) => score(x, x.winsAgainst) // Need to lose
case (x, Paper) => score(x, x) // Need to tie
case (x, Scissors) => score(x, x.losesTo) // Need to win
}

}

val source: String => ZStream[Any, Throwable, String] =
fileName => ZStream.fromFileName(fileName).via(ZPipeline.utfDecode)

val pt1Pipeline: ZPipeline[Any, Nothing, String, Int] =
ZPipeline.splitLines >>>
ZPipeline.map[String, Int] { str =>
val arr = str.split(" ").map(RPS.apply)
RPS.score(arr.head, arr.last)
}

val pt2Pipeline: ZPipeline[Any, Nothing, String, Int] =
ZPipeline.splitLines >>>
ZPipeline.map[String, Int] { str =>
val arr = str.split(" ").map(RPS.apply)
RPS.throwTheGame(arr.head, arr.last)
}

val scoreSink: ZSink[Any, Nothing, Int, Nothing, Int] = ZSink.sum[Int]

val data = "day-2-1.data"
override def run: ZIO[Any, Any, Any] = for {
_ <- source(data)
.via(pt1Pipeline)
.run(scoreSink)
.debug("Answer pt.1")
_ <- source(data)
.via(pt2Pipeline)
.run(scoreSink)
.debug("Answer pt.2")
} yield ExitCode.success

}

· One min read

My solution for https://adventofcode.com/2022/day/1

import zio.*
import zio.stream.*

object Day1 extends ZIOAppDefault {

// Add a couple new lines so we don't have to collectLeftover
val source: String => ZStream[Any, Throwable, String] =
fileName =>
ZStream.fromFileName(fileName).via(ZPipeline.utfDecode) ++ ZStream("\n\n")

val pt1Pipeline: ZPipeline[Any, Nothing, String, Int] =
// Split by lines
ZPipeline.splitLines >>>
// group into Chunk[Chunk[_]] based on empty lines
ZPipeline
.mapAccum[String, Chunk[String], Chunk[String]] {
Chunk.empty
} { (state, elem) =>
if (elem.nonEmpty) (state :+ elem, Chunk.empty)
else (Chunk.empty, state)
}
//Get rid of empty Chunks
.filter(_.nonEmpty) >>>
// Add up the inner Chunk
ZPipeline.map[Chunk[String], Int](_.map(_.toInt).sum)

// Find the max
val pt1Sink: ZSink[Any, Nothing, Int, Nothing, Int] =
ZSink.collectAll[Int].map(_.max)

// Sum of biggest 3
val pt2Sink: ZSink[Any, Nothing, Int, Nothing, Int] =
ZSink.collectAll[Int].map(_.sortBy(-_).take(3).sum)

override def run: ZIO[Any, Any, Any] = for {
_ <- source("day-1-1.data")
.via(pt1Pipeline)
.run(pt1Sink)
.debug("Answer pt.1")
_ <- source("day-1-1.data")
.via(pt1Pipeline)
.run(pt2Sink)
.debug("Answer pt.2")
} yield ExitCode.success

}