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