A quick example

Let us define the rules of a game and start a match against the AI:

from easyAI import TwoPlayersGame, Human_Player, AI_Player, Negamax

class GameOfBones( TwoPlayersGame ):
    """ In turn, the players remove one, two or three bones from a
    pile of bones. The player who removes the last bone loses. """

    def __init__(self, players):
        self.players = players
        self.pile = 20 # start with 20 bones in the pile
        self.nplayer = 1 # player 1 starts

    def possible_moves(self): return ['1','2','3']
    def make_move(self,move): self.pile -= int(move) # remove bones.
    def win(self): return self.pile<=0 # opponent took the last bone ?
    def is_over(self): return self.win() # Game stops when someone wins.
    def show(self): print "%d bones left in the pile"%self.pile
    def scoring(self): return 100 if self.win() else 0 # For the AI

# Start a match (and store the history of moves when it ends)
ai = Negamax(13) # The AI will think 13 moves in advance
game = GameOfBones( [ Human_Player(), AI_Player(ai) ] )
history = game.play()

Result:

20 bones left in the pile

Player 1 what do you play ? 3

Move #1: player 1 plays 3 :
17 bones left in the pile

Move #2: player 2 plays 1 :
16 bones left in the pile

Player 1 what do you play ?

Solving the game

Let us now solve the game:

from easyAI import id_solve
r,d,m = id_solve(GameOfBones, ai_depths=range(2,20), win_score=100)

We obtain r=1, meaning that if both players play perfectly, the first player to play can always win (-1 would have meant always lose), d=10, which means that the wins will be in ten moves (i.e. 5 moves per player) or less, and m='3', which indicates that the first player’s first move should be '3'.

These computations can be sped up using a transposition table which will store the situations encountered and the best moves for each:

tt = TT()
GameOfBones.ttentry = lambda game : game.pile # key for the table
r,d,m = id_solve(GameOfBones, range(2,20), win_score=100, tt=tt)

After these lines are run the variable tt contains a transposition table storing the possible situations (here, the possible sizes of the pile) and the optimal moves to perform. With tt you can play perfectly without thinking:

game = GameOfBones( [  AI_Player( tt ), Human_Player() ] )
game.play() # you will always lose this game :)