module Deckstrings
Public Class Methods
Decodes a Hearthstone deckstring into format, hero, and card counts.
This method validates the well-formedness of the deckstring and the embedded version, but does not validate the format, individual hero/card IDs, or card counts. For stricter validation and additional deck info, see {Deck.decode}.
All IDs refer to unique Hearthstone DBF IDs which can be used in conjunction with [HearthstoneJSON metadata](hearthstonejson.com/). @example
deck = Deckstrings::decode('AAEBAf0GAA/yAaIC3ALgBPcE+wWKBs4H2QexCMII2Q31DfoN9g4A')
@example
deck = Deckstrings::decode('AAECAZICCPIF+Az5DK6rAuC7ApS9AsnHApnTAgtAX/4BxAbkCLS7Asu8As+8At2+AqDNAofOAgA=')
@param deckstring [String] Base64-encoded Hearthstone deckstring. @raise [FormatError] If the deckstring is malformed or contains invalid deck data. @return [{ format: Integer, heroes: Array<Integer>, cards: Hash{Integer => Integer} }] Parsed Hearthstone deck details.
`heroes` is an array of hero IDs, but this will usually be just one element. `cards` is a Hash from card ID to its instance count in the deck.
@see Deck.decode
@see .encode @see hearthstonejson.com/ HearthstoneJSON
# File lib/deckstrings/deckstrings.rb, line 526 def self.decode(deckstring) if deckstring.nil? || deckstring.empty? raise FormatError, 'Invalid deckstring.' end stream = begin StringIO.new(Base64::strict_decode64(deckstring)) rescue ArgumentError raise FormatError, 'Invalid base64-encoded string.' end begin reserved = stream.read_varint if reserved != 0 raise FormatError, "Unexpected reserved byte: #{reserved}." end version = stream.read_varint if version != 1 raise FormatError, "Unexpected version: #{version}." end format = stream.read_varint # Heroes heroes = [] length = stream.read_varint length.times do heroes << stream.read_varint end # Cards cards = {} 1.upto(3) do |i| length = stream.read_varint length.times do card = stream.read_varint cards[card] = i < 3 ? i : stream.read_varint end end rescue EOFError raise FormatError, 'Unexpected end of data.' end return { format: format, heroes: heroes, cards: cards } end
Encodes a Hearthstone deck as a compact deckstring.
This method validates card counts, but does not validate the format or individual hero/card IDs. For stricter validation, see {Deck.encode}.
All IDs refer to unique Hearthstone DBF IDs which can be seen in [HearthstoneJSON metadata](hearthstonejson.com/). @example
deckstring = Deckstrings::encode(format: 2, heroes: [637], cards: { 1004 => 2, 315 => 2 })
@example
deckstring = Deckstrings::encode( format: Deckstrings::Format.standard, heroes: [Deckstrings::Hero.mage], cards: { 1004 => 2, 315 => 2 } )
@param format [Integer, Deckstrings::Format] Format
for this deck: wild or standard. @param heroes [Array<Integer, Deckstrings::Hero>] Heroes for this deck. Multiple heroes are supported, but typically
this array will contain one element.
@param cards [Hash{Integer, Deckstrings::Card
=> Integer}] Cards in the deck. A Hash from card ID to its instance count in the deck. @raise [FormatError] If any card counts are less than 1. @return [String] Base64-encoded compact byte string representing the deck. @see Deck.encode
@see .decode @see hearthstonejson.com/ HearthstoneJSON
# File lib/deckstrings/deckstrings.rb, line 471 def self.encode(format:, heroes:, cards:) stream = StringIO.new('') format = format.is_a?(Deckstrings::Format) ? format.value : format heroes = heroes.map { |hero| hero.is_a?(Deckstrings::Hero) ? hero.id : hero } # Reserved slot, version, and format. stream.write_varint(0) stream.write_varint(1) stream.write_varint(format) # Heroes. stream.write_varint(heroes.length) heroes.sort.each do |hero| stream.write_varint(hero) end # Cards. by_count = cards.group_by { |id, n| n > 2 ? 3 : n } invalid = by_count.keys.select { |count| count < 1 } unless invalid.empty? raise FormatError, "Invalid card count: #{invalid.join(', ')}." end 1.upto(3) do |count| group = by_count[count] || [] stream.write_varint(group.length) group.sort_by { |id, n| id }.each do |id, n| stream.write_varint(id) stream.write_varint(n) if n > 2 end end Base64::strict_encode64(stream.string).strip end