6 agent_timeout = -1.0 # Timeout in seconds for AI players to make moves
7 # WARNING: Won't work for windows based operating systems
9 if platform.system() == "Windows":
10 agent_timeout = -1 # Hence this
12 # A player who can't play
14 def __init__(self, name, colour):
18 def update(self, result):
21 def reset_board(self, s):
25 return self.name + "<"+str(self.colour)+">"
27 def base_player(self):
34 def open_fifo(name, mode, timeout=None):
36 return open(name, mode)
39 class Worker(threading.Thread):
41 threading.Thread.__init__(self)
48 self.result = open(name, mode)
58 while time.time() - start < timeout:
59 if w.is_alive() == False:
61 if w.exception != None:
68 #sys.stderr.write("FIFO_TIMEOUT!\n")
69 # Recursive to deal with possible race condition
72 f = open_fifo(name, "w", 1)
74 f = open_fifo(name, "r", 1)
78 #sys.stderr.write("Opened other end!\n")
85 raise Exception("FIFO_TIMEOUT")
88 if w.exception != None:
93 # Player that runs through a fifo
94 class FifoPlayer(Player):
98 def __init__(self, name, colour):
99 Player.__init__(self, name, colour)
100 os.mkfifo(self.name+".in")
101 os.mkfifo(self.name+".out")
105 self.fifo_out = open_fifo(self.name+".out","w", FifoPlayer.timeout)
107 raise Exception("FIFO_TIMEOUT")
109 self.fifo_out.write("START "+colour+"\n")
110 self.fifo_out.close()
113 def update(self, result):
114 sys.stderr.write("update fifo called\n")
116 self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout)
118 raise Exception("FIFO_TIMEOUT")
120 self.fifo_out.write(result +"\n")
121 self.fifo_out.close()
125 sys.stderr.write("select fifo called\n")
127 self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout)
129 #sys.stderr.write("TIMEOUT\n")
130 raise Exception("FIFO_TIMEOUT")
133 self.fifo_out.write("SELECT?\n")
134 self.fifo_out.close()
135 self.fifo_in = open_fifo(self.name+".in", "r", FifoPlayer.timeout)
136 s = map(int, self.fifo_in.readline().strip(" \r\n").split(" "))
141 sys.stderr.write("get_move fifo called\n")
143 self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout)
145 raise Exception("FIFO_TIMEOUT")
147 self.fifo_out.write("MOVE?\n")
148 self.fifo_out.close()
149 self.fifo_in = open_fifo(self.name+".in", "r", FifoPlayer.timeout)
150 s = map(int, self.fifo_in.readline().strip(" \r\n").split(" "))
154 def quit(self, result):
156 self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout)
160 self.fifo_out.write(result + "\n")
161 self.fifo_out.close()
164 os.remove(self.name+".in")
165 os.remove(self.name+".out")
169 # Player that runs from another process
170 class ExternalAgent(Player):
173 def __init__(self, name, colour):
174 Player.__init__(self, name, colour)
175 #raise Exception("waht")
176 self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True)
178 self.send_message(colour)
180 def send_message(self, s):
181 if agent_timeout > 0.0:
182 ready = select.select([], [self.p.stdin], [], agent_timeout)[1]
184 ready = [self.p.stdin]
185 if self.p.stdin in ready:
186 #sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n")
188 self.p.stdin.write(s + "\n")
190 raise Exception("UNRESPONSIVE")
192 raise Exception("TIMEOUT")
194 def get_response(self):
195 if agent_timeout > 0.0:
196 ready = select.select([self.p.stdout], [], [], agent_timeout)[0]
198 ready = [self.p.stdout]
199 if self.p.stdout in ready:
200 #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
202 result = self.p.stdout.readline().strip(" \t\r\n")
203 #sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n")
205 except: # Exception, e:
206 raise Exception("UNRESPONSIVE")
208 raise Exception("TIMEOUT")
212 self.send_message("SELECTION?")
213 line = self.get_response()
216 m = re.match("\s*(\d+)\s+(\d+)\s*", line)
217 result = map(int, [m.group(1), m.group(2)])
219 raise Exception("GIBBERISH \"" + str(line) + "\"")
222 def update(self, result):
223 #print "Update " + str(result) + " called for AgentPlayer"
224 self.send_message(result)
229 self.send_message("MOVE?")
230 line = self.get_response()
233 m = re.match("\s*(\d+)\s+(\d+)\s*", line)
234 result = map(int, [m.group(1), m.group(2)])
237 raise Exception("GIBBERISH \"" + str(line) + "\"")
240 def reset_board(self, s):
241 self.send_message("BOARD")
242 for line in s.split("\n"):
243 self.send_message(line.strip(" \r\n"))
244 self.send_message("END BOARD")
246 def quit(self, final_result):
248 self.send_message("QUIT " + final_result)
252 # So you want to be a player here?
253 class HumanPlayer(Player):
254 def __init__(self, name, colour):
255 Player.__init__(self, name, colour)
258 # Select your preferred account
260 if isinstance(graphics, GraphicsThread):
261 # Basically, we let the graphics thread do some shit and then return that information to the game thread
262 graphics.cond.acquire()
263 # We wait for the graphics thread to select a piece
264 while graphics.stopped() == False and graphics.state["select"] == None:
265 graphics.cond.wait() # The difference between humans and machines is that humans sleep
266 select = graphics.state["select"]
269 graphics.cond.release()
270 if graphics.stopped():
272 return [select.x, select.y]
274 # Since I don't display the board in this case, I'm not sure why I filled it in...
276 sys.stdout.write("SELECTION?\n")
278 p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
281 sys.stderr.write("ILLEGAL GIBBERISH\n")
284 # It's your move captain
286 if isinstance(graphics, GraphicsThread):
287 graphics.cond.acquire()
288 while graphics.stopped() == False and graphics.state["dest"] == None:
290 graphics.cond.release()
292 return graphics.state["dest"]
296 sys.stdout.write("MOVE?\n")
298 p = map(int, sys.stdin.readline().strip("\r\n ").split(" "))
301 sys.stderr.write("ILLEGAL GIBBERISH\n")
304 # Are you sure you want to quit?
305 def quit(self, final_result):
307 sys.stdout.write("QUIT " + final_result + "\n")
309 # Completely useless function
310 def update(self, result):
311 if isinstance(graphics, GraphicsThread):
314 sys.stdout.write(result + "\n")
318 # Default internal player (makes random moves)
319 class InternalAgent(Player):
320 def __init__(self, name, colour):
321 Player.__init__(self, name, colour)
324 self.board = Board(style = "agent")
327 return "@internal:"+self.name
329 def update(self, result):
331 self.board.update(result)
335 def reset_board(self, s):
336 self.board.reset_board(s)
338 def quit(self, final_result):
341 class AgentRandom(InternalAgent):
342 def __init__(self, name, colour):
343 InternalAgent.__init__(self, name, colour)
347 self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)]
349 # Check that the piece has some possibility to move
350 tmp = self.choice.current_type
351 if tmp == "unknown": # For unknown pieces, try both types
352 for t in self.choice.types:
355 self.choice.current_type = t
356 all_moves += self.board.possible_moves(self.choice)
358 all_moves = self.board.possible_moves(self.choice)
359 self.choice.current_type = tmp
360 if len(all_moves) > 0:
362 return [self.choice.x, self.choice.y]
365 moves = self.board.possible_moves(self.choice)
366 move = moves[random.randint(0, len(moves)-1)]
370 # Terrible, terrible hacks
372 def run_agent(agent):
373 #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n")
375 line = sys.stdin.readline().strip(" \r\n")
376 if line == "SELECTION?":
377 #sys.stderr.write(sys.argv[0] + " : Make selection\n")
378 [x,y] = agent.select() # Gets your agent's selection
379 #sys.stderr.write(sys.argv[0] + " : Selection was " + str(agent.choice) + "\n")
380 sys.stdout.write(str(x) + " " + str(y) + "\n")
381 elif line == "MOVE?":
382 #sys.stderr.write(sys.argv[0] + " : Make move\n")
383 [x,y] = agent.get_move() # Gets your agent's move
384 sys.stdout.write(str(x) + " " + str(y) + "\n")
385 elif line.split(" ")[0] == "QUIT":
386 #sys.stderr.write(sys.argv[0] + " : Quitting\n")
387 agent.quit(" ".join(line.split(" ")[1:])) # Quits the game
389 elif line.split(" ")[0] == "BOARD":
391 line = sys.stdin.readline().strip(" \r\n")
392 while line != "END BOARD":
394 line = sys.stdin.readline().strip(" \r\n")
395 agent.board.reset_board(s)
398 agent.update(line) # Updates agent.board
404 class ExternalWrapper(ExternalAgent):
405 def __init__(self, agent):
406 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))\""
408 ExternalAgent.__init__(self, run, agent.colour)