# I, the copyright holder of this work, release this work into the public domain. This applies worldwide.
#
# In some countries this may not be legally possible; if so:
# I grant anyone the right to use this work for any purpose, without any conditions, unless such conditions are required by law.
# Version 0.0.4
import sys
import random
misses = 0.0
# Return the value of an attack, given a base attack value, the card drawn, the deck of remaining cards and the discard pile.
# Also returns the deck with the card removed and all the discarded cards, including the card being considered.
def cardValue(base, card, deck, discard):
global misses
discard.append(card)
if card == '0':
return base
elif card == '+1':
return base + 1
elif card == '-1':
return base - 1
elif card == '+2':
return base + 2
elif card == '-2':
return base - 2
elif card == 'MISS':
misses += 1
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return 0
elif card == 'CURSE':
misses += 1
return 0
elif card == '2x':
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return 2*base
elif card == 'BLESS':
return 2*base
elif card == 'R+1':
card2 = deck.pop()
return cardValue(base+1,card2,deck,discard)
elif card == 'R+0':
card2 = deck.pop()
return cardValue(base,card2,deck,discard)
else:
raise ValueError
# Return the value of an attack with advantage, given a base attack value, the cards drawn, the deck of remaining cards and the
# discard pile. Also returns the deck with the cards removed and all the discarded cards, including the cards being considered.
def advantageValue(base,card1, card2, deck, discard):
if card1 == 'R+1':
discard.append(card1)
return cardValue(base+1,card2,deck,discard)
elif card2 == 'R+1':
discard.append(card2)
return cardValue(base+1,card1,deck,discard)
if card1 == 'R+0':
discard.append(card1)
return cardValue(base,card2,deck,discard)
elif card2 == 'R+0':
discard.append(card2)
return cardValue(base,card1,deck,discard)
elif card1 == 'MISS':
discard.append(card1)
cv = cardValue(base,card2,deck,discard)
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return cv
elif card2 == 'MISS':
discard.append(card2)
cv = cardValue(base,card1,deck,discard)
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return cv
elif card1 == 'CURSE':
discard.append(card1)
cv = cardValue(base,card2,deck,discard)
return cv
elif card2 == 'CURSE':
discard.append(card2)
cv = cardValue(base,card1,deck,discard)
return cv
discard.append(card1)
discard.append(card2)
assert len(deck)+len(discard) == len(amd)
if card1 == '2x' or card2 == '2x':
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return 2*base
elif card1 == 'BLESS' or card2 == 'BLESS':
return 2*base
elif card1 == '+2' or card2 == '+2':
return 2+base
elif card1 == '+1' or card2 == '+1':
return 1+base
elif card1 == '0' or card2 == '0':
return base
elif card1 == '-1' or card2 == '-1':
return base - 1
assert card1 == '-2' or card2 == '-2'
return base - 2
# Return the value of an attack with disadvantage, given a base attack value, the cards drawn, the deck of remaining cards and the
# discard pile. Also returns the deck with the cards removed and all the discarded cards, including the cards being considered.
def disadvantageValue(base,card1, card2, deck, discard):
global misses
if card1 == 'MISS' or card2 == 'MISS':
discard.append(card1)
discard.append(card2)
misses += 1
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
return 0
if card1 == 'CURSE' or card2 == 'CURSE':
discard.append(card1)
discard.append(card2)
# We still need to shuffle if the 2nd card is a 2x, even without using it
if card1 == '2x' or card2 == '2x':
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
misses += 1
return 0
elif card1 == 'R+1':
discard.append(card1)
return cardValue(base+1,card2,deck,discard)
elif card2 == 'R+1':
discard.append(card2)
return cardValue(base+1,card1,deck,discard)
if card1 == 'R+0':
discard.append(card1)
return cardValue(base,card2,deck,discard)
elif card2 == 'R+0':
discard.append(card2)
return cardValue(base,card1,deck,discard)
discard.append(card1)
discard.append(card2)
# Even if we don't use the 'x2', we still need to reshuffle
if card1 == '2x' or card2 == '2x':
deck += discard
random.shuffle(deck)
assert len(deck) == len(amd)
discard[:] = []
assert len(deck)+len(discard) == len(amd)
if card1 == '-2' or card2 == '-2':
return base - 2
elif card1 == '-1' or card2 == '-1':
return base - 1
elif card1 == '0' or card2 == '0':
return base
elif card1 == '+1' or card2 == '+1':
return 1+base
elif card1 == '+2' or card2 == '+2':
return 2+base
# You need either one 2x and one bless or 2 bless
assert (card1 == '2x' or 'BLESS') and (card2 == '2x' or 'BLESS')
return 2*base
# Given an attack modifier deck, amd, determine the average attack value with and without advantage.
# Optionally takes a base attack value, defaulting to 3 if none is provided.
def calculateAverageAttack(amd, base = None, normal = True, advantage = False, disadvantage = False):
global misses
if base is None:
base = 3
deck = list(amd)
random.shuffle(deck)
discard = []
count = 1000000
# Run without advantage or disadvantage
if normal == True:
total = 0.0 # A running total of the all "damage" calculated
misses = 0.0
for x in range(0,count):
card = deck.pop()
total = total + cardValue(base, card, deck, discard)
print ("Average attack: ", (total / count)) # the average attack value
print ("Miss frequency: ", (misses/count)) # percent of attacks that pull a null or curse
# Run with advantage
if advantage == True:
# reset
total = 0.0
misses = 0.0
deck += discard
random.shuffle(deck)
discard[:] = []
for x in range(0,count):
card1 = deck.pop()
card2 = deck.pop()
total = total + advantageValue(base, card1,card2, deck,discard);
print ("Average attack with advantage: ",total / count) # the average attack value
print ("Miss frequency: ", misses/count) # percent of attacks that pull a null or curse
# Run with disadvantage
if disadvantage == True:
# reset
total = 0.0
misses = 0.0
deck += discard
random.shuffle(deck)
discard[:] = []
for x in range(0,count):
card1 = deck.pop()
card2 = deck.pop()
total = total + disadvantageValue(base, card1, card2, deck, discard);
print ("Average attack with disadvantage: ",total / count) # the average attack value
print ("Miss frequency: ", misses/count) # percent of attacks that pull a null or curse
# Basic attack deck
amd = ['0','0','0','0','0','0','+1','+1','+1','+1','+1','-1','-1','-1','-1','-1','-2','+2','MISS','2x']
print (" Base attack deck")
print (amd)
calculateAverageAttack(amd, advantage = True, disadvantage = True)
# Fully cursed deck
amd = ['0','0','0','0','0','0','+1','+1','+1','+1','+1','-1','-1','-1','-1','-1','-2','+2','MISS','2x','CURSE','CURSE','CURSE','CURSE','CURSE','CURSE','CURSE','CURSE','CURSE','CURSE']
print (" Ten curses")
print (amd)
calculateAverageAttack(amd, disadvantage = True)
# Out of curiosity, the difference between curse and miss
amd = ['0','0','0','0','0','0','+1','+1','+1','+1','+1','-1','-1','-1','-1','-1','-2','+2','MISS','2x','MISS','MISS','MISS','MISS','MISS','MISS','MISS','MISS','MISS','MISS']
print (" Eleven miss")
print (amd)
calculateAverageAttack(amd, disadvantage = True)