X-Git-Url: https://git.ucc.asn.au/?p=progcomp2013.git;a=blobdiff_plain;f=qchess%2Fqchess.py;h=1279ec16f8541ab9ecda0a9161fa4955eb83c14e;hp=8a3610bd9cfc1d3e4ba1af9565d070f9d645d6b8;hb=HEAD;hpb=573931ea67fa99135eca781ff814933e04df4308 diff --git a/qchess/qchess.py b/qchess/qchess.py index 8a3610b..1279ec1 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -432,6 +432,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)): @@ -587,6 +593,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] @@ -612,7 +620,7 @@ class Board(): self.grid[x2][y2] = target for p in self.pieces["white"] + self.pieces["black"]: - p.possible_moves = None + p.possible_moves = None # --- board.py --- # import subprocess @@ -644,12 +652,152 @@ 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") + 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: + 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): 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) @@ -731,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): @@ -752,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): @@ -770,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 @@ -796,7 +948,8 @@ class InternalAgent(Player): self.board = Board(style = "agent") - + def argForm(self): + return "@internal:"+self.name def update(self, result): @@ -886,10 +1039,9 @@ class ExternalWrapper(ExternalAgent): 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 @@ -1084,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 @@ -1106,7 +1261,7 @@ def TimeoutFunction(function, args, timeout): w.terminate() s.join() raise Exception("TIMEOUT") - + time.sleep(0.1) @@ -1283,9 +1438,11 @@ 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 if network_timeout_delay > 0.0: @@ -1295,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") @@ -1309,7 +1466,7 @@ class Network(): if self.src in ready: self.src.send(s + "\n") else: - raise Exception("UNRESPONSIVE") + raise Exception("NET_UNRESPONSIVE") @@ -1331,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 @@ -1534,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): @@ -1548,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") @@ -1599,10 +1754,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") @@ -1651,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: @@ -2449,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 @@ -2491,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) @@ -2531,7 +2694,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) @@ -2555,6 +2722,7 @@ def main(argv): global sleep_timeout + retry_illegal = False server_addr = None max_moves = None @@ -2576,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 @@ -2652,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 @@ -2666,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! @@ -2693,6 +2870,7 @@ def main(argv): board = Board(style) board.max_moves = max_moves game = GameThread(board, players) + game.retry_illegal = retry_illegal @@ -2715,6 +2893,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: @@ -2834,4 +3013,4 @@ if __name__ == "__main__": # --- main.py --- # -# EOF - created from make on Sat Apr 20 12:19:31 WST 2013 +# EOF - created from make on Monday 24 June 23:55:46 WST 2013