From 9b5054e5a06872ae85aca693079c17a0cd40c339 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Sun, 19 May 2013 00:54:42 +0800 Subject: [PATCH] cgi-script almost working --- qchess/qchess.cgi | 155 +++++++++++++++++++++++++++++ qchess/qchess.py | 187 +++++++++++++++++++++++++---------- qchess/src/agent_bishop.py | 5 +- qchess/src/board.py | 10 +- qchess/src/game.py | 51 +++++----- qchess/src/main.py | 15 ++- qchess/src/player.py | 118 +++++++++++++++++----- qchess/src/server.py | 6 +- qchess/src/thread_util.py | 2 +- qchess/src/timeout_player.py | 7 +- web/qchess.cgi | 55 ----------- 11 files changed, 445 insertions(+), 166 deletions(-) create mode 100755 qchess/qchess.cgi delete mode 100755 web/qchess.cgi diff --git a/qchess/qchess.cgi b/qchess/qchess.cgi new file mode 100755 index 0000000..96e45a1 --- /dev/null +++ b/qchess/qchess.cgi @@ -0,0 +1,155 @@ +#!/usr/bin/python + +# CGI wrapper to qchess + +import sys +import os + +import cgi +import subprocess +import time +import threading + + +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 + + def run(self): + self.result = open(name, mode) + + + w = Worker() + w.start() + + start = time.time() + while time.time() - start < timeout: + if w.is_alive() == False: + w.join() + return w.result + time.sleep(0.1) + + + if w.is_alive(): + #sys.stderr.write("FIFO_TIMEOUT!\n") + if mode == "r": + f = open(name, "w") + else: + f = open(name, "r") + + #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() + return w.result + +def quit(): + try: + fifo_out = open_fifo("../cgi-data/"+client+".in", "w", 5) + except: + pass + else: + fifo_out.write("quit\n") + fifo_out.close() + + try: + fifo_in = open_fifo("../cgi-data/"+client+".out", "w", 5) + except: + pass + else: + s = fifo_in.readline().strip(" \r\n") + while s != "": + #print s + s = fifo_in.readline().strip(" \r\n") + fifo_in.close() + time.sleep(0.5) + + + + +def main(argv): + global client + #form = cgi.FieldStorage() + #client = cgi.escape(os.environ["REMOTE_ADDR"]) + + client = "127.0.0.1" + + + print "Content-Type: text/plain\r\n\r\n" + + + try: + request = argv[1] + except: + request = None + + + try: + x = int(argv[1]) + y = int(argv[2]) + except: + if request == "quit": + quit() + return 0 + + if os.path.exists("../cgi-bin/"+client+".in") and os.path.exists("../cgi-bin/"+client+".out"): + print "Error: Game in progress expects x and y" + return 1 + else: + print "NEW GAME" + args = ["./qchess.py"] + if request == None: + args += ["@fifo:../cgi-data/"+client, "@internal:AgentBishop"] + elif request == "eigengame": + args += ["--server=progcomp.ucc.asn.au", "@fifo:../cgi-data/"+client] + subprocess.Popen(args) + time.sleep(1) + + else: + + fifo_out = open_fifo("../cgi-data/"+client+".in", "w") + fifo_out.write("%d %d\n" % (x, y)) + fifo_out.close() + + + + sys.stderr.write("\ncgi read from fifo here\n") + try: + fifo_in = open_fifo("../cgi-data/"+client+".out", "r") + except: + quit() + else: + sys.stderr.write("Opened fine\n") + s = fifo_in.readline().strip(" \r\n") + + while s != "SELECT?" and s != "MOVE?" and s.split(" ")[0] not in ["white", "black"]: + if s != "": + print s + s = fifo_in.readline().strip(" \r\n") + print s + fifo_in.close() + if s.split(" ")[0] in ["white", "black"]: + quit() + + sys.stderr.write("Done\n") + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main(sys.argv)) + except Exception, e: + print "Exception: ", e + sys.exit(1) diff --git a/qchess/qchess.py b/qchess/qchess.py index 0e03777..0ff4209 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -651,9 +651,60 @@ 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 + + + def run(self): + self.result = open(name, mode) + + + w = Worker() + w.start() + + start = time.time() + while time.time() - start < timeout: + if w.is_alive() == False: + w.join() + return w.result + time.sleep(0.1) + + + if w.is_alive(): + #sys.stderr.write("FIFO_TIMEOUT!\n") + if mode == "r": + f = open(name, "w") + else: + f = open(name, "r") + + #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() + 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") @@ -665,37 +716,58 @@ class FifoPlayer(Player): 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: + os.remove(self.name+".in") + os.remove(self.name+".out") + #raise Exception("FIFO_TIMEOUT") + + else: + self.fifo_out.write(result + "\n") + self.fifo_out.close() + os.remove(self.name+".in") + os.remove(self.name+".out") # Player that runs from another process class ExternalAgent(Player): @@ -1136,8 +1208,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 +1233,7 @@ def TimeoutFunction(function, args, timeout): w.terminate() s.join() raise Exception("TIMEOUT") - + time.sleep(0.1) @@ -1383,8 +1458,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 @@ -1600,8 +1674,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,28 +1777,31 @@ 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(): + if self.stopped(): + break + except Exception,e: + #if False: + result = e.message + #sys.stderr.write(result + "\n") + + self.stop() + + with self.lock: + self.final_result = self.state["turn"].colour + " " + e.message break + for p2 in self.players: p2.quit(self.final_result) @@ -2501,7 +2578,7 @@ def dedicated_server(): return 0 -def client(addr): +def client(addr, player="@human"): @@ -2516,9 +2593,9 @@ def client(addr): 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 --- # #!/usr/bin/python -u @@ -2722,7 +2799,13 @@ 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].name) + else: + return client(server_addr) # Create the board @@ -2891,4 +2974,4 @@ if __name__ == "__main__": # --- main.py --- # -# EOF - created from make on Thu May 16 23:54:28 WST 2013 +# EOF - created from make on Sun May 19 00:54:03 WST 2013 diff --git a/qchess/src/agent_bishop.py b/qchess/src/agent_bishop.py index 0323edb..20cb4c0 100644 --- a/qchess/src/agent_bishop.py +++ b/qchess/src/agent_bishop.py @@ -2,10 +2,9 @@ class AgentBishop(AgentRandom): # Inherits from AgentRandom (in qchess) - def __init__(self, name, colour): + def __init__(self, name, colour,value={"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 2}): InternalAgent.__init__(self, name, colour) - self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4} - + self.value = value self.aggression = 2.0 # Multiplier for scoring due to aggressive actions self.defence = 1.0 # Multiplier for scoring due to defensive actions diff --git a/qchess/src/board.py b/qchess/src/board.py index f4229be..adcf429 100644 --- a/qchess/src/board.py +++ b/qchess/src/board.py @@ -332,6 +332,12 @@ class Board(): return result def prob_is_type(self, p, state): + if p.current_type != 0: + if state == p.current_type: + return 1.0 + else: + return 0.0 + prob = 0.5 result = 0 for i in range(len(p.types)): @@ -487,6 +493,8 @@ class Board(): def on_board(self, x, y): return (x >= 0 and x < w) and (y >= 0 and y < h) + + # Pushes a move temporarily def push_move(self, piece, x, y): target = self.grid[x][y] @@ -512,5 +520,5 @@ class Board(): self.grid[x2][y2] = target for p in self.pieces["white"] + self.pieces["black"]: - p.possible_moves = None + p.possible_moves = None diff --git a/qchess/src/game.py b/qchess/src/game.py index f1f48bb..6972c5c 100644 --- a/qchess/src/game.py +++ b/qchess/src/game.py @@ -29,8 +29,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") @@ -80,10 +80,10 @@ class GameThread(StoppableThread): graphics.state["dest"] = None continue - try: - [x2,y2] = p.get_move() # Player selects a destination - except: - self.stop() + #try: + [x2,y2] = p.get_move() # Player selects a destination + #except: + # self.stop() if self.stopped(): #debug("Quitting in get_move") @@ -132,28 +132,31 @@ 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(): + if self.stopped(): + break + except Exception,e: + #if False: + result = e.message + #sys.stderr.write(result + "\n") + + self.stop() + + with self.lock: + self.final_result = self.state["turn"].colour + " " + e.message break + for p2 in self.players: p2.quit(self.final_result) diff --git a/qchess/src/main.py b/qchess/src/main.py index ea50a1f..6ebf70c 100644 --- a/qchess/src/main.py +++ b/qchess/src/main.py @@ -60,7 +60,11 @@ def make_player(name, colour): sys.stderr.write(sys.argv[0] + " : Can't find an internal agent matching \"" + s[1] + "\"\n") sys.stderr.write(sys.argv[0] + " : Choices are: " + str(map(lambda e : e[0], internal_agents)) + "\n") return None - + if s[0] == "fifo": + if len(s) > 1: + return FifoPlayer(s[1], colour) + else: + return FifoPlayer(str(os.getpid())+"."+colour, colour) else: return ExternalAgent(name, colour) @@ -195,7 +199,13 @@ 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].name) + else: + return client(server_addr) # Create the board @@ -244,6 +254,7 @@ def main(argv): server_addr = graphics.SelectServer() if server_addr != None: + pygame.quit() # Time to say goodbye if server_addr == True: return dedicated_server() else: diff --git a/qchess/src/player.py b/qchess/src/player.py index fb6cbcd..1f40066 100644 --- a/qchess/src/player.py +++ b/qchess/src/player.py @@ -26,9 +26,60 @@ 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 + + + def run(self): + self.result = open(name, mode) + + + w = Worker() + w.start() + + start = time.time() + while time.time() - start < timeout: + if w.is_alive() == False: + w.join() + return w.result + time.sleep(0.1) + + + if w.is_alive(): + #sys.stderr.write("FIFO_TIMEOUT!\n") + if mode == "r": + f = open(name, "w") + else: + f = open(name, "r") + + #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() + 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") @@ -40,37 +91,58 @@ class FifoPlayer(Player): 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: + os.remove(self.name+".in") + os.remove(self.name+".out") + #raise Exception("FIFO_TIMEOUT") + + else: + self.fifo_out.write(result + "\n") + self.fifo_out.close() + os.remove(self.name+".in") + os.remove(self.name+".out") # Player that runs from another process class ExternalAgent(Player): diff --git a/qchess/src/server.py b/qchess/src/server.py index 2bae000..5479997 100644 --- a/qchess/src/server.py +++ b/qchess/src/server.py @@ -59,7 +59,7 @@ def dedicated_server(): return 0 -def client(addr): +def client(addr, player="@human"): @@ -74,8 +74,8 @@ def client(addr): 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 \ No newline at end of file diff --git a/qchess/src/thread_util.py b/qchess/src/thread_util.py index 2c79330..d8fd050 100644 --- a/qchess/src/thread_util.py +++ b/qchess/src/thread_util.py @@ -12,4 +12,4 @@ class StoppableThread(threading.Thread): self._stop.set() def stopped(self): - return self._stop.isSet() + return self._stop.isSet() \ No newline at end of file diff --git a/qchess/src/timeout_player.py b/qchess/src/timeout_player.py index 937c94c..1bd53c9 100644 --- a/qchess/src/timeout_player.py +++ b/qchess/src/timeout_player.py @@ -22,8 +22,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 @@ -44,7 +47,7 @@ def TimeoutFunction(function, args, timeout): w.terminate() s.join() raise Exception("TIMEOUT") - + time.sleep(0.1) diff --git a/web/qchess.cgi b/web/qchess.cgi deleted file mode 100755 index e0c1460..0000000 --- a/web/qchess.cgi +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/python - -# CGI wrapper to qchess - -import sys -import os - -import cgi -import subprocess - -def main(argv): - form = cgi.FieldStorage() - client = cgi.escape(os.environ["REMOTE_ADDR"]) - - print "Content-Type: text/plain\r\n\r\n" - - try: - with open(client): pass - except IOError: - args = ["python", "../qchess/qchess.py", "--no-graphics", "@fifo:"+client, "@internal:AgentBishop"] - subprocess.Popen(args) - form["mode"] = "query" - - if form["mode"] == "response": - x = int(form["x"]) - y = int(form["y"]) - fifo_out = open(client+".in", "w") - fifo_out.write("%d %d\n" % (x, y)) - fifo_out.close() - form["mode"] = "query" - - - if form["mode"] == "query": - fifo_in = open(client+".out", "r") - s = fifo_in.readline().strip(" \r\n") - while s != "SELECT?" and s != "MOVE?" and s.split(" ")[0] != "white" and s.split(" ")[0] != "black": - print s - s = fifo_in.readline().strip(" \r\n") - print s - fifo_in.close() - form["mode"] = "response" - - if s == "quit": - os.remove(client) - - - return 0 - - -if __name__ == "__main__": - try: - sys.exit(main(sys.argv)) - except, e: - print "Exception: ", e - sys.exit(1) -- 2.20.1