Skip to main content

Advent of Code - Day 2

· 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

}