Skip to content

MaxHalford/zugzug

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

3 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

zugzug

This is a little framework to answer statistical questions related to Hearthstone. Things started when I wrote an analysis that gathered some interest on reddit. I then looked into doing some more analysis but noticed that I was doing a lot of copy/pasting. I then decided to write some helpers to avoid repeating myself and make less mistakes.

Many Hearthstone questions can probably be answered with exact formulas. However, that may involve brain power that you might want to invest elsewhere. An alternative solution is to approach the exact answer by running multiple simulations and aggregating the results. Essentially, zugzug is a tool that helps you perform so-called Monte Carlo experiments. The user provides a simulation function, which takes various parameters as inputs and outputs a number. Then, the user calls zugzug's run function and specifies a grid of parameters. The results are then aggregated and displayed in a table.

Various utilities such as cards, conditions, and game mechanisms are implemented in zugzug to help out writing simulation functions. These utilities are implemented on an as-needed basis. Therefore, not all of them are available. However, new features and specific requests are more than welcome to be discussed. Likewise, the API is highly succeptible to change.

Installation

pip install git+https://github.com/MaxHalford/zugzug

Examples

What is the probability of having a 1 mana card at the first turn?

We first import zugzug.

>>> import zugzug as zz

Reproducibility can be enforced by fixing the global random number generator.

>>> import random
>>> random.seed(42)

For this analysis, we're not interested in any card in particular. Instead, we are interested by the mana cost of each cost. We can thus define two kinds of cards, one that costs 1 mana and 1 that costs 2 mana.

>>> one_mana_card = zz.cards.Card(name='1 Mana Card', mana=1)
>>> two_mana_card = zz.cards.Card(name='2 Mana Card', mana=2)

Let us now define a simulation function. One parameter will determine one many 1 mana cards are in the deck, whilst the other will indicate if we're looking for 1 mana cards during the mulligan phase or not. The details of the simulation are influenced by these two parameters. We'll output a boolean value which tells whether or not a 1 mana card is in hand.

>>> def sim(n_ones, mulligan):
...
...     # Create a deck with 1 and 2 mana cards
...     deck = [one_mana_card] * n_ones + [two_mana_card] * (30 - n_ones)
...
...     # Indicate that we want to fish for 1 mana cards during the mulligan phase
...     wishlist = [one_mana_card] * 3 if mulligan else []
...     game = zz.Game(deck, wishlist=wishlist)
...
...     # Go to the first turn
...     game.next_turn()
...
...     return one_mana_card in game.hand

We may now call the run function by providing it with the simulation function. We'll also choose how many repetitions we want to do and a set of values for each parameter. The rest is taken care by zugzug.

>>> results = zz.run(sim, n=1000, n_ones=range(1, 7), mulligan=[False, True])
>>> print(results)
╒══════════╀════════════╀═══════════╀════════╀══════════╕
β”‚   n_ones β”‚ mulligan   β”‚    median β”‚   mean β”‚    stdev β”‚
β•žβ•β•β•β•β•β•β•β•β•β•β•ͺ════════════β•ͺ═══════════β•ͺ════════β•ͺ══════════║
β”‚        1 β”‚ False      β”‚ 0.0733945 β”‚  0.128 β”‚ 0.334257 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        1 β”‚ True       β”‚ 0.15445   β”‚  0.236 β”‚ 0.424835 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        2 β”‚ False      β”‚ 0.171141  β”‚  0.255 β”‚ 0.436079 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        2 β”‚ True       β”‚ 0.33612   β”‚  0.402 β”‚ 0.490547 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        3 β”‚ False      β”‚ 0.293651  β”‚  0.37  β”‚ 0.483046 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        3 β”‚ True       β”‚ 0.595841  β”‚  0.553 β”‚ 0.497432 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        4 β”‚ False      β”‚ 0.402527  β”‚  0.446 β”‚ 0.497324 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        4 β”‚ True       β”‚ 0.760355  β”‚  0.676 β”‚ 0.468234 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        5 β”‚ False      β”‚ 0.589253  β”‚  0.549 β”‚ 0.497842 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        5 β”‚ True       β”‚ 0.826146  β”‚  0.742 β”‚ 0.437753 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        6 β”‚ False      β”‚ 0.702552  β”‚  0.627 β”‚ 0.483844 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚        6 β”‚ True       β”‚ 0.87578   β”‚  0.801 β”‚ 0.399448 β”‚
β•˜β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•›

How much mana does Frizz Kindleroost save?

Summoning Frizz Kindleroot reduces the mana cost of each dragon in the deck by 2. To measure how much mana this saves on average, we can run a simulation where the turns go by as long as Frizz is not in hand. We can do this by calling game.play_until with the zz.conditions.Playable(frizz) condition.

>>> import random
>>> import zugzug as zz

>>> random.seed(42)

>>> dragon = zz.cards.Minion(name='Dragon', mana=None, race=zz.races.DRAGON)
>>> frizz = zz.cards.FrizzKindleroost()

>>> def sim(mulligan, n_dragons):
...
...     deck = [frizz] + [dragon] * n_dragons
...     deck = deck + [zz.cards.Wisp()] * (30 - len(deck))
...     game = zz.Game(deck, wishlist=[frizz] if mulligan else [])
...
...     game.play_until(zz.conditions.Playable(frizz))
...
...     return sum(2 for card in game.deck if card == dragon)

>>> results = zz.run(sim, n=1000, mulligan=[False, True], n_dragons=[2, 4, 6, 8, 10, 12])
>>> print(results)
╒════════════╀═════════════╀══════════╀════════╀═════════╕
β”‚ mulligan   β”‚   n_dragons β”‚   median β”‚   mean β”‚   stdev β”‚
β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•ͺ═════════════β•ͺ══════════β•ͺ════════β•ͺ═════════║
β”‚ False      β”‚           2 β”‚  1.93236 β”‚  1.898 β”‚ 1.5761  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ False      β”‚           4 β”‚  3.90851 β”‚  3.7   β”‚ 2.6178  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ False      β”‚           6 β”‚  5.98276 β”‚  5.728 β”‚ 3.76034 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ False      β”‚           8 β”‚  8.03237 β”‚  7.678 β”‚ 4.73653 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ False      β”‚          10 β”‚ 10.1261  β”‚  9.72  β”‚ 5.68805 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ False      β”‚          12 β”‚ 12.0412  β”‚ 11.724 β”‚ 6.57381 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚           2 β”‚  2.02603 β”‚  2.038 β”‚ 1.59408 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚           4 β”‚  4.07219 β”‚  3.948 β”‚ 2.79376 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚           6 β”‚  6.28    β”‚  6.12  β”‚ 3.74802 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚           8 β”‚  9.52564 β”‚  8.224 β”‚ 4.74514 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚          10 β”‚ 11.5612  β”‚ 10.298 β”‚ 5.81214 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ True       β”‚          12 β”‚ 13.8684  β”‚ 12.224 β”‚ 6.94997 β”‚
β•˜β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•›

How long does it take to get Zixor Prime in hand?

This was the first analysis I did. You can see the code I used in this gist. Using zugzug reduces the amount of necessary of code and helps a bit with readability. It also helped me gain trust in my analysis by delegating the game mechanics to zugzug.

This simulation is a bit more verbose than the previous ones because their are two first phases involved. First of all we need to wait that Zixor is in hand. Then, once Zixor's deathrattle has triggered, we have to wait to draw Zixor Prime. The goal of this analysis is to study the impact of draw cards such as Diving Gryphon, Scavenger's Ingenuity, and Tracking.

>>> import random
>>> import zugzug as zz

>>> random.seed(42)

>>> zixor = zz.cards.Zixor()
>>> zixor_prime = zz.cards.ZixorPrime()
>>> gryphon = zz.cards.DivingGryphon()
>>> si = zz.cards.ScavengersIngenuity()
>>> tracking = zz.cards.Tracking(zixor_prime, zixor, si, gryphon)
>>> tracking.wishlist.append(tracking)
>>> wisp = zz.cards.Wisp()

>>> playlist = [si, gryphon, tracking]
>>> wishlist = [zixor, si, gryphon, tracking]

>>> def sim(n_gryphons, n_si, n_tracking):
...
...     deck = (
...         [zixor] +
...         [gryphon] * n_gryphons +
...         [si] * n_si +
...         [tracking] * n_tracking +
...         [wisp] * (30 - 1 - n_gryphons - n_si - n_tracking)
...     )
...     game = zz.Game(deck, wishlist=wishlist, playlist=playlist)
...
...     # Play until Zixor is playable
...     game.play_until(zz.conditions.Playable(zixor))
...
...     # Assume it takes 0 to 2 turns to get Zixor killed
...     for _ in range(random.randint(0, 2)):
...         game.next_turn()
...
...     # Insert Zixor Prime into the deck once Zixor's deathrattle triggers
...     game.play_card(zixor)
...
...     # Wait until Zixor Prime is playable
...     game.play_until(zz.conditions.Playable(zixor_prime))
...
...     return game.turn

