7 ( an agent, not an implementation of a bishop chess piece!)
13 # Skeleton class for your agent
14 class Agent(AgentRandom): # Inherits from AgentRandom (in qchess.py)
15 def __init__(self, name, colour):
16 AgentRandom.__init__(self, name, colour)
17 self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4}
19 self.aggression = 2.0 # Multiplier for scoring due to aggressive actions
20 self.defence = 1.0 # Multiplier for scoring due to defensive actions
22 self.depth = 0 # Current depth
23 self.max_depth = 2 # Recurse this many times (for some reason, makes more mistakes when this is increased???)
24 self.recurse_for = -1 # Recurse for the best few moves each times (less than 0 = all moves)
26 for p in self.board.pieces["white"] + self.board.pieces["black"]:
28 p.selected_moves = None
32 def get_value(self, piece):
35 return float(self.value[piece.types[0]] + self.value[piece.types[1]]) / 2.0
37 # Score possible moves for the piece
38 # Highest score is 1.0 (which means: make this move!)
39 def prioritise_moves(self, piece):
41 #sys.stderr.write(sys.argv[0] + ": prioritise called for " + str(piece) + "\n")
45 grid = self.board.probability_grid(piece)
46 #sys.stderr.write("\t Probability grid " + str(grid) + "\n")
50 if grid[x][y] < 0.3: # Throw out moves with < 30% probability
51 #sys.stderr.write("\tReject " + str(x) + "," + str(y) + " (" + str(grid[x][y]) + ")\n")
54 target = self.board.grid[x][y]
59 # Get total probability that the move is protected
60 [xx,yy] = [piece.x, piece.y]
61 [piece.x, piece.y] = [x, y]
62 self.board.grid[x][y] = piece
63 self.board.grid[xx][yy] = None
65 defenders = self.board.coverage(x, y, piece.colour, reject_allied = False)
67 for d in defenders.keys():
68 d_prob += defenders[d]
69 if len(defenders.keys()) > 0:
70 d_prob /= float(len(defenders.keys()))
75 # Get total probability that the move is threatened
76 attackers = self.board.coverage(x, y, opponent(piece.colour), reject_allied = False)
78 for a in attackers.keys():
79 a_prob += attackers[a]
80 if len(attackers.keys()) > 0:
81 a_prob /= float(len(attackers.keys()))
86 self.board.grid[x][y] = target
87 self.board.grid[xx][yy] = piece
88 [piece.x, piece.y] = [xx, yy]
92 value = self.aggression * (1.0 + d_prob) * self.get_value(target) - self.defence * (1.0 - d_prob) * a_prob * self.get_value(piece)
94 # Adjust score based on movement of piece out of danger
95 attackers = self.board.coverage(piece.x, piece.y, opponent(piece.colour))
97 for a in attackers.keys():
98 s_prob += attackers[a]
99 if len(attackers.keys()) > 0:
100 s_prob /= float(len(attackers.keys()))
104 value += self.defence * s_prob * self.get_value(piece)
106 # Adjust score based on probability that the move is actually possible
107 moves.append([[x, y], grid[x][y] * value])
109 moves.sort(key = lambda e : e[1], reverse = True)
110 #sys.stderr.write(sys.argv[0] + ": Moves for " + str(piece) + " are " + str(moves) + "\n")
112 piece.last_moves = moves
113 piece.selected_moves = None
120 def select_best(self, colour):
124 for p in self.board.pieces[colour]:
125 self.choice = p # Temporarily pick that piece
126 m = self.prioritise_moves(p)
128 all_moves.update({p : m[0]})
130 if len(all_moves.items()) <= 0:
134 opts = all_moves.items()
135 opts.sort(key = lambda e : e[1][1], reverse = True)
137 if self.depth >= self.max_depth:
141 if self.recurse_for >= 0:
142 opts = opts[0:self.recurse_for]
143 sys.stderr.write(sys.argv[0] + " : Before recurse, options are " + str(opts) + "\n")
145 # Take the best few moves, and recurse
146 for choice in opts[0:self.recurse_for]:
147 [xx,yy] = [choice[0].x, choice[0].y] # Remember position
148 [nx,ny] = choice[1][0] # Target
149 [choice[0].x, choice[0].y] = [nx, ny] # Set position
150 target = self.board.grid[nx][ny] # Remember piece in spot
151 self.board.grid[xx][yy] = None # Remove piece
152 self.board.grid[nx][ny] = choice[0] # Replace with moving piece
155 best_enemy_move = self.select_best(opponent(choice[0].colour))
156 choice[1][1] -= best_enemy_move[1][1] / float(self.depth + 1.0)
158 [choice[0].x, choice[0].y] = [xx, yy] # Restore position
159 self.board.grid[nx][ny] = target # Restore taken piece
160 self.board.grid[xx][yy] = choice[0] # Restore moved piece
164 opts.sort(key = lambda e : e[1][1], reverse = True)
165 sys.stderr.write(sys.argv[0] + " : After recurse, options are " + str(opts) + "\n")
172 # Returns [x,y] of selected piece
175 self.choice = self.select_best(self.colour)[0]
176 return [self.choice.x, self.choice.y]
178 # Returns [x,y] of square to move selected piece into
180 self.choice.selected_moves = self.choice.last_moves
181 moves = self.prioritise_moves(self.choice)
185 return AgentRandom.get_move(self)
190 # Horrible messy graphics class that draws what the agent is doing, kind of useful for testing
191 class AgentGraphics(GraphicsThread):
192 def __init__(self, board, title):
193 GraphicsThread.__init__(self, board, title, grid_sz = [64,64])
198 square_img = pygame.Surface((self.grid_sz[0], self.grid_sz[1]),pygame.SRCALPHA) # A square image
199 while not self.stopped():
201 self.board.display_grid(window = self.window, grid_sz = self.grid_sz)
203 # Draw choice of the AI
204 if agent.choice != None:
205 mp = [self.grid_sz[i] * [agent.choice.x, agent.choice.y][i] for i in range(2)]
206 square_img.fill(pygame.Color(0,255,0,64))
207 self.window.blit(square_img, mp)
209 # Draw calculated choices for the piece clicked on
210 if self.choice != None:
211 mp = [self.grid_sz[i] * [self.choice.x, self.choice.y][i] for i in range(2)]
212 square_img.fill(pygame.Color(0,0,255,128))
213 self.window.blit(square_img, mp)
215 # Draw the choices the AI calculated from the selection of the chosen piece
216 if agent.choice != None and agent.choice.selected_moves != None:
217 for m in agent.choice.selected_moves:
218 mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
219 square_img.fill(pygame.Color(128,128,255,128))
220 self.window.blit(square_img, mp)
221 font = pygame.font.Font(None, 14)
222 text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(255,0,0))
223 mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
224 mp[1] = mp[1] + self.grid_sz[1] - text.get_height()
225 self.window.blit(text, mp)
228 # Draw the choice the AI's chosen piece could have actually made
229 if agent.choice != None and agent.choice.last_moves != None:
230 for m in agent.choice.last_moves:
231 mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
232 square_img.fill(pygame.Color(255,0,0,128))
233 self.window.blit(square_img, mp)
234 font = pygame.font.Font(None, 14)
235 text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,255))
236 mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
237 self.window.blit(text, mp)
242 if self.moves != None:
244 mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
245 square_img.fill(pygame.Color(255,0,255,128))
246 self.window.blit(square_img, mp)
247 font = pygame.font.Font(None, 14)
248 text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,0))
249 self.window.blit(text, mp)
253 self.board.display_pieces(window = self.window, grid_sz = self.grid_sz)
255 pygame.display.flip()
257 for event in pygame.event.get():
258 if event.type == pygame.QUIT:
261 elif event.type == pygame.MOUSEBUTTONDOWN:
262 m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
263 p = agent.board.grid[m[0]][m[1]]
267 self.last_moves = self.choice.last_moves
268 self.selected_moves = self.choice.selected_moves
269 if event.button == 3 or self.choice.last_moves == None:
270 self.moves = agent.prioritise_moves(self.choice)
272 self.moves = self.choice.last_moves
274 elif event.type == pygame.MOUSEBUTTONUP:
275 if self.choice == None:
277 self.choice.last_moves = self.last_moves
278 self.choice.selected_moves = self.selected_moves
282 pygame.display.quit()
286 # Main function; don't alter
290 colour = sys.stdin.readline().strip("\n") # Gets the colour of the agent from stdin
292 agent = Agent(argv[0], colour) # Creates your agent
294 graphics = AgentGraphics(agent.board, title="Agent Bishop (" + str(colour) + ") - DEBUG VIEW")
297 # Plays quantum chess using your agent
299 line = sys.stdin.readline().strip(" \r\n")
300 #sys.stderr.write(argv[0] + ": gets line \"" + str(line) + "\"\n")
301 if line == "SELECTION?":
302 [x,y] = agent.select() # Gets your agent's selection
303 #print "Select " + str(x) + "," + str(y)
304 sys.stdout.write(str(x) + " " + str(y) + "\n")
305 elif line == "MOVE?":
306 [x,y] = agent.get_move() # Gets your agent's move
307 sys.stdout.write(str(x) + " " + str(y) + "\n")
308 elif line.split(" ")[0] == "QUIT":
309 agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
313 agent.update(line) # Updates agent.board
320 if __name__ == "__main__":
321 sys.exit(main(sys.argv))