79 lines
2 KiB
Scala
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
|