public
Created

Quick-and-Dirty Brute Force Risk vs Reward bot

  • Download Gist
ZombieBot_QaDBFRvR.py
Python
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
 
# Quick-and-Dirty Brute Force Risk vs Reward bot
# Before each roll (except the first), do a brute force calculation of risk vs reward. In this case,
# risk is the probability of having 3 shotgun dice after the roll, and reward is the probability of
# getting an extra 1, 2, or 3 brains. If P(death) - rewardBonus[1]*P(1 brain) -
# rewardBonus[2]*P(2 brain) - rewardBonus[3]*P(3 brain) > rvrCutoff, then roll.
# If behindBonus and/or aheadPenalty are not zero, then those amounts are added to or subtracted from
# the risk vs reward depending on weather the bot is winning or losing, encouraging risky play when
# behind and safer play when ahead
 
# Based purely on trial-and-error, the following configurations seem to work best:
# ZombieBot_QaDBFRvR('QaDBFRvR A', 0.125, [0.11,0.11,0.11], 0.025, 0),
# ZombieBot_QaDBFRvR('QaDBFRvR B', 0.19, [0.1,0.15,0.2], 0, 0.1),
# ZombieBot_QaDBFRvR('QaDBFRvR C', 0.19, [0.1,0.1,0.1], 0, 0.1),
 
class ZombieBot_QaDBFRvR(object):
 
def __init__(self, name, rvrCutoff, rewardBonus, behindBonus, aheadPenalty):
self.name = name
self.rvrCutoff = rvrCutoff
self.rewardBonus = rewardBonus
self.behindBonus = behindBonus
self.aheadPenalty = aheadPenalty
 
# Precalcualted roll probabilities, given colour and face
self.rollProbabilities = {
GREEN: {BRAINS: 0.5, FOOTSTEPS: 1.0/3, SHOTGUN: 1.0/6},
YELLOW: {BRAINS: 1.0/3, FOOTSTEPS: 1.0/3, SHOTGUN: 1.0/3},
RED: {BRAINS: 1.0/6, FOOTSTEPS: 1.0/3, SHOTGUN: 0.5}
}
 
def initState(self):
self.diceLeft = {GREEN: 6, YELLOW: 4, RED: 3}
self.shotguns = 0
self.footsteps = [] # list of dice colours
self.brains = [] # list of dice colours
self.rollNumber = 1
 
def updateState(self, results):
oldFootsteps = self.footsteps[:]
self.footsteps = []
for i in results:
if i[ICON] == SHOTGUN:
self.shotguns += 1
if i[ICON] == FOOTSTEPS:
self.footsteps += [i[COLOR]]
if i[ICON] == BRAINS:
self.brains += [i[COLOR]]
 
self.diceLeft[i[COLOR]] -= 1
 
# "Add back" the old set of footsteps, since they were already in our hand and were not
# taken out of the dice jar
for colour in oldFootsteps:
self.diceLeft[colour] += 1
 
def printState(self, gameState):
print('%s round %d: Shotguns: %d, Footsteps: %s, Dice Left: G=%d, Y=%d, R=%d' % (
self.name, gameState['round'], self.shotguns, self.footsteps,
self.diceLeft[GREEN], self.diceLeft[YELLOW], self.diceLeft[RED]))
 
def putBackBrainDice(self):
for colour in self.brains:
self.diceLeft[colour] += 1
self.brains = []
 
# Generate a list of all possible combinations of the colours of dice that can come out of a roll.
# This only calculates the combinations of the dice left over when you take into account the
# footstep dice that are left over from the last roll
def generateColourCombinations(self):
dice = [GREEN]*self.diceLeft[GREEN] + [YELLOW]*self.diceLeft[YELLOW] + [RED]*self.diceLeft[RED]
return itertools.combinations(dice, 3 - len(self.footsteps))
 
# No indices because I'm lazy,
# 0 = probability of having 3 or more shotguns after the roll
# 1 = probability of having 1 additional brain after the roll
# 2 = probability of having 2 additional brains after the roll
# 3 = probability of having 3 additional brains after the roll
def calculateProbabilites(self):
probabilities = [0, 0, 0, 0]
 
# All possible permutations of a roll with repeated elements (e.g. SSS, SSB, SBS, BSS)
rollPermutations = itertools.product([SHOTGUN, FOOTSTEPS, BRAINS], repeat=3)
 
# All possible combinations of dice colours
colourCombinations = self.generateColourCombinations()
 
# For each possible combination of dice colours, add to the probabilites
for combination in colourCombinations:
colours = self.footsteps + list(combination)
 
# Calculate the probability of the roll, given the colours
for roll in rollPermutations:
probability = 1;
for (colour, die) in zip(colours, roll):
x = self.rollProbabilities[colour][die]
probability *= x
 
# Chance of death
shotgunsInRoll = roll.count(SHOTGUN)
if (shotgunsInRoll + self.shotguns >= 3):
probabilities[0] += probability
 
# Chance of any number of brains
brainsInRoll = roll.count(BRAINS)
if (brainsInRoll > 0):
probabilities[brainsInRoll] += probability
 
return probabilities
 
def turn(self, gameState):
self.initState()
shouldRoll = True
 
while shouldRoll and self.shotguns < 3:
 
# Before the roll, make sure we have enough dice left over
numDiceLeft = self.diceLeft[GREEN] + self.diceLeft[YELLOW] + self.diceLeft[RED]
numDiceNeeded = 3 - len(self.footsteps)
if (numDiceNeeded > numDiceLeft):
self.putBackBrainDice()
 
results = roll()
self.rollNumber += 1
self.updateState(results)
 
probabilities = self.calculateProbabilites()
 
risk = probabilities[0]
reward = (self.rewardBonus[0]*probabilities[1] +
self.rewardBonus[1]*probabilities[2] +
self.rewardBonus[2]*probabilities[3])
 
maxScore = max(gameState[SCORES].items())
myScore = gameState[SCORES][self.name]
if (myScore > maxScore):
# Add risk (play safer)
risk += self.aheadPenalty
elif (myScore < maxScore):
# Add reward (play riskier)
reward += self.behindBonus
 
shouldRoll = (risk - reward) < self.rvrCutoff

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.