aoc2023/Day7.scala
2023-12-07 11:57:37 +01:00

79 lines
2 KiB
Scala

package aoc.day7
import aoc._
val possibleCards = "AKQJT98765432".reverse
enum DeckKind:
case High
case Pair
case Pairs
case Three
case House
case Four
case Five
object DeckKind:
def apply(deck: String) =
val counts =
deck.iterator.toSeq.groupBy(identity).values.map(_.length).toSeq
if counts.contains(5) then Five
else if counts.contains(4) then Four
else if counts.contains(3) then if counts.contains(2) then House else Three
else if counts.count(_ == 2) == 2 then Pairs
else if counts.contains(2) then Pair
else High
import DeckKind._
case class Hand(deck: String, bet: Int):
def deckRank(using cardToRank: Map[Char, Int]) = deck.map(cardToRank(_))
val kind = DeckKind(deck)
lazy val bestKind =
possibleCards
.map(c => deck.replace('J', c))
.map(DeckKind(_))
.maxBy(_.ordinal)
inline def nonZero(ins: Int*) = ins.find(_ != 0).getOrElse(0)
object Parser extends CommonParser:
val deck = (s"[${possibleCards}]{5}").r
val hand = deck ~ num ^^ { case (deck ~ num) => Hand(deck, num) }
def apply(s: String) =
parse(hand, s).get
// part 1
def handOrdering(toKind: Hand => DeckKind)(using cardOrdering: Map[Char, Int]) =
new Ordering[Hand]:
override def compare(dx: Hand, dy: Hand): Int =
val (x, y) = (toKind(dx), toKind(dy))
if x.ordinal != y.ordinal then x.ordinal.compareTo(y.ordinal)
else nonZero(dx.deckRank.zip(dy.deckRank).map(_ compareTo _)*)
def print(using Ordering[Hand]) =
val hands = lines.map(Parser(_)).toSeq
val res =
hands.sorted.zipWithIndex
.map((h, idx) => h.bet * (idx + 1L))
.sum
println(res)
def part1 =
val ordering = possibleCards.zipWithIndex.toMap
val handOrd = handOrdering(_.kind)(using ordering)
print(using handOrd)
// part 2
def part2 =
val ordering = "J23456789TQKA".zipWithIndex.toMap
val handOrd = handOrdering(_.bestKind)(using ordering)
print(using handOrd)
@main def Day7(part: Int) = part match
case 1 => part1
case 2 => part2