• Skip to main content
  • Skip to primary sidebar

John Champaign Writes

Adventures in Self Publishing

Gloomhaven Python Code

# 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)

Primary Sidebar

Subscribe to Blog via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 46 other subscribers

RECENT BLOG POSTS

  • A Practical View on the 4% Rule
  • Qualities of a Good Job & Life
  • Whom to Trust?
  • My Experiences with Republic Wireless
  • HYIP – Avoid at All Cost!

Categories

  • Board games
  • Business
  • Game Development
  • Real Estate
  • Role Playing
  • Self Publishing
  • Writing Ideas

Archives

  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • December 2021
  • November 2021
  • October 2021
  • September 2021
  • August 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • October 2020
  • August 2020
  • June 2020
  • May 2020

Recent Comments

  • A Moment to Freak Out - Scott Alexander Clark on BookFunnel, StoryOrigin, Prolific Works, and BookSprout
  • John Champaign on Do You Owe Your Mother $1,000,000.00?
  • Catherine Holloway on Do You Owe Your Mother $1,000,000.00?
  • John Champaign on BookFunnel, StoryOrigin, Prolific Works, and BookSprout
  • cheryl-wright on BookFunnel, StoryOrigin, Prolific Works, and BookSprout

Copyright © 2022 · News Pro on Genesis Framework · WordPress · Log in