Skip to content

Commit

Permalink
feat: 2015 day 16
Browse files Browse the repository at this point in the history
  • Loading branch information
scarf005 committed Sep 22, 2024
1 parent f9587b7 commit 3ddc301
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 0 deletions.
66 changes: 66 additions & 0 deletions 2015/day16.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package y2015.day16

import prelude.*

import cats.parse.Parser
import cats.parse.Parser.*
import cats.parse.Rfc5234.{digit, alpha}

type Clue = Map[String, Int]

val number: Parser[Int] =
digit.rep.string.map(_.toInt)

val ident: Parser[String] =
alpha.rep.string

val id: Parser[Int] =
string("Sue ") *> number <* string(": ")

val clue: Parser[(String, Int)] =
(ident <* string(": ")) ~ number

val clues: Parser[Clue] =
clue.repSep(string(", ")).map(_.toList.toMap)

val aunt: Parser[Aunt] =
(id ~ clues).map { (id, clues) => Aunt(id, clues) }

case class Aunt(id: Int, info: Clue):
def matchEq(known: Clue): Boolean =
zipAllByKey(info, known).values.forall { (a, b) => a == b }

def matchRange(known: Clue): Boolean =
zipAllByKey(info, known).forall {
case (k, v) if Set("cats", "trees") contains k => v._1 > v._2
case (k, v) if Set("pomeranians", "goldfish") contains k => v._1 < v._2
case (k, v) => v._1 == v._2
}

val known = Map(
"children" -> 3,
"cats" -> 7,
"samoyeds" -> 2,
"pomeranians" -> 3,
"akitas" -> 0,
"vizslas" -> 0,
"goldfish" -> 5,
"trees" -> 3,
"cars" -> 2,
"perfumes" -> 1,
)

def part1(xs: Iterable[Aunt]) =
xs.find(_.matchEq(known)).get.id

def part2(xs: Iterable[Aunt]) =
xs.find(_.matchRange(known)).get.id

@main def main() =
val input = fromFile(".cache/2015/16.txt").getLines
.map(_.trim)
.flatMap(aunt.parseAll)
.toSeq

println(part1(input))
println(part2(input))
61 changes: 61 additions & 0 deletions 2015/day16.test.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package y2015.day16

import prelude.*
import munit.FunSuite
import y2015.day16.*

val auntRight = Aunt(1, Map("goldfish" -> 9, "cars" -> 0, "samoyeds" -> 9))
val auntEmpty = Aunt(1, Map.empty)

class ParserTests extends FunSuite:
assertEquals(
aunt.parseAll("Sue 1: goldfish: 9, cars: 0, samoyeds: 9"),
Right(auntRight),
)

class MatchEqTests extends FunSuite:
val clue = Map("goldfish" -> 9, "cars" -> 0, "samoyeds" -> 9)

test("empty"):
assertEquals(auntEmpty.matchEq(clue), true)

test("matches"):
assertEquals(auntRight.matchEq(clue), true)

test("mismatches"):
assertEquals(auntRight.matchEq(clue + ("goldfish" -> 10)), false)

test("unknown clue"):
assertEquals(auntRight.matchEq(clue + ("unknown" -> 10)), true)

class MatchRangeTests extends FunSuite:
val auntRight =
Aunt(1, Map("cats" -> 6, "trees" -> 6, "pomeranians" -> 4, "goldfish" -> 4))

val clue =
Map("cats" -> 5, "trees" -> 5, "pomeranians" -> 5, "goldfish" -> 5)

test("empty"):
assertEquals(auntEmpty.matchRange(clue), true)

test("matches"):
assertEquals(auntRight.matchRange(clue), true)

test("cats"):
assertEquals(auntRight.matchRange(clue + ("cats" -> 10)), false)
assertEquals(auntRight.matchRange(clue + ("cats" -> 5)), true)

test("trees"):
assertEquals(auntRight.matchRange(clue + ("trees" -> 10)), false)
assertEquals(auntRight.matchRange(clue + ("trees" -> 5)), true)

test("pomeranians"):
assertEquals(auntRight.matchRange(clue + ("pomeranians" -> 10)), true)
assertEquals(auntRight.matchRange(clue + ("pomeranians" -> 4)), false)

test("goldfish"):
assertEquals(auntRight.matchRange(clue + ("goldfish" -> 10)), true)
assertEquals(auntRight.matchRange(clue + ("goldfish" -> 4)), false)

test("unknown clue"):
assertEquals(auntRight.matchRange(clue + ("unknown" -> 10)), true)

0 comments on commit 3ddc301

Please sign in to comment.