>>> results = zz.run(
...     sim, n=1000,
...     n_gryphons=[0, 1, 2],
...     n_si=[0, 1, 2],
...     n_tracking=[0, 1, 2]
... )
>>> print(results)
╒══════════════╀════════╀══════════════╀══════════╀════════╀═════════╕
β”‚   n_gryphons β”‚   n_si β”‚   n_tracking β”‚   median β”‚   mean β”‚   stdev β”‚
β•žβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•ͺ════════β•ͺ══════════════β•ͺ══════════β•ͺ════════β•ͺ═════════║
β”‚            0 β”‚      0 β”‚            0 β”‚ 22.7881  β”‚ 21     β”‚ 6.45024 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      0 β”‚            1 β”‚ 19.7245  β”‚ 18.687 β”‚ 5.65376 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      0 β”‚            2 β”‚ 17.959   β”‚ 16.835 β”‚ 4.97056 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      1 β”‚            0 β”‚ 16.3727  β”‚ 16.652 β”‚ 6.19462 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      1 β”‚            1 β”‚ 15.2869  β”‚ 15.328 β”‚ 5.3125  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      1 β”‚            2 β”‚ 13.6     β”‚ 13.836 β”‚ 4.43517 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      2 β”‚            0 β”‚ 11.4167  β”‚ 12.864 β”‚ 4.98481 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      2 β”‚            1 β”‚ 10.7182  β”‚ 12.204 β”‚ 4.35814 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            0 β”‚      2 β”‚            2 β”‚  9.76364 β”‚ 11.118 β”‚ 3.61623 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      0 β”‚            0 β”‚ 16.5435  β”‚ 16.481 β”‚ 6.1929  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      0 β”‚            1 β”‚ 15.1866  β”‚ 15.239 β”‚ 5.34588 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      0 β”‚            2 β”‚ 13.0821  β”‚ 13.556 β”‚ 4.74694 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      1 β”‚            0 β”‚ 11.4     β”‚ 13.165 β”‚ 5.41434 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      1 β”‚            1 β”‚ 10.7222  β”‚ 12.243 β”‚ 4.57109 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      1 β”‚            2 β”‚  9.48864 β”‚ 11.186 β”‚ 3.80866 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      2 β”‚            0 β”‚  8.91096 β”‚ 10.991 β”‚ 4.01036 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      2 β”‚            1 β”‚  8.47466 β”‚ 10.254 β”‚ 3.19683 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            1 β”‚      2 β”‚            2 β”‚  8.35616 β”‚  9.604 β”‚ 2.60845 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      0 β”‚            0 β”‚ 11.8519  β”‚ 13.515 β”‚ 5.63556 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      0 β”‚            1 β”‚ 11.1833  β”‚ 12.664 β”‚ 4.79897 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      0 β”‚            2 β”‚  9.51818 β”‚ 11.342 β”‚ 3.88692 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      1 β”‚            0 β”‚  9.30172 β”‚ 11.208 β”‚ 4.12065 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      1 β”‚            1 β”‚  8.75954 β”‚ 10.536 β”‚ 3.56559 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      1 β”‚            2 β”‚  8.47466 β”‚  9.96  β”‚ 2.95112 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      2 β”‚            0 β”‚  8.4311  β”‚  9.948 β”‚ 3.02795 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      2 β”‚            1 β”‚  8.33056 β”‚  9.391 β”‚ 2.44256 β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚            2 β”‚      2 β”‚            2 β”‚  8.28616 β”‚  9.138 β”‚ 2.1353  β”‚
β•˜β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•§β•β•β•β•β•β•β•β•β•β•›

What is the likelihood of having Scalerider in hand without a dragon?

To do.

Development

I don't expect anyone else to use this code but you never know. Here are the steps you'll want to follow:

$ python3 -m venv .
$ source ./bin/activate
$ pip install -e ".[dev]"
$ python3 setup.py develop

You can run tests with pytest and mypy.

License

Licensed under the WTFPL.

About

πŸ‘Ή Monte Carlo experiments for Hearthstone

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages