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