class RuneterraCards::CardSet

Represents a collection of cards.

@todo The API to this class is very unstable and will change a lot in a coming release. @todo add #== !

Constants

HIGH_BIT

Extract this bitmask so Mutant can't see it, until this fix is released github.com/mbj/mutant/pull/1218

Attributes

cards[R]

@return [Hash{String => Number}] @deprecated

Public Class Methods

from_deck_code(deck_code) click to toggle source

Parse a Deck Code. @param deck_code [String] @raise [Base32Error] if the deck code cannot be Base32 decoded. @raise [UnrecognizedVersionError] if the deck code's version is not supported by this library

(see {SUPPORTED_VERSION}).

@raise [EmptyInputError] if the deck code is an empty string. @return [CardSet]

# File lib/runeterra_cards/card_set.rb, line 65
def self.from_deck_code(deck_code)
  binary_data = decode_base32(deck_code)
  format, version = decode_format_and_version(binary_data[0])

  raise UnrecognizedVersionError.new(SUPPORTED_VERSION, version) unless version <= SUPPORTED_VERSION

  raise unless format.equal? 1

  int_array = unpack_big_endian_varint(binary_data[1..])
  cards = assemble_card_list(int_array)

  new(cards.to_h)
end
new(cards) click to toggle source

@param [Hash{String => Number},Enumerable{String => Number}] cards A Hash of card codes mapping to card counts

# File lib/runeterra_cards/card_set.rb, line 20
def initialize(cards)
  @cards = cards
end

Private Class Methods

assemble_card_list(array) click to toggle source

@param [Array<Fixnum>] array @return [Array<Card>]

# File lib/runeterra_cards/card_set.rb, line 106
def self.assemble_card_list(array)
  3.downto(1).flat_map do |number_of_copies|
    set_faction_combination_count = array.shift
    set_faction_combination_count.times.flat_map do
      number_of_cards, set, faction = array.shift(3)

      array.shift(number_of_cards).map do |card_number|
        cac = Card.new(set: set, faction_number: faction, card_number: card_number)
        [cac.code, number_of_copies]
      end
    end
  end
end
decode_base32(string) click to toggle source

@param string [String] base32-encoded string @return [String] binary data

# File lib/runeterra_cards/card_set.rb, line 81
def self.decode_base32(string)
  raise EmptyInputError if string.empty?

  begin
    Base32.decode(string)
  rescue StandardError
    raise Base32Error
  end
end
decode_format_and_version(byte) click to toggle source

@param byte [String] a single byte @return [FixNum] format and version, in that order

# File lib/runeterra_cards/card_set.rb, line 95
def self.decode_format_and_version(byte)
  format_and_version = byte.unpack1('C')
  format = format_and_version >> 4
  version = format_and_version & 0xF
  [format, version]
end
unpack_big_endian_varint(binary) click to toggle source

@param [String] binary @return [Enumerable<Fixnum>]

# File lib/runeterra_cards/card_set.rb, line 124
def self.unpack_big_endian_varint(binary)
  binary.each_byte.slice_after { |b| (b & HIGH_BIT).zero? }.map do |int_bytes|
    acc = 0
    int_bytes.each_with_index do |byte, index|
      acc += (byte & 0b0111_1111) << (7 * index)
    end
    acc
  end
end

Public Instance Methods

-(other) click to toggle source

Subtract another {CardSet CardSet} from this one. Items with count 0 are not represented in the returned {CardSet CardSet}, they are removed altogether. @param [CardSet] other An object that responds to {#count_for_card_code} @return [CardSet]

# File lib/runeterra_cards/card_set.rb, line 28
def -(other)
  remaining_cards =
    cards.each_with_object({}) do |(code, count), result|
      new_count = count - other.count_for_card_code(code)
      result[code] = new_count unless new_count.equal?(0)
    end

  CardSet.new(remaining_cards)
end
as_card_codes() click to toggle source

Return all cards in the card set as a map of card codes to counts. @example

set.as_card_codes #=> { '01DE044' => 1, '02NX003' => 2 }

@return [Enumerable<String => Number>]

# File lib/runeterra_cards/card_set.rb, line 47
def as_card_codes
  cards
end
as_cards() click to toggle source

@return [Enumerable<Card => Number>]

# File lib/runeterra_cards/card_set.rb, line 39
def as_cards
  cards.transform_keys { |code| Card.new(code: code) }
end
count_for_card_code(code) click to toggle source

Returns how many of the given card are in this CardSet. @param [String] code Card code, e.g. “01DE031” @return [Integer] How many of the card are in this CardSet, or 0 if it isn't present.

# File lib/runeterra_cards/card_set.rb, line 54
def count_for_card_code(code)
  cards[code] || 0
end