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
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)
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:
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):
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 update(self, result):
#print "Update " + str(result) + " called for AgentPlayer"
self.send_message(result)
-
+ return result
def get_move(self):
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)
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)]
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)
+