Skip to content

Instantly share code, notes, and snippets.

@adambard
Created November 6, 2016 17:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adambard/3665a80dd3c553f791ac14747e91b25c to your computer and use it in GitHub Desktop.
Save adambard/3665a80dd3c553f791ac14747e91b25c to your computer and use it in GitHub Desktop.
Stats on new Hearthstone discover cards
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