Created
November 6, 2016 17:38
-
-
Save adambard/3665a80dd3c553f791ac14747e91b25c to your computer and use it in GitHub Desktop.
Stats on new Hearthstone discover cards
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import random | |
import numpy | |
from collections import namedtuple | |
## LOAD CARDS | |
with open("cards.collectible.json") as f: | |
cards = json.load(f) | |
cards = [c for c in cards if 'cost' in c and 'text' in c] | |
def filter_by_class(cards, cls): | |
return [c for c in cards if c['playerClass'] == cls] | |
GRIMY_GOONS = ("PALADIN", "WARRIOR", "HUNTER") | |
LOTUS_GANG = ("ROGUE", "DRUID", "SHAMAN") | |
POTION_GUYS = ("MAGE", "PRIEST", "WARLOCK") | |
PALADIN_CARDS = filter_by_class(cards, "PALADIN") | |
WARRIOR_CARDS = filter_by_class(cards, "WARRIOR") | |
HUNTER_CARDS = filter_by_class(cards, "HUNTER") | |
DRUID_CARDS = filter_by_class(cards, "DRUID") | |
ROGUE_CARDS = filter_by_class(cards, "ROGUE") | |
SHAMAN_CARDS = filter_by_class(cards, "SHAMAN") | |
MAGE_CARDS = filter_by_class(cards, "MAGE") | |
PRIEST_CARDS = filter_by_class(cards, "PRIEST") | |
WARLOCK_CARDS = filter_by_class(cards, "WARLOCK") | |
# Utils | |
def show_card(c): | |
return "[{cost}] {name}: {text}".format(**c) | |
class CardLog(object): | |
def __init__(self): | |
self.count = 0 | |
self.cost = [] | |
self.taunt = [] | |
self.spell = [] | |
self.tirion_count = 0 | |
def pick_card(cards, log=None): | |
c = random.choice(cards) | |
if log is not None: | |
log.count += 1 | |
log.cost.append(c['cost']) | |
if 'TAUNT' in c.get('mechanics', []): | |
log.taunt.append(c) | |
if c['type'] == 'SPELL': | |
log.spell.append(c) | |
if 'Tirion' in c['name']: | |
log.tirion_count += 1 | |
return c | |
def simulate_multiclass_discover(set1, set2, set3, log=None): | |
return (pick_card(set1, log), pick_card(set2, log), pick_card(set3, log)) | |
def run_simulation(set1, set2, set3, rounds=10000): | |
log = CardLog() | |
print("Sample choice: ") | |
a, b, c = simulate_multiclass_discover(set1, set2, set3, log=log) | |
print(show_card(a)) | |
print(show_card(b)) | |
print(show_card(c)) | |
for _ in range(rounds - 1): | |
simulate_multiclass_discover(set1, set2, set3, log=log) | |
return log | |
def print_log_report(log): | |
cost_mean = numpy.mean(log.cost) | |
cost_std = numpy.std(log.cost) | |
cost_pctile = ["%d" % p | |
for p in numpy.percentile(log.cost, range(10, 100, 10))] | |
taunt_count = len(log.taunt) | |
taunt_pct = 100 * taunt_count / log.count | |
spell_count = len(log.spell) | |
spell_pct = 100 * spell_count / log.count | |
tirion_pct = 100 * log.tirion_count / (log.count / 3) | |
print() | |
print("Simulation result: ") | |
print("Count: {} ({} rounds)".format(log.count, log.count // 3)) | |
print("Cost Avg, Std. Dev.: {:.2f}, {:.2f}".format(cost_mean, cost_std)) | |
print("Cost Percentiles (10, 20, 30, 40, 50, 60, 70, 80, 90): " + ", ".join(cost_pctile)) | |
print("Choices with taunt (%): {} ({:.2f})".format(taunt_count, taunt_pct)) | |
print("Proportion of spells (%): {} ({:.2f})".format(spell_count, spell_pct)) | |
if(log.tirion_count > 0): | |
print("Number of Tirions (%): {} ({})".format(log.tirion_count, tirion_pct)) | |
NUM_ROUNDS = 100000 | |
print("SIMULATING GRIMY GOONS") | |
print("======================") | |
print("") | |
print_log_report(run_simulation(PALADIN_CARDS, WARRIOR_CARDS, HUNTER_CARDS, rounds=NUM_ROUNDS)) | |
print("") | |
print("SIMULATING LOTUS GANG") | |
print("======================") | |
print("") | |
print_log_report(run_simulation(DRUID_CARDS, ROGUE_CARDS, SHAMAN_CARDS, rounds=NUM_ROUNDS)) | |
print("") | |
print("SIMULATING POTION GUYS") | |
print("======================") | |
print("") | |
print_log_report(run_simulation(MAGE_CARDS, PRIEST_CARDS, WARLOCK_CARDS, rounds=NUM_ROUNDS)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment