-
Notifications
You must be signed in to change notification settings - Fork 0
/
backgammon.py
162 lines (131 loc) · 5.84 KB
/
backgammon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from board import Board, Dice
from player import Player, RandomPlayer
from neural_net import NeuralNetwork
import sys
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()
if __name__ == '__main__':
bg = Backgammon(training_mode=True, restore_net=True)
wins = [0,0]
n_games = 10
print "\nTraining the neural net ..."
print "Network experience: %s games" %(bg.neural_network.num_games)
for i in range(n_games):
bg.run()
#print "Game {}, won by {}".format(i + 1, bg.winner.identity)
if bg.winner.color == 0:
wins[0] += 1
else:
wins[1] += 1
bg.progress(i+1, n_games, "[G: %s, w: %s, b: %s ]" %(i+1, wins[0], wins[1]))
bg.reset()
bg.save_network()
print ""