X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;ds=inline;f=qchess%2Fqchess.py;h=1279ec16f8541ab9ecda0a9161fa4955eb83c14e;hb=HEAD;hp=0e03777c7a3ba7e7a85f19d9e73a568fe7e0d4d4;hpb=5d8f204c6bde7cd0f4534e0904d20ad26df4ef5e;p=progcomp2013.git diff --git a/qchess/qchess.py b/qchess/qchess.py index 0e03777..1279ec1 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -652,50 +652,144 @@ class Player(): def base_player(self): return self + + + + +def open_fifo(name, mode, timeout=None): + if timeout == None: + return open(name, mode) + + + class Worker(threading.Thread): + def __init__(self): + threading.Thread.__init__(self) + self.result = None + self.exception = None + + + def run(self): + try: + self.result = open(name, mode) + except Exception, e: + self.exception = e + self.result = None + + + w = Worker() + w.start() + + start = time.time() + while time.time() - start < timeout: + if w.is_alive() == False: + w.join() + if w.exception != None: + raise w.exception + return w.result + time.sleep(0.1) + + + if w.is_alive(): + #sys.stderr.write("FIFO_TIMEOUT!\n") + # Recursive to deal with possible race condition + try: + if mode == "r": + f = open_fifo(name, "w", 1) + else: + f = open_fifo(name, "r", 1) + except: + pass + + #sys.stderr.write("Opened other end!\n") + while w.is_alive(): + time.sleep(0.1) + + w.join() + f.close() + w.result.close() + raise Exception("FIFO_TIMEOUT") + else: + w.join() + if w.exception != None: + raise w.exception + return w.result + + # Player that runs through a fifo class FifoPlayer(Player): + + timeout = 300 + def __init__(self, name, colour): Player.__init__(self, name, colour) os.mkfifo(self.name+".in") os.mkfifo(self.name+".out") - - - - - + + + try: + self.fifo_out = open_fifo(self.name+".out","w", FifoPlayer.timeout) + except: + raise Exception("FIFO_TIMEOUT") + else: + self.fifo_out.write("START "+colour+"\n") + self.fifo_out.close() + + def update(self, result): sys.stderr.write("update fifo called\n") - self.fifo_out = open(self.name+".out", "w") - self.fifo_out.write(result +"\n") - self.fifo_out.close() - return result + try: + self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout) + except: + raise Exception("FIFO_TIMEOUT") + else: + self.fifo_out.write(result +"\n") + self.fifo_out.close() + return result def select(self): sys.stderr.write("select fifo called\n") - self.fifo_out = open(self.name+".out", "w") - self.fifo_out.write("SELECT?\n") - self.fifo_out.close() - self.fifo_in = open(self.name+".in", "r") - s = map(int, self.fifo_in.readline().strip(" \r\n").split(" ")) - self.fifo_in.close() - return s + try: + self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout) + except: + #sys.stderr.write("TIMEOUT\n") + raise Exception("FIFO_TIMEOUT") + else: + + self.fifo_out.write("SELECT?\n") + self.fifo_out.close() + self.fifo_in = open_fifo(self.name+".in", "r", FifoPlayer.timeout) + s = map(int, self.fifo_in.readline().strip(" \r\n").split(" ")) + self.fifo_in.close() + return s def get_move(self): sys.stderr.write("get_move fifo called\n") - self.fifo_out = open(self.name+".out", "w") - self.fifo_out.write("MOVE?\n") - self.fifo_out.close() - self.fifo_in = open(self.name+".in", "r") - s = map(int, self.fifo_in.readline().strip(" \r\n").split(" ")) - self.fifo_in.close() - return s + try: + self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout) + except: + raise Exception("FIFO_TIMEOUT") + else: + self.fifo_out.write("MOVE?\n") + self.fifo_out.close() + self.fifo_in = open_fifo(self.name+".in", "r", FifoPlayer.timeout) + s = map(int, self.fifo_in.readline().strip(" \r\n").split(" ")) + self.fifo_in.close() + return s def quit(self, result): - self.fifo_out = open(self.name+".out", "w") - self.fifo_out.write(result + "\n") - self.fifo_out.close() - os.remove(self.name+".in") - os.remove(self.name+".out") + try: + self.fifo_out = open_fifo(self.name+".out", "w", FifoPlayer.timeout) + except: + pass + else: + self.fifo_out.write(result + "\n") + self.fifo_out.close() + + try: + os.remove(self.name+".in") + os.remove(self.name+".out") + except OSError: + pass # Player that runs from another process class ExternalAgent(Player): @@ -703,6 +797,7 @@ class ExternalAgent(Player): def __init__(self, name, colour): Player.__init__(self, name, colour) + #raise Exception("waht") self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True) self.send_message(colour) @@ -784,6 +879,7 @@ class HumanPlayer(Player): def __init__(self, name, colour): Player.__init__(self, name, colour) + # Select your preferred account def select(self): if isinstance(graphics, GraphicsThread): @@ -805,9 +901,11 @@ class HumanPlayer(Player): sys.stdout.write("SELECTION?\n") try: p = map(int, sys.stdin.readline().strip("\r\n ").split(" ")) + return p except: sys.stderr.write("ILLEGAL GIBBERISH\n") continue + # It's your move captain def get_move(self): if isinstance(graphics, GraphicsThread): @@ -823,6 +921,7 @@ class HumanPlayer(Player): sys.stdout.write("MOVE?\n") try: p = map(int, sys.stdin.readline().strip("\r\n ").split(" ")) + return p except: sys.stderr.write("ILLEGAL GIBBERISH\n") continue @@ -849,7 +948,8 @@ class InternalAgent(Player): self.board = Board(style = "agent") - + def argForm(self): + return "@internal:"+self.name def update(self, result): @@ -1136,8 +1236,11 @@ class Worker(multiprocessing.Process): self.q = q def run(self): - #print str(self) + " runs " + str(self.function) + " with args " + str(self.args) + #print str(self) + " runs " + str(self.function) + " with args " + str(self.args) + #try: self.q.put(self.function(*self.args)) + #except IOError: + # pass @@ -1158,7 +1261,7 @@ def TimeoutFunction(function, args, timeout): w.terminate() s.join() raise Exception("TIMEOUT") - + time.sleep(0.1) @@ -1335,8 +1438,10 @@ class Network(): if self.src in ready: s = self.src.recv(1) else: - raise Exception("UNRESPONSIVE") + raise Exception("NET_UNRESPONSIVE") + + debug("Network get_response s = " + str(s)) while s[len(s)-1] != '\n': # Timeout on each character in the message @@ -1347,7 +1452,7 @@ class Network(): if self.src in ready: s += self.src.recv(1) else: - raise Exception("UNRESPONSIVE") + raise Exception("NET_UNRESPONSIVE") return s.strip(" \r\n") @@ -1361,7 +1466,7 @@ class Network(): if self.src in ready: self.src.send(s + "\n") else: - raise Exception("UNRESPONSIVE") + raise Exception("NET_UNRESPONSIVE") @@ -1383,8 +1488,7 @@ class StoppableThread(threading.Thread): self._stop.set() def stopped(self): - return self._stop.isSet() -# --- thread_util.py --- # + return self._stop.isSet()# --- thread_util.py --- # log_files = [] import datetime import urllib2 @@ -1586,11 +1690,10 @@ class GameThread(StoppableThread): self.cond = threading.Condition() # conditional for some reason, I forgot self.final_result = "" self.server = server + self.retry_illegal = False - - - + # Run the game (run in new thread with start(), run in current thread with run()) def run(self): @@ -1600,8 +1703,8 @@ class GameThread(StoppableThread): for p in self.players: with self.lock: self.state["turn"] = p.base_player() - #try: - if True: + try: + #if True: [x,y] = p.select() # Player selects a square if self.stopped(): #debug("Quitting in select") @@ -1703,26 +1806,32 @@ class GameThread(StoppableThread): graphics.state["dest"] = None graphics.state["moves"] = None - # Commented out exception stuff for now, because it makes it impossible to tell if I made an IndentationError somewhere - # except Exception,e: - # result = e.message - # #sys.stderr.write(result + "\n") - # - # self.stop() - # with self.lock: - # self.final_result = self.state["turn"].colour + " " + e.message - - end = self.board.end_condition() - if end != None: - with self.lock: - if end == "DRAW": - self.final_result = self.state["turn"].colour + " " + end - else: - self.final_result = end - self.stop() + + end = self.board.end_condition() + if end != None: + with self.lock: + if end == "DRAW": + self.final_result = self.state["turn"].colour + " " + end + else: + self.final_result = end + self.stop() - if self.stopped(): - break + if self.stopped(): + break + except Exception,e: + #if False: + + + result = e.message + if self.retry_illegal: + self.state["turn"].update(result); + else: + sys.stderr.write("qchess.py exception: "+result + "\n") + self.stop() + with self.lock: + self.final_result = self.state["turn"].colour + " " + e.message + break + for p2 in self.players: @@ -2501,26 +2610,27 @@ def dedicated_server(): return 0 -def client(addr): - +def client(addr, player="@human"): + debug("Client " + player + " starts") s = socket.socket() s.connect((addr, 4562)) [colour,port] = s.recv(1024).strip(" \r\n").split(" ") - #debug("Colour: " + colour + ", port: " + port) + debug("Colour: " + colour + ", port: " + port) s.shutdown(socket.SHUT_RDWR) s.close() if colour == "white": - p = subprocess.Popen(["python", "qchess.py", "@human", "@network:"+addr+":"+port]) + p = subprocess.Popen(["python", "qchess.py", player, "@network:"+addr+":"+port]) else: - p = subprocess.Popen(["python", "qchess.py", "@network:"+addr+":"+port, "@human"]) + p = subprocess.Popen(["python", "qchess.py", "@network:"+addr+":"+port, player]) p.wait() - return 0# --- server.py --- # + return 0 +# --- server.py --- # #!/usr/bin/python -u # Do you know what the -u does? It unbuffers stdin and stdout @@ -2543,6 +2653,7 @@ sleep_timeout = None [game, graphics] = [None, None] def make_player(name, colour): + debug(name) if name[0] == '@': if name[1:] == "human": return HumanPlayer(name, colour) @@ -2611,6 +2722,7 @@ def main(argv): global sleep_timeout + retry_illegal = False server_addr = None max_moves = None @@ -2632,17 +2744,7 @@ def main(argv): i += 1 arg = argv[i] if arg[0] != '-': - p = make_player(arg, colour) - if not isinstance(p, Player): - sys.stderr.write(sys.argv[0] + " : Fatal error creating " + colour + " player\n") - return 100 - players.append(p) - if colour == "white": - colour = "black" - elif colour == "black": - pass - else: - sys.stderr.write(sys.argv[0] + " : Too many players (max 2)\n") + players.append(arg) continue # Option parsing goes here @@ -2708,7 +2810,8 @@ def main(argv): sleep_timeout = -1 else: sleep_timeout = float(arg[2:].split("=")[1]) - + elif (arg[1] == '-' and arg[2:] == "retry-illegal"): + retry_illegal = not retry_illegal elif (arg[1] == '-' and arg[2:] == "help"): # Help os.system("less data/help.txt") # The best help function @@ -2722,9 +2825,27 @@ def main(argv): if server_addr == True: return dedicated_server() else: - return client(server_addr) + if len(players) > 1: + sys.stderr.write("Only a single player may be provided when --server is used\n") + return 1 + if len(players) == 1: + return client(server_addr, players[0]) + else: + return client(server_addr) + + for i in xrange(len(players)): + p = make_player(players[i], colour) + if not isinstance(p, Player): + sys.stderr.write(sys.argv[0] + " : Fatal error creating " + colour + " player\n") + return 100 + players[i] = p + if colour == "white": + colour = "black" + elif colour == "black": + pass + else: + sys.stderr.write(sys.argv[0] + " : Too many players (max 2)\n") - # Create the board # Construct a GameThread! Make it global! Damn the consequences! @@ -2749,6 +2870,7 @@ def main(argv): board = Board(style) board.max_moves = max_moves game = GameThread(board, players) + game.retry_illegal = retry_illegal @@ -2891,4 +3013,4 @@ if __name__ == "__main__": # --- main.py --- # -# EOF - created from make on Thu May 16 23:54:28 WST 2013 +# EOF - created from make on Monday 24 June 23:55:46 WST 2013