All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fordeckmacia.Deck.scala Maven / Gradle / Ivy

The newest version!
package fordeckmacia

import scodec.bits.BitVector
import scodec.codecs._
import scodec.{Attempt, Codec, Err}
import shapeless.{::, HNil}

case class Deck(cards: Map[Card, Int]) {

  def encode: Attempt[String] = Deck.encode(this)

  def cardList: List[Card]    = cards.toList.flatMap { case (card, count) => List.fill(count)(card) }
  def codeList: List[String]  = cardList.map(_.code)
  def codes: Map[String, Int] = cards.map { case (card, count) => (card.code, count) }
}

object Deck {
  def decode(code: String): Attempt[Deck] =
    Attempt.fromEither(BitVector.fromBase32Descriptive(code.toUpperCase).left.map(Err.apply)).flatMap(codec.complete.decodeValue)

  def encode(deck: Deck): Attempt[String] =
    codec.encode(deck).map(_.toBase32.takeWhile(_ != '='))

  def fromCards(cards: List[Card]): Deck =
    Deck(cards.groupBy(card => card).map { case (card, cards) => (card, cards.size) })

  val supportedFormat     = 1.toByte
  val maxSupportedVersion = 4.toByte

  def codec: Codec[Deck] =
    (prefixCodec :: Card.cardsOf1To3Codec :: Card.cardsOf1To3Codec :: Card.cardsOf1To3Codec :: Card.cardsOf4PlusCodec).xmapc {
      case _ :: cardsOf3 :: cardsOf2 :: cardsOf1 :: cardsOf4Plus :: HNil =>
        def toMap[A](set: Set[A], count: Int): Map[A, Int] = set.map(_ -> count).toMap
        Deck(toMap(cardsOf3, 3) ++ toMap(cardsOf2, 2) ++ toMap(cardsOf1, 1) ++ cardsOf4Plus)
    } { deck =>
      def cardsOfCount[A](map: Map[A, Int], count: Int): Set[A] = map.filter(_._2 == count).keySet
      def cardsOf4Plus[A](map: Map[A, Int]): Map[A, Int]        = map.filter(_._2 >= 4)
      calculateVersion(deck) :: cardsOfCount(deck.cards, 3) :: cardsOfCount(deck.cards, 2) :: cardsOfCount(deck.cards, 1) :: cardsOf4Plus(deck.cards) :: HNil
    }

  private[this] val prefixCodec: Codec[Byte] = (ubyte(4) :: ubyte(4)).narrowc { case format :: version :: HNil =>
    Attempt.guard(format == supportedFormat && version <= maxSupportedVersion, Err(unsupportedVersion(version))).map(_ => version)
  }(version => supportedFormat :: version :: HNil)

  private[this] def calculateVersion(deck: Deck): Byte = {
    val versions = deck.cards.keys.map(_.faction).map(versionsForFactions)
    if (versions.isEmpty) 1 else versions.max
  }

  private[this] val versionsForFactions: Faction => Byte = {
    case Faction.Demacia         => 1
    case Faction.Freljord        => 1
    case Faction.Ionia           => 1
    case Faction.Noxus           => 1
    case Faction.PiltoverAndZaun => 1
    case Faction.ShadowIsles     => 1
    case Faction.Bilgewater      => 2
    case Faction.MountTargon     => 2
    case Faction.Shurima         => 3
    case Faction.BandleCity      => 4
  }

  private[this] def unsupportedVersion(version: Byte) =
    s"Unsupported deckcode version or format: $version. Please update ForDeckmacia or create an Issue/PR if there isn't a newer version"
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy