Programming AI Bots for Zombie Dice
Wed 21 November 2012 Al Sweigart
NOTE: This blog post may be obsolete. Please read Writing Bots to Play Zombie Dice instead.
This tutorial outlines how to create a tournament simulation program for the Zombie Dice game in Python. With this tournament program, you can also code your own AI bots to play Zombie Dice against each other. You can quickly test out how the different strategies the bots use compare against each other over thousands of simulated games. This tutorial assumes you know basic Python programming. (You can learn to program from the free book on this site, "Invent Your Own Computer Games with Python".
Computer game simulations make for great science fair experiments, and since the rules to Zombie Dice are so simple it's fairly easy to program a simulation for it.
The Rules of Zombie Dice
Zombie Dice is a dice rolling game that is fun for groups, quick to play, and can be learned in a couple minutes. It has a "push your luck" game mechanic.
Each of the players is a zombie. Each of the dice represents a human victim. You want to eat brains and avoid shotgun blasts. If the footsteps come up, the human has eluded you. The rules are summarized below: (Or view the official rules PDF or view the Flash tutorial.)
- On your turn grab 3 dice from the cup and roll them. Dice are colored red, yellow, and green and have footsteps, brains, or shotgun icons.
- Set aside any brain and shotgun dice.
- If you have 3 shotguns, your turn ends with a score of 0.
- You can decide to either stop rolling or roll again.
- If you stop, your score for this turn is the number of brains you have.
- If you re-roll, keep the footsteps dice you rolled, set aside the brain and shotgun dice rolled, and randomly grab dice to replace the brain and shotgun dice. Roll the 3 dice.
- Go back to step 4. You basically can keep re-rolling for as long as you want to push your luck.
To win:
The colors note your odds of winning. The entire dice set has 6 green, 4 yellow, and 3 red dice.
Running the Tournament Program
Download the Zombie Dice simulation code. This should run with Python 2 and Python 3. You can also find it on GitHub. The two main files are:
- zombiedice.py is the basic simulator and outputs text results when the tournament is finished.
- zombiedice_web.py runs a web server and launches your browser to provide a GUI and real-time updates while the tournament is in progress.
When you click the "Begin Tournament" button, the simulation will begin with the loaded bots:
When the simulation has finished, you can reload the page to start a new tournament.
To edit which bots are being run in the simulation, modify the BOTS
list at the top of zombiedice_web.py.
The AI Bots
Each zombie AI bot will be a class that has:
- A
name
member which is set in the constructor function. The name uniquely identifies the bot in a tournament (this way you can have multiple bots from the same class compete against each other.) - A
turn()
method that has agameState
tuple passed to it. - The
turn()
method calls a globalroll()
function (zombiedice.roll()
if your bot is in another file that imports zombiedice.py) as many times as it likes. The turn is over when theturn()
method returns. (Calls toroll()
after getting three shotgun blasts have no effect, and roll() simply returns an empty list.) - Optionally you can have a
newGame()
and/orendGame()
methods that are called so that the bot can know when a game has started and ended (in case the bot should change its strategy if it is winning or losing a multi-game tournament.)
# A "skeleton" zombie class. Get it? Skeleton? Heh heh heh... eh... nevermind. class MyZombie(object): def __init__(self, name): self.name = name def newGame(self): pass # do nothing def endGame(self, gameState): pass # do nothing def turn(gameState): results = roll()
The gameState
parameter is a dictionary with the following keys:
- Key
'order'
has a value of a list of player order like['player1name', 'player2name', ...]
. - Key
'scores'
has a value of a dictionary with scores like{'player1name': player1score, 'player2name': player2score, ...}
. - Key
'round'
has a value of an integer telling which round it is in the current game. (The first round is 1.)
The return value of roll()
is a list of three dictionaries that have the color and icon of the rolls. For example:
[{'color': 'green', 'icon': 'shotgun'}, {'color': 'red', 'icon': 'footsteps'}, {'color': 'yellow', 'icon': 'brains')]
There are uppercase constant variables that you can use instead of string values, just to avoid typos:
[{COLOR: GREEN, ICON: SHOTGUN}, {COLOR: RED, ICON: FOOTSTEPS}, {COLOR: YELLOW, ICON: BRAINS}]
For example, here's the code for a Zombie Dice bot that keeps rolling until they have at least 3 brains:
class ThreeBrainsThenStops(object): def __init__(self, name): self.name = name def newGame(self): pass # do nothing def endGame(self, gameState): pass # do nothing def turn(self, gameState): brains = 0 while brains < 3: results = roll() if results = []: return for i in results: if i[ICON] == BRAINS: brains += 1
Loading Bots into the Tournament Program
To configure a tournament, create a new Python script (called config.py in this example, but any name is fine) and run zombiedice.py like this:
python zombiedice.py config.py
The config file is formatted with games, ui, and bots variables:
games
- integer, the number of games to simulateui
- string, either "web" for web interface or "cli" for command line interfacebots
- a list of lists. Each inner list represents a bot, and has values:- filename - string, the python file where the bot code is
- class name - string, the name of the class
- bot name - string, the name of the bot instance
- args - arguments passed to the bot's constructor
Additionally, the config file can have these variables:
verbose
- boolean, if True, output game info to stdoutexceptions_lose_game
- boolean, if True, an exception in the bot code causes the bot to forfeit the current game. If False, an exception crashes the tournament program.max_turn_time
- if None, there is no time limit for a bot's turn. Otherwise, the number of seconds the bot has per turn before forfeiting the current game.
Example config.py file:
games = 100 ui = 'web' bots = [ ['zombieBotExamples.py', 'RandomCoinFlipZombie', 'Random Bot'], ['zombieBotExamples.py', 'MonteCarloZombie', 'Monte Carlo Bot', 40, 20], ['zombieBotExamples.py', 'MinNumShotgunsThenStopsZombie', 'Min Shotguns Bot', 2], ]
The Included Bots
The zombiedice.py program has some basic bots:
- The
ZombieBot_RandomCoinFlip
bot simply has a 50/50 chance of continuing to call theroll()
function or stopping. It'll most likely lose most games. - The
ZombieBot_MinNumShotgunsThenStops
bot will continue to call theroll()
function until it has a minimum number of shotgun rolls. This minimum can be set by passing an integer for theminShotguns
parameter. - The
ZombieBot_HumanPlayer
bot actually usesprint()
andinput()
calls so that a human player can play against the bots. - The
ZombieBot_RollsUntilInTheLead
bot will keep rolling until it gets into the lead compared to the other bots. This bot takes higher risks once it starts trailing. - The
ZombieBot_MonteCarlo
bot is the most sophisticated of all the bots. It basically runs several random experiments to see if the next roll would result in 3 or more shotguns. You can pass different values to the constructors to tell it how many experiments to run on each turn and what percentage of them must not result in death to roll again.
Write your own bots and then see how they do against these simple bots. You can post your code to https://gist.github.com and post a link to it in the comments section below.