The Invent with Python Blog

Writings from the author of Automate the Boring Stuff.

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

  1. 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.
  2. Set aside any brain and shotgun dice.
  3. If you have 3 shotguns, your turn ends with a score of 0.
  4. You can decide to either stop rolling or roll again.
  5. If you stop, your score for this turn is the number of brains you have.
  6. 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.
  7. Go back to step 4. You basically can keep re-rolling for as long as you want to push your luck.

To win:

  • Once a player gets 13 brains, finish the round. If there is a tie, the tied players play a single tie breaker round.
  • Also, if you run out of dice for your turn, note the number of brain dice you've rolled and place those brain dice back into the cup. Then continue as normal.
  • The colors note your odds of winning. The entire dice set has 6 green, 4 yellow, and 3 red dice.

    Here's a video of gameplay:

    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 a gameState tuple passed to it.
    • The turn() method calls a global roll() 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 the turn() method returns. (Calls to roll() after getting three shotgun blasts have no effect, and roll() simply returns an empty list.)
    • Optionally you can have a newGame() and/or endGame() 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 simulate
    • ui - string, either "web" for web interface or "cli" for command line interface
    • bots - 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 stdout
      exceptions_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 the roll() function or stopping. It'll most likely lose most games.
    • The ZombieBot_MinNumShotgunsThenStops bot will continue to call the roll() function until it has a minimum number of shotgun rolls. This minimum can be set by passing an integer for the minShotguns parameter.
    • The ZombieBot_HumanPlayer bot actually uses print() and input() 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.


    Learn to program for free with my books for beginners:

    Sign up for my "Automate the Boring Stuff with Python" online course with this discount link.

    Email | Mastodon | Twitter | Twitch | YouTube | GitHub | Blog | Patreon | LinkedIn | Personal Site