class Backgammon(object): """ This class wraps all of the backgammon functionality. Basically, the use model for this class is to build a new Backgammon with two players, execute backgammon.run(), which runs the game, and the call backgammon.reset(), backgammon.run() if you want to play again. """ def __init__(self, training_mode, restore_net): # the dice self.dice = Dice() # internal board, which is the state before the current move self.board = Board() # the neural network used by the players, both players share the same net if not restore_net: self.neural_network = NeuralNetwork(input_size=198, hidden_size=40, \ output_size=2) elif restore_net: self.neural_network = NeuralNetwork(restore_from_file=True) # list of players if training_mode: self.players = [Player('white', self.neural_network, learning_mode=True), \ Player('black', self.neural_network, learning_mode=True)] # let white play against RandomPlayer black for evaluating performance elif not training_mode: self.players = [Player('white', self.neural_network, learning_mode=False), \ RandomPlayer('black')] # the current player of this instance self.current_player = None # winner of this game self.winner = None self.reset() def save_network(self): """ Saves the Neural Network of this Backgammon instance to a file. """ self.neural_network.save_network() def reset(self): """ Resets this backgammon instance to the initial state, with a new board and determines starting player. """ self.board.reset_board() self.dice.roll() # decide which player starts the game by rolling dice # die1 > die2 player 0 starts and vice versa # if die1==die2, roll until different if self.dice.get_die1() != self.dice.get_die2(): # determine starting player: # die1 rolls for white and die2 rolls for black self.current_player = (0 if self.dice.get_die1() > self.dice.get_die2() else 1) # make sure that dice dont show same number elif self.dice.get_die1() == self.dice.get_die2(): same = True # roll until different while same: self.dice.roll() if self.dice.get_die1() != self.dice.get_die2(): self.current_player = (0 if self.dice.get_die1() > self.dice.get_die2() else 1) same = False # if black starts game, reverse players list # because white is first in the initial list if self.current_player == 1: self.players = list(reversed(self.players)) def run(self): """ Runs a game of backgammon, and does not return until the game is over. Returns the player who won the game. """ while not self.board.is_gameover(): # request players to choose a board self.get_move(self.players[0]) if self.board.is_gameover(): break self.get_move(self.players[1]) if self.board.is_gameover(): break # check whether a player has all checkers beared off # and return it as winner. if self.board.get_off(Board.WHITE) == 15: for player in self.players: if player.color == Board.WHITE: player.won(self.board) self.winner = player else: player.lost(self.board) elif self.board.get_off(Board.BLACK) == 15: for player in self.players: if player.color == Board.BLACK: player.won(self.board) self.winner = player else: player.lost(self.board) return self.winner def get_move(self, player): """ Receives a board from the player and applies the move. """ #print player.color new_board = player.choose_move(self) self.apply_move(new_board) def apply_move(self, new_board): """ Updates the board according to chosen move and initiates the next turn. """ # update board according to chosen board self.board = new_board # roll new dice self.dice.roll() # update player self.current_player = Board.get_opponent(self.current_player) @staticmethod def progress(count, total, suffix=''): bar_len = 60 filled_len = int(round(bar_len * count / float(total))) percents = round(100.0 * count / float(total), 1) bar = '=' * filled_len + '-' * (bar_len - filled_len) sys.stdout.write("\r[%s] %s%s %s" %(bar, percents, '%', suffix)) sys.stdout.flush()