+
+# Terrible, terrible hacks
+
+def run_agent(agent):
+ #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
+ while True:
+ line = sys.stdin.readline().strip(" \r\n")
+ if line == "SELECTION?":
+ #sys.stderr.write(sys.argv[0] + " : Make selection\n")
+ [x,y] = agent.select() # Gets your agent's selection
+ #sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
+ sys.stdout.write(str(x) + " " + str(y) + "\n")
+ elif line == "MOVE?":
+ #sys.stderr.write(sys.argv[0] + " : Make move\n")
+ [x,y] = agent.get_move() # Gets your agent's move
+ sys.stdout.write(str(x) + " " + str(y) + "\n")
+ elif line.split(" ")[0] == "QUIT":
+ #sys.stderr.write(sys.argv[0] + " : Quitting\n")
+ agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
+ break
+ elif line.split(" ")[0] == "BOARD":
+ s = ""
+ line = sys.stdin.readline().strip(" \r\n")
+ while line != "END BOARD":
+ s += line + "\n"
+ line = sys.stdin.readline().strip(" \r\n")
+ agent.board.reset_board(s)
+
+ else:
+ agent.update(line) # Updates agent.board
+ return 0
+
+
+# Sort of works?
+
+class ExternalWrapper(ExternalAgent):
+ def __init__(self, agent):
+ run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\""
+ # str(run)
+ ExternalAgent.__init__(self, run, agent.colour)
+
+
+
+# --- player.py --- #
+# A sample agent
+
+
+class AgentBishop(AgentRandom): # Inherits from AgentRandom (in qchess)
+ def __init__(self, name, colour):
+ InternalAgent.__init__(self, name, colour)
+ self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4}
+
+ self.aggression = 2.0 # Multiplier for scoring due to aggressive actions
+ self.defence = 1.0 # Multiplier for scoring due to defensive actions
+
+ self.depth = 0 # Current depth
+ self.max_depth = 2 # Recurse this many times (for some reason, makes more mistakes when this is increased???)
+ self.recurse_for = -1 # Recurse for the best few moves each times (less than 0 = all moves)
+
+ for p in self.board.pieces["white"] + self.board.pieces["black"]:
+ p.last_moves = None
+ p.selected_moves = None
+
+
+
+ def get_value(self, piece):
+ if piece == None:
+ return 0.0
+ return float(self.value[piece.types[0]] + self.value[piece.types[1]]) / 2.0
+
+ # Score possible moves for the piece
+
+ def prioritise_moves(self, piece):
+
+ #sys.stderr.write(sys.argv[0] + " : " + str(self) + " prioritise called for " + str(piece) + "\n")
+
+
+
+ grid = self.board.probability_grid(piece)
+ #sys.stderr.write("\t Probability grid " + str(grid) + "\n")
+ moves = []
+ for x in range(w):
+ for y in range(h):
+ if grid[x][y] < 0.3: # Throw out moves with < 30% probability
+ #sys.stderr.write("\tReject " + str(x) + "," + str(y) + " (" + str(grid[x][y]) + ")\n")
+ continue
+
+ target = self.board.grid[x][y]
+
+
+
+
+ # Get total probability that the move is protected
+ self.board.push_move(piece, x, y)
+
+
+
+ defenders = self.board.coverage(x, y, piece.colour, reject_allied = False)
+ d_prob = 0.0
+ for d in defenders.keys():
+ d_prob += defenders[d]
+ if len(defenders.keys()) > 0:
+ d_prob /= float(len(defenders.keys()))
+
+ if (d_prob > 1.0):
+ d_prob = 1.0
+
+ # Get total probability that the move is threatened
+ attackers = self.board.coverage(x, y, opponent(piece.colour), reject_allied = False)
+ a_prob = 0.0
+ for a in attackers.keys():
+ a_prob += attackers[a]
+ if len(attackers.keys()) > 0:
+ a_prob /= float(len(attackers.keys()))
+
+ if (a_prob > 1.0):
+ a_prob = 1.0
+
+ self.board.pop_move()
+
+
+
+ # Score of the move
+ value = self.aggression * (1.0 + d_prob) * self.get_value(target) - self.defence * (1.0 - d_prob) * a_prob * self.get_value(piece)
+
+ # Adjust score based on movement of piece out of danger
+ attackers = self.board.coverage(piece.x, piece.y, opponent(piece.colour))
+ s_prob = 0.0
+ for a in attackers.keys():
+ s_prob += attackers[a]
+ if len(attackers.keys()) > 0:
+ s_prob /= float(len(attackers.keys()))
+
+ if (s_prob > 1.0):
+ s_prob = 1.0
+ value += self.defence * s_prob * self.get_value(piece)
+
+ # Adjust score based on probability that the move is actually possible
+ moves.append([[x, y], grid[x][y] * value])
+
+ moves.sort(key = lambda e : e[1], reverse = True)
+ #sys.stderr.write(sys.argv[0] + ": Moves for " + str(piece) + " are " + str(moves) + "\n")
+
+ piece.last_moves = moves
+ piece.selected_moves = None
+
+
+
+
+ return moves
+
+ def select_best(self, colour):
+
+ self.depth += 1
+ all_moves = {}
+ for p in self.board.pieces[colour]:
+ self.choice = p # Temporarily pick that piece
+ m = self.prioritise_moves(p)
+ if len(m) > 0:
+ all_moves.update({p : m[0]})
+
+ if len(all_moves.items()) <= 0:
+ return None
+
+
+ opts = all_moves.items()
+ opts.sort(key = lambda e : e[1][1], reverse = True)
+
+ if self.depth >= self.max_depth:
+ self.depth -= 1
+ return list(opts[0])
+
+ if self.recurse_for >= 0:
+ opts = opts[0:self.recurse_for]
+ #sys.stderr.write(sys.argv[0] + " : Before recurse, options are " + str(opts) + "\n")
+
+ # Take the best few moves, and recurse
+ for choice in opts[0:self.recurse_for]:
+ [xx,yy] = [choice[0].x, choice[0].y] # Remember position
+ [nx,ny] = choice[1][0] # Target
+ [choice[0].x, choice[0].y] = [nx, ny] # Set position
+ target = self.board.grid[nx][ny] # Remember piece in spot
+ self.board.grid[xx][yy] = None # Remove piece
+ self.board.grid[nx][ny] = choice[0] # Replace with moving piece
+
+ # Recurse
+ best_enemy_move = self.select_best(opponent(choice[0].colour))
+ choice[1][1] -= best_enemy_move[1][1] / float(self.depth + 1.0)
+
+ [choice[0].x, choice[0].y] = [xx, yy] # Restore position
+ self.board.grid[nx][ny] = target # Restore taken piece
+ self.board.grid[xx][yy] = choice[0] # Restore moved piece
+
+
+
+ opts.sort(key = lambda e : e[1][1], reverse = True)
+ #sys.stderr.write(sys.argv[0] + " : After recurse, options are " + str(opts) + "\n")
+
+ self.depth -= 1
+ return list(opts[0])
+
+
+
+ # Returns [x,y] of selected piece
+ def select(self):
+ #sys.stderr.write("Getting choice...")
+ self.choice = self.select_best(self.colour)[0]
+
+ #sys.stderr.write(" Done " + str(self.choice)+"\n")
+ return [self.choice.x, self.choice.y]
+
+ # Returns [x,y] of square to move selected piece into
+ def get_move(self):
+ #sys.stderr.write("Choice is " + str(self.choice) + "\n")
+ self.choice.selected_moves = self.choice.last_moves
+ moves = self.prioritise_moves(self.choice)
+ if len(moves) > 0:
+ return moves[0][0]
+ else:
+ return AgentRandom.get_move(self)
+
+# --- agent_bishop.py --- #
+import multiprocessing
+
+# Hacky alternative to using select for timing out players
+
+# WARNING: Do not wrap around HumanPlayer or things breakify
+# WARNING: Do not use in general or things breakify
+
+class Sleeper(multiprocessing.Process):
+ def __init__(self, timeout):
+ multiprocessing.Process.__init__(self)
+ self.timeout = timeout
+
+ def run(self):
+ time.sleep(self.timeout)
+
+
+class Worker(multiprocessing.Process):
+ def __init__(self, function, args, q):
+ multiprocessing.Process.__init__(self)
+ self.function = function
+ self.args = args
+ self.q = q
+
+ def run(self):
+ #print str(self) + " runs " + str(self.function) + " with args " + str(self.args)
+ self.q.put(self.function(*self.args))
+
+
+
+def TimeoutFunction(function, args, timeout):
+ q = multiprocessing.Queue()
+ w = Worker(function, args, q)
+ s = Sleeper(timeout)
+ w.start()
+ s.start()
+ while True: # Busy loop of crappyness
+ if not w.is_alive():
+ s.terminate()
+ result = q.get()
+ w.join()
+ #print "TimeoutFunction gets " + str(result)
+ return result
+ elif not s.is_alive():
+ w.terminate()
+ s.join()
+ raise Exception("TIMEOUT")
+
+
+
+
+# A player that wraps another player and times out its moves
+# Uses threads
+# A (crappy) alternative to the use of select()
+class TimeoutPlayer(Player):
+ def __init__(self, base_player, timeout):
+ Player.__init__(self, base_player.name, base_player.colour)
+ self.base_player = base_player
+ self.timeout = timeout
+
+ def select(self):
+ return TimeoutFunction(self.base_player.select, [], self.timeout)
+
+
+ def get_move(self):
+ return TimeoutFunction(self.base_player.get_move, [], self.timeout)
+