forked from senbar/sigmaChess
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbot.py
181 lines (158 loc) · 6.17 KB
/
bot.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
from board import ChessBoard
from pieces import *
import random
class MoveNode:
def __init__(self, move, children, parent):
self.actualCoordinates = move[0]
self.targetCoordinates = move[1]
self.children = children
self.parent = parent
self.pointAdvantage = None
self.depth = 1
self.isCheckmate = False
def getDepth(self):
depth = 1
highestNode = self
while True:
if highestNode.parent is not None:
highestNode = highestNode.parent
depth += 1
else:
return depth
def getActualCoordinates(self):
return self.actualCoordinates
def getTargetCoorinates(self):
return self.targetCoordinates
def __gt__(self, other):
if self.isCheckmate and not other.isCheckmate:
return True
if self.isCheckmate and other.isCheckmate:
return False
if self.isCheckmate and other.isCheckmate:
return False
return self.pointAdvantage > other.pointAdvantage
def __lt__(self, other):
if not self.isCheckmate and other.isCheckmate:
return True
if self.isCheckmate and not other.isCheckmate:
return False
if self.isCheckmate and other.isCheckmate:
return False
return self.pointAdvantage < other.pointAdvantage
def __eq__(self, other):
return self.pointAdvantage == other.pointAdvantage
class Bot:
def __init__(self, depth, side, board, isSecondBot=False):
self.board = board
self.depth = depth
self.side = side
self.isSecondBot = isSecondBot
def getActualBoard(self):
return self.board
def setActualBoard(self, board):
self.board = board
def generateMoveTree(self):
moveTree = []
allMoves = self.board.getAllMoves(self.side)
for move in allMoves:
moveTree.append(MoveNode(move, [], None))
for node in moveTree:
self.board.movePiece(self.board.getPiece(node.actualCoordinates[0], node.actualCoordinates[1]),
node.targetCoordinates[0], node.targetCoordinates[1])
self.populateNodeChildren(node)
self.board.undoMove()
return moveTree
def populateNodeChildren(self, node):
node.pointAdvantage = self.evaluateMove(self.side)
node.depth = node.getDepth()
if node.depth == self.depth:
return
currentFaction = self.board.getOppositeFaction(self.board.whoMoved)
legalMoves = self.board.getAllMoves(currentFaction)
if len(legalMoves) == 0:
node.pointAdvantage = 0
return
if self.board.factionLost(self.board.getOppositeFaction(self.side)):
node.isCheckmate = True
for move in legalMoves:
node.children.append(MoveNode(move, [], node))
pieceToMove = self.board.getPiece(move[0][0], move[0][1])
self.board.movePiece(pieceToMove, move[1][0], move[1][1])
self.populateNodeChildren(node.children[-1])
self.board.undoMove()
def evaluateMove(self, faction):
moveValue = 0
moveValue += 0.5 * len(self.board.getAllMoves(faction))
for i in range(8):
for j in range(8):
piece = self.board.getPiece(i, j)
if piece is not None:
if type(piece) == piecePawn:
if piece.faction == faction:
moveValue += 1
continue
else:
moveValue -= 1
continue
if type(piece) == pieceBishop or type(piece) == pieceKnight:
if piece.faction == faction:
moveValue += 3
continue
else:
moveValue -= 3
continue
if type(piece) == pieceRook:
if piece.faction == faction:
moveValue += 5
continue
else:
moveValue -= 5
continue
if type(piece) == pieceQueen:
if piece.faction == faction:
moveValue += 9
continue
else:
moveValue -= 9
continue
if type(piece) == pieceKing:
if piece.faction == faction:
moveValue += 200
continue
else:
moveValue -= 200
continue
return moveValue
def getOptimalPointAdvantage(self, node):
return self.alphaBeta(node, -1e8, 1e8)
def alphaBeta(self, node, alpha, beta):
if not node.children:
return node.pointAdvantage
if node.children[0].depth % 2 == 0: #enemy move
for child in node.children:
beta = min(beta, self.alphaBeta(child, alpha, beta))
if alpha >= beta:
break
return beta
else:
for child in node.children:
alpha = max(alpha, self.alphaBeta(child, alpha, beta))
if alpha >= beta:
break
return alpha
def getBestMoves(self, moveTree):
bestMoves = []
for node in moveTree:
node.pointAdvantage = self.getOptimalPointAdvantage(node)
if not bestMoves:
bestMoves.append(node)
elif node > bestMoves[0]:
bestMoves = []
bestMoves.append(node)
elif node == bestMoves[0]:
bestMoves.append(node)
return [(node.actualCoordinates, node.targetCoordinates) for node in bestMoves]
def getBotMove(self):
moveTree = self.generateMoveTree()
bestMoves = self.getBestMoves(moveTree)
return random.choice(bestMoves)