Source code for easyAI.TwoPlayersGame
from copy import deepcopy
[docs]class TwoPlayersGame:
"""
Base class for... wait for it... two-players games !
To define a new game, make a subclass of TwoPlayersGame, and define
the following methods:
- ``__init__(self, players, ...)`` : initialization of the game
- ``possible_moves(self)`` : returns of all moves allowed
- ``make_move(self, move)``: transforms the game according to the move
- ``is_over(self)``: check whether the game has ended
The following methods are optional:
- ``show(self)`` : prints/displays the game
- ``scoring``: gives a score to the current game (for the AI)
- ``unmake_move(self, move)``: how to unmake a move (speeds up the AI)
- ``ttentry(self)``: returns a string/tuple describing the game.
- ``ttrestore(self, entry)``: use string/tuple from ttentry to restore a game.
The __init__ method *must* do the following actions:
- Store ``players`` (which must be a list of two Players) into
self.players
- Tell which player plays first with ``self.nplayer = 1 # or 2``
When defining ``possible_moves``, you must keep in mind that you
are in the scope of the *current player*. More precisely, a
subclass of TwoPlayersGame has the following attributes that
indicate whose turn it is. These methods can be used but should not
be overwritten:
- ``self.player`` : the current player (e.g. ``Human_Player``)
- ``self.opponent`` : the current Player's opponent (Player).
- ``self.nplayer``: the number (1 or 2) of the current player.
- ``self.nopponent``: the number (1 or 2) of the opponent.
- ``self.nmove``: How many moves have been played so far ?
For more, see the examples in the dedicated folder.
Examples:
----------
::
from easyAI import TwoPlayersGame, Human_Player
class Sticks( TwoPlayersGame ):
''' In turn, the players remove one, two or three sticks from
a pile. The player who removes the last stick loses '''
def __init__(self, players):
self.players = players
self.pile = 20 # start with 20 sticks
self.nplayer = 1 # player 1 starts
def possible_moves(self): return ['1','2','3']
def make_move(self,move): self.pile -= int(move)
def is_over(self): return self.pile <= 0
game = Sticks( [Human_Player(), Human_Player() ] )
game.play()
"""
[docs] def play(self, nmoves=1000, verbose=True):
"""
Method for starting the play of a game to completion. If one of the
players is a Human_Player, then the interaction with the human is via
the text terminal.
Parameters
-----------
nmoves:
The limit of how many moves (plies) to play unless the game ends on
it's own first.
verbose:
Setting verbose=True displays additional text messages.
"""
history = []
if verbose:
self.show()
for self.nmove in range(1, nmoves + 1):
if self.is_over():
break
move = self.player.ask_move(self)
history.append((deepcopy(self), move))
self.make_move(move)
if verbose:
print("\nMove #%d: player %d plays %s :" % (
self.nmove, self.nplayer, str(move)))
self.show()
self.switch_player()
history.append(deepcopy(self))
return history
@property
def nopponent(self):
return 2 if (self.nplayer == 1) else 1
@property
def player(self):
return self.players[self.nplayer - 1]
@property
def opponent(self):
return self.players[self.nopponent - 1]
def switch_player(self):
self.nplayer = self.nopponent
def copy(self):
return deepcopy(self)
[docs] def get_move(self):
"""
Method for getting a move from the current player. If the player is an
AI_Player, then this method will invoke the AI algorithm to choose the
move. If the player is a Human_Player, then the interaction with the
human is via the text terminal.
"""
return self.player.ask_move(self)
[docs] def play_move(self, move):
"""
Method for playing one move with the current player. After making the move,
the current player will change to the next player.
Parameters
-----------
move:
The move to be played. ``move`` should match an entry in the ``.possibles_moves()`` list.
"""
result = self.make_move(move)
self.switch_player()
return result