/
Player.py
145 lines (122 loc) · 4.48 KB
/
Player.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
from Move import Move
import copy
import random
WHITE = 1
BLACK = 2
# The Player classes take turns in games of checkers. They are called by checkers.py
# The human player recieves input from a human player telling it where the human
# wants to move. This class makes sure the move is valid and checks for jumps
class Human_Player():
color = None
#Constructor
def __init__(self, color):
self.color = color
# The turn method should receive the start and end points of the desired move
# and the board object to make the move on. This method should check that the move
# is valid (by using the board's methods) and then update the board with that move.
#
# Returns a code indicating if the turn is over, and the reason if it is not
def turn(self, start, end, board, state):
if board.checkMove(start, end, state, False) == Move.MOVE_INVALID:
return Move.MOVE_INVALID
return board.move(start, end, state)
# The AI player searches the board for the best move available. It only takes the board
# as a parameter and will return the updated board and the move made (so that the GUI
# can be updated)
class AI_Player():
color = None
checkers = None
best_move = None
#Constructor
def __init__(self, color, checkers):
self.color = color
self.checkers = checkers
self.best_move = None
def get_best(self):
return self.best_move
def set_best(self, best):
self.best_move = best
def turn(self, board, state):
# Toughness of CPU
depth = 2
alpha = -999
beta = 999
player = True # True means Max, False means Min
board_orig = copy.deepcopy(board.board)
value_best = self.alphabeta(board, depth, alpha, beta, player, state)
# we found it so actually make the move
updateGUI = 1
board.board = copy.deepcopy(board_orig)
[best_start, best_end] = self.get_best()
last_cell = board.board[best_start.row][best_start.column]
return_code = board.move(best_start, best_end, state)
self.checkers.move(best_start, best_end, last_cell, return_code)
self.jumpAgain(board, state, return_code, updateGUI)
#board.printBoardMinimal()
print "AI chose board value:", value_best
print "AI turn complete"
# TODO FIX Doesn't stop after a full move
def jumpAgain(self, board, state, return_code, updateGUI):
while return_code == Move.JUMP_AVAILABLE:
moves = board.getAllPlayerMoves(state)
if not moves:
break
move = moves.pop()
end = move.pop()
start = move.pop()
last_cell = board.board[start.row][start.column]
return_code = board.move(start, end, state)
if updateGUI:
self.checkers.move(start, end, last_cell, return_code)
def alphabeta(self, board, depth, alpha, beta, player, state):
if depth == 0 or board.gameOver(state):
return board.getValue(state, player)
moves = board.getAllPlayerMoves(state)
if not moves:
return
# variables for finding the best move for this turn
board_orig = copy.deepcopy(board.board)
other_state = copy.deepcopy(state)
other_state.switchPlayer()
updateGUI = 0
random.shuffle(moves)
[start, end] = moves[0]
local_best = [start, end]
if player: # If player is true, then it is Max, else Min
for move in moves:
board.board = copy.deepcopy(board_orig)
end = move.pop()
start = move.pop()
return_code = board.move(start, end, state)
self.jumpAgain(board, state, return_code, updateGUI)
alpha_new = self.alphabeta(board, depth - 1, alpha, beta, not player, other_state)
if alpha_new > alpha:
alpha = alpha_new
local_best = [start, end]
#print "The new best for", player, " is ", alpha
if (beta <= alpha):
break
board.printBoardMinimal()
print "The alpha is", alpha
print "The chosen alpha at depth", depth, "is", alpha
self.set_best(local_best)
return alpha
else:
for move in moves:
board.board = copy.deepcopy(board_orig)
end = move.pop()
start = move.pop()
return_code = board.move(start, end, state)
self.jumpAgain(board, state, return_code, updateGUI)
beta_new = self.alphabeta(board, depth - 1, alpha, beta, not player, other_state)
if beta_new < beta:
beta = beta_new
local_best = [start, end]
#print "The new best for", player, " is ", beta
if (beta <= alpha):
break
board.printBoardMinimal()
print "The beta is", beta
print "The beta chosen at depth", depth, "is", beta
self.set_best(local_best)
return beta