repl.it
@anonymous/

GrotesqueCreativeInitialization

Python

No description

fork
loading
Files
  • main.py
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import decimal

# Helper method to save on typing
def d(num):
    return decimal.Decimal(num)

def getNumber(msg):
    print(msg)
    try:
        return int(input(" > "))
    except EOFError:
        return getNumber(msg)
    except ValueError:
        print("That's not a number!")
        return getNumber(msg)

# Return the odds of a single draw *not* being one of the desired cards.
def singleDrawMissChance(copies, drawnSoFar):
    return d(1) - (copies / d(38 - drawnSoFar))

# Return the odds of N draws, starting with a certain number of cards drawn so far, not being any of the desired cards.
def nDrawMissChance(copies, drawnSoFar, numDraws):
    result = d(1)
    for i in range(0, numDraws):
        result = result * singleDrawMissChance(copies, drawnSoFar + i)
    
    return result

# Return the odds of a single turn cycle - one replace and one draw - not being any of the desired cards.
# The replace doesn't make the deck any smaller, so drawnSoFar doesn't help.
def turnCycleMissChance(copies, drawnSoFar):
    return singleDrawMissChance(copies, drawnSoFar) * singleDrawMissChance(copies, drawnSoFar)

# Return the odds that the desired cards are *not* drawn in the opening hand.
# Five draws + two replaces, with no restriction on which cards can come back.
# Both replaced cards are replaced at once, as far as I'm aware. This means one of them uses drawnSoFar=3
# and the other uses drawnSoFar=4.
def mulliganOdds(copies):
    return nDrawMissChance(copies, 0, 5) * singleDrawMissChance(copies, 3) * singleDrawMissChance(copies, 4)

def main():
    print("### How lucky is your Wanderer opponent? ###")

    copies = getNumber("How many copies of the effect they need are in the deck?")
    turn = getNumber("What turn did they need to draw it by?")

    # Use Decimals for precision.
    copies = d(copies)

    # Accumulate the result. Start with an opening hand, then (turn - 1) turns, and a final replace.
    missChance = mulliganOdds(copies)
    # We draw one card from the deck per turn, on top of the five we removed during the opening hand.
    # So on turn 1 we've already drawn 5 cards, by turn 2 we've drawn 6, etc.
    drawnSoFar = 5
    for i in range(1, turn):
        missChance *= turnCycleMissChance(copies, drawnSoFar)
        drawnSoFar += 1
    
    # On the pivotal turn, there's another replace to resolve.
    missChance *= singleDrawMissChance(copies, drawnSoFar)

    # We now have the chance of failing to draw the needed card for the entire game up to this point.
    # Invert it to get the result we need.
    result = d(1) - missChance
    percentage = 100 * result

    print("Your opponent had a {0:.2f}% chance of getting what they needed.".format(percentage))
    if result >= 0.5:
        print("You should have played around it!")
    else:
        print("Yeah, they're a lucky scrub. Go ahead and flame them in chat.")

if __name__ == "__main__":
    main()
?