Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # -*- coding: utf-8 -*-
- from collections import defaultdict, namedtuple
- from csv import DictReader
- from statistics import mean, StatisticsError
- COLLECTION_FILE = r"C:\Users\sqfky\Desktop\mtg_collection.txt"
- CURRENT_SETS = [
- "KHM",
- "ZNR",
- "M21",
- "IKO",
- "THB",
- "ELD",
- "M20",
- "WAR",
- "RNA",
- "GRN",
- "M19",
- "DOM",
- "RIX",
- "XLN",
- "AKR",
- "KLR",
- ]
- # ToDo: Expand this to filter out also rares/mythics you can't get from boosters
- # Other sides of MDFCs to filter out
- MDFC_OTHER = {
- # ZNR rares
- 'Boulderloft Pathway',
- 'Glasspool Shore',
- 'Grimclimb Pathway',
- 'Hagra Broodpit',
- 'Kazandu Valley',
- 'Lavaglide Pathway',
- 'Murkwater Pathway',
- 'Ondu Skyruins',
- 'Pillarverge Pathway',
- 'Timbercrown Pathway',
- 'Valakut Stoneforge',
- # ZNR mythics
- 'Agadeem, the Undercrypt',
- 'Emeria, Shattered Skyclave',
- 'Sea Gate, Reborn',
- 'Shatterskull, the Hammer Pass',
- 'Turntimber, Serpentine Wood',
- # KHM rares
- 'Harnfel, Horn of Bounty',
- 'Hengegate Pathway',
- 'Kaldring, the Rimestaff',
- 'Searstep Pathway',
- 'Slitherbore Pathway',
- "Tergrid's Lantern",
- 'The Omenkeel',
- 'The Ringhart Crest',
- 'Throne of Death',
- 'Tidechannel Pathway',
- "Valkmira, Protector's Shield",
- # KHM mythics
- 'Hakka, Whispering Raven',
- 'Sword of the Realms',
- 'The Prismatic Bridge',
- 'Tibalt, Cosmic Impostor',
- "Toralf's Hammer",
- }
- MISSING_FILE = r"C:\Users\sqfky\Desktop\mtg_missing.txt"
- # MISSING_FILE = r"C:\Users\sqfky\Desktop\mtg_missing_historic.txt"
- MissingCard = namedtuple("MissingCard", "name weight")
- def from_boosters(line):
- if line["Rarity"] in ["Uncommon", "Common"]:
- return False
- elif line["Set"] not in CURRENT_SETS:
- return False
- return True
- def mythic_chance(mtg_set):
- if mtg_set == "AKR":
- return 1 / 6
- elif mtg_set == "KLR":
- return 1 / 7
- elif mtg_set in ["M21",
- "IKO",
- "THB",
- "ELD",
- "M20",
- "WAR",
- "RNA",
- "GRN",
- "M19",
- "DOM",
- "RIX",
- "XLN",
- ]:
- return 1 / 8
- else:
- return 1 / 7.4
- class Collection:
- def __init__(self, collection_file, missing_file):
- # Set name as key into card names into amount, since we can have multiple sources of the name name of card
- self.collection = defaultdict(lambda: defaultdict(int))
- self.missing_cards = {}
- self._read_missing(missing_file)
- self._read_collection(collection_file)
- self._filter_collection()
- def _filter_collection(self):
- """
- Removes all cards we have 4 of already.
- Removes other sides from ZNR/KHM Modal Dual-Faced rare/mythic cards.
- Removes also the extra printings of the split cards.
- """
- for set_name, set_cards in self.collection.items():
- self.collection[set_name] = {
- card: amount for card, amount in set_cards.items() if amount < 4 and card.name not in MDFC_OTHER
- }
- for set_name, set_cards in self.collection.items():
- for missing_card in list(set_cards.keys()):
- if "//" in missing_card.name:
- split_start, split_end = missing_card.name.split(" // ")
- split_start.strip()
- split_end.strip()
- del set_cards[MissingCard(split_start, weight=0)]
- del set_cards[MissingCard(split_end, weight=0)]
- def _read_collection(self, collection_file):
- with open(collection_file, "r") as f:
- reader = DictReader(f, delimiter=",", quotechar='"')
- for line in reader:
- if not from_boosters(line):
- continue
- name = line["Name"]
- try:
- weight = self.missing_cards[name]
- except KeyError:
- weight = 0
- self.collection[f"{line['Set']}_{line['Rarity']}"][
- MissingCard(name=name, weight=weight)
- ] += int(line["Amount"])
- def _read_missing(self, missing_file):
- with open(missing_file, "r") as f:
- reader = DictReader(f, delimiter="\t", quotechar='"')
- for line in reader:
- if not from_boosters(line):
- continue
- avg_weight = int(line["Weight"].replace(",", "")) / int(line["Missing"])
- self.missing_cards[line["Card"]] = avg_weight
- def estimated_weights(self, debug=False):
- """
- Prints the estimated weights for boosters for each set taking into consideration
- that rares and mythics have different chances
- """
- booster_weights = {}
- for mtg_set in CURRENT_SETS:
- set_mythic_chance = mythic_chance(mtg_set=mtg_set)
- set_rare_chance = 1 - set_mythic_chance
- try:
- mean_rare_weight = mean(
- card.weight for card in self.collection[f"{mtg_set}_Rare"]
- )
- except StatisticsError:
- mean_rare_weight = 0
- try:
- mean_mythic_weight = mean(
- card.weight for card in self.collection[f"{mtg_set}_Mythic"]
- )
- except StatisticsError:
- mean_mythic_weight = 0
- booster_weights[mtg_set] = (
- set_rare_chance * mean_rare_weight
- + set_mythic_chance * mean_mythic_weight
- )
- for mtg_set, weight in sorted(
- booster_weights.items(), key=lambda x: x[1], reverse=True
- ):
- print(f"\n{mtg_set} avg weight is {weight:.0f}")
- good_rares = len(
- [card for card in self.collection[f"{mtg_set}_Rare"] if card.weight > 0]
- )
- bad_rares = len(
- [
- card
- for card in self.collection[f"{mtg_set}_Rare"]
- if card.weight == 0
- ]
- )
- good_mythics = len(
- [
- card
- for card in self.collection[f"{mtg_set}_Mythic"]
- if card.weight > 0
- ]
- )
- bad_mythics = len(
- [
- card
- for card in self.collection[f"{mtg_set}_Mythic"]
- if card.weight == 0
- ]
- )
- print(
- f"Unique cards left with nonzero weight: {good_rares} rares and {good_mythics} mythics"
- )
- print(
- f"Unique cards left with zero weight: {bad_rares} rares and {bad_mythics} mythics"
- )
- if debug:
- print("\nDebug info:")
- print("\nRares left:")
- for rare in self.collection[f"{mtg_set}_Rare"]:
- print(rare)
- print("\nMythics left:")
- for mythic in self.collection[f"{mtg_set}_Mythic"]:
- print(mythic)
- if __name__ == "__main__":
- collection = Collection(collection_file=COLLECTION_FILE, missing_file=MISSING_FILE)
- collection.estimated_weights(debug=False)
Add Comment
Please, Sign In to add comment