Skip to content

Commit

Permalink
Day 2 part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
horothesun committed Dec 2, 2024
1 parent 8135118 commit 998d5e0
Show file tree
Hide file tree
Showing 3 changed files with 1,081 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/main/scala/Day02.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Day02.Safety.*
import cats.data.NonEmptyList
import cats.syntax.all.*

object Day02:

case class Level(value: Int):
def differsFrom(min: Int, max: Int)(that: Level): Boolean =
Math.abs(value - that.value) >= min && Math.abs(value - that.value) <= max

object Level:

given Ordering[Level] = Ordering.by(_.value)

def parse(s: String): Option[Level] = s.toIntOption.map(Level.apply)

enum Safety:
case Safe, Unsafe

case class Report(levels: NonEmptyList[Level]):

def isAllIncreasing: Boolean = levels.toList == levels.toList.sorted
def isAllDecreasing: Boolean = levels.toList == levels.toList.sorted.reverse
def areAllDeltasBetween1And3: Boolean =
levels.toList.zip(levels.tail).forall((l, r) => l.differsFrom(min = 1, max = 3)(r))

def safety: Safety = if ((isAllIncreasing || isAllDecreasing) && areAllDeltasBetween1And3) Safe else Unsafe

object Report:
def parse(s: String): Option[Report] = s.split(' ').toList.traverse(Level.parse).flatMap(_.toNel.map(Report.apply))

def parse(input: List[String]): Option[List[Report]] = input.traverse(Report.parse)

def safetyCount(input: List[String]): Option[Int] =
parse(input).map(_.foldMap(_.safety match
case Safe => 1
case Unsafe => 0
))
43 changes: 43 additions & 0 deletions src/test/scala/Day02Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Day02.*
import Day02Suite.*
import cats.data.NonEmptyList
import munit.ScalaCheckSuite

class Day02Suite extends ScalaCheckSuite:

test("parsing small input"):
assertEquals(
parse(smallInput),
Some(
List(
NonEmptyList.of(7, 6, 4, 2, 1).map(Level.apply),
NonEmptyList.of(1, 2, 7, 8, 9).map(Level.apply),
NonEmptyList.of(9, 7, 6, 2, 1).map(Level.apply),
NonEmptyList.of(1, 3, 2, 4, 5).map(Level.apply),
NonEmptyList.of(8, 6, 4, 4, 1).map(Level.apply),
NonEmptyList.of(1, 3, 6, 7, 9).map(Level.apply)
).map(Report.apply)
)
)

test("parsing big input returns a proper reports list"):
assert(parse(bigInput).isDefined)

test("safety count for small input is 2"):
assertEquals(safetyCount(smallInput), Some(2))

test("safety count for big input is 490"):
assertEquals(safetyCount(bigInput), Some(490))

object Day02Suite:

val bigInput: List[String] = getLinesFromFile("src/test/scala/day02_input.txt")

val smallInput: List[String] = List(
"7 6 4 2 1",
"1 2 7 8 9",
"9 7 6 2 1",
"1 3 2 4 5",
"8 6 4 4 1",
"1 3 6 7 9"
)
Loading

0 comments on commit 998d5e0

Please sign in to comment.