X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=qchess%2Fsrc%2Fplayer.py;h=346674b227bc9296ade7bba59a19945733ceb555;hb=52068b63d49f02f4455a4415356ecfe38db72f59;hp=3e6fabadb566b04e856d3ea4e9709345b7498558;hpb=444244d5c7698bb7861cdb7c0ec6bfb0e8cebfb7;p=progcomp2013.git diff --git a/qchess/src/player.py b/qchess/src/player.py index 3e6faba..346674b 100644 --- a/qchess/src/player.py +++ b/qchess/src/player.py @@ -1,7 +1,7 @@ import subprocess import select import platform - +import re agent_timeout = -1.0 # Timeout in seconds for AI players to make moves # WARNING: Won't work for windows based operating systems @@ -15,13 +15,155 @@ class Player(): self.name = name self.colour = colour + def update(self, result): + return result + + def reset_board(self, s): + pass + + def __str__(self): + return self.name + "<"+str(self.colour)+">" + + 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") + + + + + + def update(self, result): + sys.stderr.write("update fifo called\n") + 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") + 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") + 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): + 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 AgentPlayer(Player): +class ExternalAgent(Player): def __init__(self, name, colour): Player.__init__(self, name, colour) - self.p = subprocess.Popen(name, stdin=subprocess.PIPE, stdout=subprocess.PIPE,stderr=subprocess.PIPE) + self.p = subprocess.Popen(name,bufsize=0,stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=True,universal_newlines=True) self.send_message(colour) @@ -31,13 +173,13 @@ class AgentPlayer(Player): else: ready = [self.p.stdin] if self.p.stdin in ready: - #print "Writing to p.stdin" + #sys.stderr.write("Writing \'" + s + "\' to " + str(self.p) + "\n") try: self.p.stdin.write(s + "\n") except: raise Exception("UNRESPONSIVE") else: - raise Exception("UNRESPONSIVE") + raise Exception("TIMEOUT") def get_response(self): if agent_timeout > 0.0: @@ -45,13 +187,15 @@ class AgentPlayer(Player): else: ready = [self.p.stdout] if self.p.stdout in ready: - #print "Reading from p.stdout" + #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n") try: - return self.p.stdout.readline().strip("\r\n") + result = self.p.stdout.readline().strip(" \t\r\n") + #sys.stderr.write("Read \'" + result + "\' from " + str(self.p) + "\n") + return result except: # Exception, e: raise Exception("UNRESPONSIVE") else: - raise Exception("UNRESPONSIVE") + raise Exception("TIMEOUT") def select(self): @@ -59,7 +203,8 @@ class AgentPlayer(Player): line = self.get_response() try: - result = map(int, line.split(" ")) + m = re.match("\s*(\d+)\s+(\d+)\s*", line) + result = map(int, [m.group(1), m.group(2)]) except: raise Exception("GIBBERISH \"" + str(line) + "\"") return result @@ -67,7 +212,7 @@ class AgentPlayer(Player): def update(self, result): #print "Update " + str(result) + " called for AgentPlayer" self.send_message(result) - + return result def get_move(self): @@ -75,11 +220,19 @@ class AgentPlayer(Player): line = self.get_response() try: - result = map(int, line.split(" ")) + m = re.match("\s*(\d+)\s+(\d+)\s*", line) + result = map(int, [m.group(1), m.group(2)]) + except: raise Exception("GIBBERISH \"" + str(line) + "\"") return result + def reset_board(self, s): + self.send_message("BOARD") + for line in s.split("\n"): + self.send_message(line.strip(" \r\n")) + self.send_message("END BOARD") + def quit(self, final_result): try: self.send_message("QUIT " + final_result) @@ -145,16 +298,35 @@ class HumanPlayer(Player): pass else: sys.stdout.write(result + "\n") + return result -# Player that makes random moves -class AgentRandom(Player): +# Default internal player (makes random moves) +class InternalAgent(Player): def __init__(self, name, colour): Player.__init__(self, name, colour) self.choice = None self.board = Board(style = "agent") + + + def update(self, result): + + self.board.update(result) + #self.board.verify() + return result + + def reset_board(self, s): + self.board.reset_board(s) + + def quit(self, final_result): + pass + +class AgentRandom(InternalAgent): + def __init__(self, name, colour): + InternalAgent.__init__(self, name, colour) + def select(self): while True: self.choice = self.board.pieces[self.colour][random.randint(0, len(self.board.pieces[self.colour])-1)] @@ -179,12 +351,46 @@ class AgentRandom(Player): move = moves[random.randint(0, len(moves)-1)] return move - def update(self, result): - #sys.stderr.write(sys.argv[0] + " : Update board for AgentRandom\n") - self.board.update(result) - self.board.verify() - def quit(self, final_result): - pass +# 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) +