-
Notifications
You must be signed in to change notification settings - Fork 0
/
Players.py
126 lines (93 loc) · 4.16 KB
/
Players.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
'''
Erich Kramer - April 2017
Apache License
If using this code please cite creator.
'''
from operator import attrgetter
class Player:
def __init__(self, symbol):
self.symbol = symbol
#PYTHON: use obj.symbol instead
def get_symbol(self):
return self.symbol
#parent get_move should not be called
def get_move(self, board):
raise NotImplementedError()
class HumanPlayer(Player):
def __init__(self, symbol):
Player.__init__(self, symbol);
def clone(self):
return HumanPlayer(self.symbol)
#PYTHON: return tuple instead of change reference as in C++
def get_move(self, board):
col = int(input("Enter col:"))
row = int(input("Enter row:"))
return (col, row)
class MoveNode():
def __init__(self, column, rownum, utility, board):
self.col = column
self.row = rownum
self.utility = utility
self.board = board # Does not do a deep copy, must do a clone of another board or create a new one to input
# def __gt__(self, other):
# if (self.utility > other.utility):
# return True
# else:
# return False
# def __lt__(self, other):
# if (self.utility < other.utility):
# return True
# else:
# return False
class MinimaxPlayer(Player):
def __init__(self, symbol):
Player.__init__(self, symbol);
if symbol == 'X':
self.oppSym = 'O'
else:
self.oppSym = 'X'
def get_move(self, board):
allSuccessors = self.generate_successors(self.symbol, board)
for x in allSuccessors:
print("Row: ", x.row, " Column: ", x.col, " Utility: ", x.utility)
optimalState = min(allSuccessors, key=attrgetter('utility'))
return (optimalState.col, optimalState.row)
def generate_successors(self, currentSymbol, board):
allSuccessors = []
for c in range (0, board.cols):
for r in range (0, board.rows):
if board.is_legal_move(c, r, currentSymbol):
newBoard = board.cloneOBoard()
newBoard.play_move(c, r, currentSymbol)
node = MoveNode(c, r, self.get_utility(newBoard), newBoard)
allSuccessors.append(node)
if (currentSymbol == self.symbol):
if (len(allSuccessors) == 0 and board.has_legal_moves_remaining(self.oppSym)):
finalState = MoveNode(-1, -1, -1, board)
newSuccessors = self.generate_successors(self.oppSym, board)
finalState.utility = (max(newSuccessors, key=attrgetter('utility'))).utility
allSuccessors.append(finalState)
## Create a situation for if the current player has no moves left but the opposing player does
else:
for x in allSuccessors:
if (x.utility == None):
newSuccessors = self.generate_successors(self.oppSym, x.board)
x.utility = (max(newSuccessors, key=attrgetter('utility'))).utility
else:
if (len(allSuccessors) == 0 and board.has_legal_moves_remaining(self.symbol)):
finalState = MoveNode(-1, -1, -1, board)
newSuccessors = self.generate_successors(self.symbol, board)
finalState.utility = (min(newSuccessors, key=attrgetter('utility'))).utility
allSuccessors.append(finalState)
## Create a situation for if the current player has no moves left but the opposing player does
else:
for x in allSuccessors:
if (x.utility == None):
newSuccessors = self.generate_successors(self.symbol, x.board)
x.utility = (min(newSuccessors, key=attrgetter('utility'))).utility
return allSuccessors
def get_utility(self, board):
if (board.has_legal_moves_remaining(self.symbol) or board.has_legal_moves_remaining(self.oppSym)):
return None
else:
return board.count_score(self.oppSym)