Actually commit stuff from ages ago
[progcomp2013.git] / qchess / qchess.py
index 5e3e5c5..48ada31 100755 (executable)
@@ -14,13 +14,13 @@ class Piece():
                self.types = types # List of possible types the piece can be (should just be two)
                self.current_type = "unknown" # Current type
                self.choice = -1 # Index of the current type in self.types (-1 = unknown type)
-               self.types_revealed = [True, False] # Whether the types are known (by default the first type is always known at game start)
                
-
-               # 
+               
                self.last_state = None
+               
                self.move_pattern = None
-
+               self.coverage = None
+               self.possible_moves = None
                
 
        def init_from_copy(self, c):
@@ -30,8 +30,7 @@ class Piece():
                self.types = c.types[:]
                self.current_type = c.current_type
                self.choice = c.choice
-               self.types_revealed = c.types_revealed[:]
-
+               
                self.last_state = None
                self.move_pattern = None
 
@@ -59,7 +58,7 @@ class Piece():
 
                # Draw the two possible types underneath the current_type image
                for i in range(len(self.types)):
-                       if always_reveal_states == True or self.types_revealed[i] == True:
+                       if always_reveal_states == True or self.types[i][0] != '?':
                                img = small_images[self.colour][self.types[i]]
                        else:
                                img = small_images[self.colour]["unknown"] # If the type hasn't been revealed, show a placeholder
@@ -77,17 +76,18 @@ class Piece():
        
        # Collapses the wave function!          
        def select(self):
-               if self.current_type == "unknown":
+               if self.current_type == "unknown" or not self.choice in [0,1]:
                        self.choice = random.randint(0,1)
+                       if self.types[self.choice][0] == '?':
+                               self.types[self.choice] = self.types[self.choice][1:]
                        self.current_type = self.types[self.choice]
-                       self.types_revealed[self.choice] = True
                return self.choice
 
        # Uncollapses (?) the wave function!
        def deselect(self):
                #print "Deselect called"
                if (self.x + self.y) % 2 != 0:
-                       if (self.types[0] != self.types[1]) or (self.types_revealed[0] == False or self.types_revealed[1] == False):
+                       if (self.types[0] != self.types[1]) or (self.types[0][0] == '?' or self.types[1][0] == '?'):
                                self.current_type = "unknown"
                                self.choice = -1
                        else:
@@ -110,6 +110,9 @@ class Board():
                self.grid = [[None] * w for _ in range(h)] # 2D List (you can get arrays in python, somehow, but they scare me)
                self.unrevealed_types = {"white" : piece_types.copy(), "black" : piece_types.copy()}
                self.king = {"white" : None, "black" : None} # We need to keep track of the king, because he is important
+               self.max_moves = None
+               self.moves = 0
+               self.move_stack = []
                for c in ["black", "white"]:
                        del self.unrevealed_types[c]["unknown"]
 
@@ -127,7 +130,6 @@ class Board():
                        c.append(Piece(s, 1, y, ["knight"]))
                        c.append(Piece(s, 2, y, ["bishop"]))
                        k = Piece(s, 3, y, ["king", "king"]) # There can only be one ruler!
-                       k.types_revealed[1] = True
                        k.current_type = "king"
                        self.king[s] = k
                        c.append(k)
@@ -165,11 +167,10 @@ class Board():
                                        types_left[choice] -= 1
                                        if types_left[choice] <= 0:
                                                del types_left[choice]
-                                       piece.types.append(choice)
+                                       piece.types.append('?' + choice)
                                elif style == "classical":
                                        piece.types.append(piece.types[0])
                                        piece.current_type = piece.types[0]
-                                       piece.types_revealed[1] = True
                                        piece.choice = 0
 
        def clone(self):
@@ -179,6 +180,40 @@ class Board():
 
                for i in range(len(mypieces)):
                        newpieces[i].init_from_copy(mypieces[i])
+       
+       # Reset the board from a string
+       def reset_board(self, s):
+               self.pieces = {"white" : [], "black" : []}
+               self.king = {"white" : None, "black" : None}
+               self.grid = [[None] * w for _ in range(h)]
+               for x in range(w):
+                       for y in range(h):
+                               self.grid[x][y] = None
+
+               for line in s.split("\n"):
+                       if line == "":
+                               continue
+                       if line[0] == "#":
+                               continue
+
+                       tokens = line.split(" ")
+                       [x, y] = map(int, tokens[len(tokens)-1].split(","))
+                       current_type = tokens[1]
+                       types = map(lambda e : e.strip(" '[],"), line.split('[')[1].split(']')[0].split(','))
+                       
+                       target = Piece(tokens[0], x, y, types)
+                       target.current_type = current_type
+                       
+                       try:
+                               target.choice = types.index(current_type)
+                       except:
+                               target.choice = -1
+
+                       self.pieces[tokens[0]].append(target)
+                       if target.current_type == "king":
+                               self.king[tokens[0]] = target
+
+                       self.grid[x][y] = target
                        
 
        def display_grid(self, window = None, grid_sz = [80,80]):
@@ -244,15 +279,23 @@ class Board():
                                del self.unrevealed_types[piece.colour][state]
 
                piece.types[type_index] = state
-               piece.types_revealed[type_index] = True
                piece.current_type = state
 
                if len(self.possible_moves(piece)) <= 0:
                        piece.deselect() # Piece can't move; deselect it
+                       
+               # Piece needs to recalculate moves
+               piece.possible_moves = None
                
        # Update the board when a piece has been moved
        def update_move(self, x, y, x2, y2):
+                               
                piece = self.grid[x][y]
+               #print "Moving " + str(x) + "," + str(y) + " to " + str(x2) + "," + str(y2) + "; possible_moves are " + str(self.possible_moves(piece))
+               
+               if not [x2,y2] in self.possible_moves(piece):
+                       raise Exception("ILLEGAL move " + str(x2)+","+str(y2))
+               
                self.grid[x][y] = None
                taken = self.grid[x2][y2]
                if taken != None:
@@ -275,7 +318,13 @@ class Board():
                        piece.current_type = "queen"
 
                piece.deselect() # Uncollapse (?) the wavefunction!
-               self.verify()   
+               self.moves += 1
+               
+               # All other pieces need to recalculate moves
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+               #self.verify()  
 
        # Update the board from a string
        # Guesses what to do based on the format of the string
@@ -332,7 +381,7 @@ class Board():
                        if prob > 0:
                                result.update({p : prob})
                
-               self.verify()
+               #self.verify()
                return result
 
 
@@ -357,7 +406,7 @@ class Board():
                for i in range(len(p.types)):
                        t = p.types[i]
                        prob = 0.5
-                       if t == "unknown" or p.types_revealed[i] == False:
+                       if t == "unknown" or p.types[i][0] == '?':
                                total_types = 0
                                for t2 in self.unrevealed_types[p.colour].keys():
                                        total_types += self.unrevealed_types[p.colour][t2]
@@ -373,7 +422,7 @@ class Board():
                                for point in self.possible_moves(p, reject_allied):
                                        result[point[0]][point[1]] += prob
                
-               self.verify()
+               #self.verify()
                p.current_type = "unknown"
                return result
 
@@ -385,7 +434,7 @@ class Board():
                        if t == state:
                                result += prob
                                continue        
-                       if t == "unknown" or p.types_revealed[i] == False:
+                       if t == "unknown" or p.types[i][0] == '?':
                                total_prob = 0
                                for t2 in self.unrevealed_types[p.colour].keys():
                                        total_prob += self.unrevealed_types[p.colour][t2]
@@ -399,10 +448,25 @@ class Board():
        # This is probably inefficient, but I looked at some sample chess games and they seem to actually do things this way
        # reject_allied indicates whether squares occupied by allied pieces will be removed
        # (set to false to check for defense)
-       def possible_moves(self, p, reject_allied = True):
-               result = []
+       def possible_moves(self, p, reject_allied = True, state=None):
                if p == None:
+                       raise Exception("SANITY: No piece")
+               
+               
+               
+               if state != None and state != p.current_type:
+                       old_type = p.current_type
+                       p.current_type = state
+                       result = self.possible_moves(p, reject_allied, state=None)
+                       p.current_type = old_type
                        return result
+               
+               if p.possible_moves != None:
+                       return p.possible_moves
+               
+               
+               result = []
+               
 
                
                if p.current_type == "unknown":
@@ -474,7 +538,9 @@ class Board():
                        if g != None and (g.colour == p.colour and reject_allied == True):
                                result.remove(point) # Remove allied pieces
                
-               self.verify()
+               #self.verify()
+               
+               p.possible_moves = result
                return result
 
 
@@ -498,16 +564,57 @@ class Board():
                                        
                return p
 
+       # Returns "white", "black" or "DRAW" if the game should end
+       def end_condition(self):
+               if self.king["white"] == None:
+                       if self.king["black"] == None:
+                               return "DRAW" # This shouldn't happen
+                       return "black"
+               elif self.king["black"] == None:
+                       return "white"
+               elif len(self.pieces["white"]) == 1 and len(self.pieces["black"]) == 1:
+                       return "DRAW"
+               elif self.max_moves != None and self.moves > self.max_moves:
+                       return "DRAW"
+               return None
 
 
        # I typed the full statement about 30 times before writing this function...
        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]
+               self.move_stack.append([piece, target, piece.x, piece.y, x, y])
+               [piece.x, piece.y] = [x, y]
+               self.grid[x][y] = piece
+               self.grid[piece.x][piece.y] = None
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                       p.possible_moves = None
+               
+       # Restore move
+       def pop_move(self):
+               #print str(self.move_stack)
+               [piece, target, x1, y1, x2, y2] = self.move_stack[len(self.move_stack)-1]
+               self.move_stack = self.move_stack[:-1]
+               piece.x = x1
+               piece.y = y1
+               self.grid[x1][y1] = piece
+               if target != None:
+                       target.x = x2
+                       target.y = y2
+               self.grid[x2][y2] = target
+               
+               for p in self.pieces["white"] + self.pieces["black"]:
+                               p.possible_moves = None
+               
 # --- board.py --- #
 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
@@ -524,6 +631,9 @@ class Player():
        def update(self, result):
                pass
 
+       def reset_board(self, s):
+               pass
+
 # Player that runs from another process
 class ExternalAgent(Player):
 
@@ -556,7 +666,7 @@ class ExternalAgent(Player):
                if self.p.stdout in ready:
                        #sys.stderr.write("Reading from " + str(self.p) + " 's stdout...\n")
                        try:
-                               result = 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:
@@ -570,7 +680,8 @@ class ExternalAgent(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
@@ -586,11 +697,19 @@ class ExternalAgent(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)
@@ -673,6 +792,9 @@ class InternalAgent(Player):
                self.board.update(result)
                self.board.verify()
 
+       def reset_board(self, s):
+               self.board.reset_board(s)
+
        def quit(self, final_result):
                pass
 
@@ -724,6 +846,14 @@ def run_agent(agent):
                        #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
@@ -743,7 +873,7 @@ class ExternalWrapper(ExternalAgent):
 # A sample agent
 
 
-class AgentBishop(InternalAgent): # Inherits from InternalAgent (in qchess)
+class AgentBishop(AgentRandom): # Inherits from AgentRandom (in qchess)
        def __init__(self, name, colour):
                InternalAgent.__init__(self, name, colour)
                self.value = {"pawn" : 1, "bishop" : 3, "knight" : 3, "rook" : 5, "queen" : 9, "king" : 100, "unknown" : 4}
@@ -789,10 +919,9 @@ class AgentBishop(InternalAgent): # Inherits from InternalAgent (in qchess)
                                
                                
                                # Get total probability that the move is protected
-                               [xx,yy] = [piece.x, piece.y]
-                               [piece.x, piece.y] = [x, y]
-                               self.board.grid[x][y] = piece
-                               self.board.grid[xx][yy] = None
+                               self.board.push_move(piece, x, y)
+                               
+
                                
                                defenders = self.board.coverage(x, y, piece.colour, reject_allied = False)
                                d_prob = 0.0
@@ -815,9 +944,8 @@ class AgentBishop(InternalAgent): # Inherits from InternalAgent (in qchess)
                                if (a_prob > 1.0):
                                        a_prob = 1.0
 
-                               self.board.grid[x][y] = target
-                               self.board.grid[xx][yy] = piece
-                               [piece.x, piece.y] = [xx, yy]
+                               self.board.pop_move()
+                               
 
                                
                                # Score of the move
@@ -905,6 +1033,7 @@ class AgentBishop(InternalAgent): # Inherits from InternalAgent (in qchess)
        def select(self):
                #sys.stderr.write("Getting choice...")
                self.choice = self.select_best(self.colour)[0]
+               
                #sys.stderr.write(" Done " + str(self.choice)+"\n")
                return [self.choice.x, self.choice.y]
        
@@ -916,7 +1045,7 @@ class AgentBishop(InternalAgent): # Inherits from InternalAgent (in qchess)
                if len(moves) > 0:
                        return moves[0][0]
                else:
-                       return InternalAgent.get_move(self)
+                       return AgentRandom.get_move(self)
 
 # --- agent_bishop.py --- #
 import multiprocessing
@@ -1199,7 +1328,7 @@ class StoppableThread(threading.Thread):
        def stopped(self):
                return self._stop.isSet()
 # --- thread_util.py --- #
-log_file = None
+log_files = []
 import datetime
 import urllib2
 
@@ -1208,6 +1337,7 @@ class LogFile():
                
                self.log = log
                self.logged = []
+               self.log.write("# Log starts " + str(datetime.datetime.now()) + "\n")
 
        def write(self, s):
                now = datetime.datetime.now()
@@ -1215,7 +1345,7 @@ class LogFile():
                self.logged.append((now, s))
 
        def setup(self, board, players):
-               self.log.write("# Log starts " + str(datetime.datetime.now()) + "\n")
+               
                for p in players:
                        self.log.write("# " + p.colour + " : " + p.name + "\n")
                
@@ -1229,11 +1359,16 @@ class LogFile():
 
        def close(self):
                self.log.write("# EOF\n")
-               self.log.close()
+               if self.log != sys.stdout:
+                       self.log.close()
 
-class HttpLog(LogFile):
+class ShortLog(LogFile):
        def __init__(self, file_name):
-               LogFile.__init__(self, open(file_name, "w", 0))
+               if file_name == "":
+                       self.log = sys.stdout
+               else:
+                       self.log = open(file_name, "w", 0)
+               LogFile.__init__(self, self.log)
                self.file_name = file_name
                self.phase = 0
 
@@ -1242,8 +1377,10 @@ class HttpLog(LogFile):
                self.logged.append((now, s))
                
                if self.phase == 0:
-                       self.log.close()
-                       self.log = open(self.file_name, "w", 0)
+                       if self.log != sys.stdout:
+                               self.log.close()
+                               self.log = open(self.file_name, "w", 0)
+                       self.log.write("# Short log updated " + str(datetime.datetime.now()) + "\n")    
                        LogFile.setup(self, game.board, game.players)
 
                elif self.phase == 1:
@@ -1253,53 +1390,123 @@ class HttpLog(LogFile):
                self.phase = (self.phase + 1) % 2               
                
        def close(self):
+               if self.phase == 1:
+                       ending = self.logged[len(self.logged)-1]
+                       self.log.write(str(ending[0]) + " : " + ending[1] + "\n")
                self.log.write("# EOF\n")
-               self.log.close()
+               if self.log != sys.stdout:
+                       self.log.close()
                
 
 class HeadRequest(urllib2.Request):
        def get_method(self):
                return "HEAD"
-               
-class HttpReplay():
+
+class HttpGetter(StoppableThread):
        def __init__(self, address):
-               self.read_setup = False
-               self.log = urllib2.urlopen(address)
+               StoppableThread.__init__(self)
                self.address = address
+               self.log = urllib2.urlopen(address)
+               self.lines = []
+               self.lock = threading.RLock() #lock for access of self.state
+               self.cond = threading.Condition() # conditional
 
-       def readline(self):
-               
-               line = self.log.readline()
-               sys.stderr.write(sys.argv[0] + " : " + str(self.__class__.__name__) + " read \""+str(line.strip("\r\n")) + "\" from address " + str(self.address) + "\n")
-               if line == "":
-                       sys.stderr.write(sys.argv[0] + " : " + str(self.__class__.__name__) + " retrieving from address " + str(self.address) + "\n")
-                       date_mod = datetime.datetime.strptime(self.log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
-                       self.log.close()
-
-                       next_log = urllib2.urlopen(HeadRequest(self.address))
-                       date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
-                       while date_new <= date_mod:
+       def run(self):
+               while not self.stopped():
+                       line = self.log.readline()
+                       if line == "":
+                               date_mod = datetime.datetime.strptime(self.log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               self.log.close()
+       
                                next_log = urllib2.urlopen(HeadRequest(self.address))
                                date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               while date_new <= date_mod and not self.stopped():
+                                       next_log = urllib2.urlopen(HeadRequest(self.address))
+                                       date_new = datetime.datetime.strptime(next_log.headers['last-modified'], "%a, %d %b %Y %H:%M:%S GMT")
+                               if self.stopped():
+                                       break
 
-                       self.log = urllib2.urlopen(self.address)
-                       game.setup()
-                       line = self.log.readline()
+                               self.log = urllib2.urlopen(self.address)
+                               line = self.log.readline()
 
+                       self.cond.acquire()
+                       self.lines.append(line)
+                       self.cond.notifyAll()
+                       self.cond.release()
 
-               return line
+                       #sys.stderr.write(" HttpGetter got \'" + str(line) + "\'\n")
+
+               self.log.close()
+                               
+                               
+       
+               
+               
+class HttpReplay():
+       def __init__(self, address):
+               self.getter = HttpGetter(address)
+               self.getter.start()
+               
+       def readline(self):
+               self.getter.cond.acquire()
+               while len(self.getter.lines) == 0:
+                       self.getter.cond.wait()
+                       
+               result = self.getter.lines[0]
+               self.getter.lines = self.getter.lines[1:]
+               self.getter.cond.release()
+
+               return result
+                       
                        
        def close(self):
-               self.log.close()
+               self.getter.stop()
+
+class FileReplay():
+       def __init__(self, filename):
+               self.f = open(filename, "r", 0)
+               self.filename = filename
+               self.mod = os.path.getmtime(filename)
+               self.count = 0
+       
+       def readline(self):
+               line = self.f.readline()
+               
+               while line == "":
+                       mod2 = os.path.getmtime(self.filename)
+                       if mod2 > self.mod:
+                               #sys.stderr.write("File changed!\n")
+                               self.mod = mod2
+                               self.f.close()
+                               self.f = open(self.filename, "r", 0)
+                               
+                               new_line = self.f.readline()
+                               
+                               if " ".join(new_line.split(" ")[0:3]) != "# Short log":
+                                       for i in range(self.count):
+                                               new_line = self.f.readline()
+                                               #sys.stderr.write("Read back " + str(i) + ": " + str(new_line) + "\n")
+                                       new_line = self.f.readline()
+                               else:
+                                       self.count = 0
+                               
+                               line = new_line
+
+               self.count += 1
+               return line
+
+       def close(self):
+               self.f.close()
+               
                                                
 def log(s):
-       if log_file != None:
-               log_file.write(s)
+       for l in log_files:
+               l.write(s)
                
 
 def log_init(board, players):
-       if log_file != None:
-               log_file.setup(board, players)
+       for l in log_files:
+               l.setup(board, players)
 
 # --- log.py --- #
 
@@ -1406,20 +1613,15 @@ class GameThread(StoppableThread):
                        #               with self.lock:
                        #                       self.final_result = self.state["turn"].colour + " " + e.message
 
-                               if self.board.king["black"] == None:
-                                       if self.board.king["white"] == None:
-                                               with self.lock:
-                                                       self.final_result = self.state["turn"].colour + " DRAW"
-                                       else:
-                                               with self.lock:
-                                                       self.final_result = "white"
-                                       self.stop()
-                               elif self.board.king["white"] == None:
+                               end = self.board.end_condition()
+                               if end != None:         
                                        with self.lock:
-                                               self.final_result = "black"
+                                               if end == "DRAW":
+                                                       self.final_result = self.state["turn"].colour + " " + end
+                                               else:
+                                                       self.final_result = end
                                        self.stop()
-                                               
-
+                               
                                if self.stopped():
                                        break
 
@@ -1435,68 +1637,73 @@ class GameThread(StoppableThread):
        
 # A thread that replays a log file
 class ReplayThread(GameThread):
-       def __init__(self, players, src, end=False,max_lines=None):
+       def __init__(self, players, src, end=False,max_moves=None):
                self.board = Board(style="empty")
+               self.board.max_moves = max_moves
                GameThread.__init__(self, self.board, players)
                self.src = src
-               self.max_lines = max_lines
-               self.line_number = 0
                self.end = end
 
                self.reset_board(self.src.readline())
 
        def reset_board(self, line):
-               pieces = {"white" : [], "black" : []}
-               king = {"white" : None, "black" : None}
-               grid = [[None] * w for _ in range(h)]
-               for x in range(w):
-                       for y in range(h):
-                               self.board.grid[x][y] = None
-               while line != "# Start game":
-                       if line[0] == "#":
+               agent_str = ""
+               self_str = ""
+               while line != "# Start game" and line != "# EOF":
+                       
+                       while line == "":
                                line = self.src.readline().strip(" \r\n")
                                continue
 
-                       tokens = line.split(" ")
-                       [x, y] = map(int, tokens[len(tokens)-1].split(","))
-                       current_type = tokens[1]
-                       types = map(lambda e : e.strip("'[], "), (tokens[2]+tokens[3]).split(","))
-                       
-                       target = Piece(tokens[0], x, y, types)
-                       target.current_type = current_type
+                       if line[0] == '#':
+                               line = self.src.readline().strip(" \r\n")
+                               continue
+
+                       self_str += line + "\n"
+
+                       if self.players[0].name == "dummy" and self.players[1].name == "dummy":
+                               line = self.src.readline().strip(" \r\n")
+                               continue
                        
-                       try:
-                               target.choice = types.index(current_type)
-                       except:
-                               target.choice = -1
+                       tokens = line.split(" ")
+                       types = map(lambda e : e.strip("[] ,'"), tokens[2:4])
+                       for i in range(len(types)):
+                               if types[i][0] == "?":
+                                       types[i] = "unknown"
 
-                       pieces[tokens[0]].append(target)
-                       if target.current_type == "king":
-                               king[tokens[0]] = target
-                       grid[x][y] = target
-               
+                       agent_str += tokens[0] + " " + tokens[1] + " " + str(types) + " ".join(tokens[4:]) + "\n"
                        line = self.src.readline().strip(" \r\n")
 
-               self.board.pieces = pieces
-               self.board.king = king
-               self.board.grid = grid
+               for p in self.players:
+                       p.reset_board(agent_str)
+               
+               
+               self.board.reset_board(self_str)
+
        
        def run(self):
                move_count = 0
+               last_line = ""
                line = self.src.readline().strip(" \r\n")
                while line != "# EOF":
+
+
                        if self.stopped():
                                break
-
+                       
+                       if len(line) <= 0:
+                               continue
                                        
 
                        if line[0] == '#':
+                               last_line = line
                                line = self.src.readline().strip(" \r\n")
                                continue
 
                        tokens = line.split(" ")
                        if tokens[0] == "white" or tokens[0] == "black":
                                self.reset_board(line)
+                               last_line = line
                                line = self.src.readline().strip(" \r\n")
                                continue
 
@@ -1508,36 +1715,68 @@ class ReplayThread(GameThread):
                        try:
                                [x,y] = map(int, tokens[0:2])
                        except:
+                               last_line = line
                                self.stop()
                                break
 
+                       log(move)
+
                        target = self.board.grid[x][y]
+                       with self.lock:
+                               if target.colour == "white":
+                                       self.state["turn"] = self.players[0]
+                               else:
+                                       self.state["turn"] = self.players[1]
                        
                        move_piece = (tokens[2] == "->")
-
                        if move_piece:
                                [x2,y2] = map(int, tokens[len(tokens)-2:])
 
-                       log(move)
-                       self.board.update(move)
+                       if isinstance(graphics, GraphicsThread):
+                               with graphics.lock:
+                                       graphics.state["select"] = target
+                                       
+                       if not move_piece:
+                               self.board.update_select(x, y, int(tokens[2]), tokens[len(tokens)-1])
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               if target.current_type != "unknown":
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                               else:
+                                                       graphics.state["moves"] = None
+                                       time.sleep(turn_delay)
+                       else:
+                               self.board.update_move(x, y, x2, y2)
+                               if isinstance(graphics, GraphicsThread):
+                                       with graphics.lock:
+                                               graphics.state["moves"] = [[x2,y2]]
+                                       time.sleep(turn_delay)
+                                       with graphics.lock:
+                                               graphics.state["select"] = None
+                                               graphics.state["moves"] = None
+                                               graphics.state["dest"] = None
+                       
+
+                       
+                       
+                       
                        for p in self.players:
                                p.update(move)
 
+                       last_line = line
                        line = self.src.readline().strip(" \r\n")
                        
-                       if isinstance(graphics, GraphicsThread):
-                               with self.lock:
-                                       if target.colour == "white":
-                                               self.state["turn"] = self.players[0]
-                                       else:
-                                               self.state["turn"] = self.players[1]
+                       
+                       end = self.board.end_condition()
+                       if end != None:
+                               self.final_result = end
+                               self.stop()
+                               break
+                                       
+                                               
+                                               
 
-                               with graphics.lock:
-                                       graphics.state["select"] = target
-                                       if move_piece:
-                                               graphics.state["moves"] = [[x2, y2]]
-                                       elif target.current_type != "unknown":
-                                               graphics.state["moves"] = self.board.possible_moves(target)
+                       
                                        
 
 
@@ -1546,18 +1785,28 @@ class ReplayThread(GameThread):
                                
                        
 
-               if self.max_lines != None and self.max_lines > count:
-                       sys.stderr.write(sys.argv[0] + " : Replaying from file; stopping at last line (" + str(count) + ")\n")
-                       sys.stderr.write(sys.argv[0] + " : (You requested line " + str(self.max_lines) + ")\n")
+               
 
                if self.end and isinstance(graphics, GraphicsThread):
                        #graphics.stop()
                        pass # Let the user stop the display
-               elif not self.end:
+               elif not self.end and self.board.end_condition() == None:
                        global game
+                       # Work out the last move
+                                       
+                       t = last_line.split(" ")
+                       if t[len(t)-2] == "black":
+                               self.players.reverse()
+                       elif t[len(t)-2] == "white":
+                               pass
+                       elif self.state["turn"] != None and self.state["turn"].colour == "white":
+                               self.players.reverse()
+
+
                        game = GameThread(self.board, self.players)
                        game.run()
-               
+               else:
+                       pass
 
                
 
@@ -1683,7 +1932,7 @@ class GraphicsThread(StoppableThread):
                        pygame.display.flip()
 
                        for event in pygame.event.get():
-                               if event.type == pygame.QUIT:
+                               if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q):
                                        if isinstance(game, GameThread):
                                                with game.lock:
                                                        game.final_result = ""
@@ -2128,12 +2377,12 @@ def main(argv):
        
        global turn_delay
        global agent_timeout
-       global log_file
+       global log_files
        global src_file
        global graphics_enabled
        global always_reveal_states
 
-       max_lines = None
+       max_moves = None
        src_file = None
        
        style = "quantum"
@@ -2173,31 +2422,33 @@ def main(argv):
                elif arg[1] == '-' and arg[2:] == "reveal":
                        always_reveal_states = True
                elif (arg[1] == '-' and arg[2:] == "graphics"):
-                       graphics_enabled = not graphics_enabled
+                       graphics_enabled = True
+               elif (arg[1] == '-' and arg[2:] == "no-graphics"):
+                       graphics_enabled = False
                elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"):
                        # Load game from file
                        if len(arg[2:].split("=")) == 1:
                                src_file = sys.stdin
                        else:
                                f = arg[2:].split("=")[1]
-                               if f[0] == '@':
-                                       src_file = HttpReplay("http://" + f.split(":")[0][1:])
+                               if f[0:7] == "http://":
+                                       src_file = HttpReplay(f)
                                else:
-                                       src_file = open(f.split(":")[0], "r", 0)
+                                       src_file = FileReplay(f.split(":")[0])
 
-                               if len(f.split(":")) == 2:
-                                       max_lines = int(f.split(":")[1])
+                                       if len(f.split(":")) == 2:
+                                               max_moves = int(f.split(":")[1])
 
                elif (arg[1] == '-' and arg[2:].split("=")[0] == "log"):
                        # Log file
                        if len(arg[2:].split("=")) == 1:
-                               log_file = LogFile(sys.stdout)
+                               log_files.append(LogFile(sys.stdout))
                        else:
                                f = arg[2:].split("=")[1]
                                if f[0] == '@':
-                                       log_file = HttpLog(f[1:])
+                                       log_files.append(ShortLog(f[1:]))
                                else:
-                                       log_file = LogFile(open(f, "w", 0))
+                                       log_files.append(LogFile(open(f, "w", 0)))
                elif (arg[1] == '-' and arg[2:].split("=")[0] == "delay"):
                        # Delay
                        if len(arg[2:].split("=")) == 1:
@@ -2237,13 +2488,15 @@ def main(argv):
                        if graphics_enabled:
                                sys.stderr.write(sys.argv[0] + " : (You won't get a GUI, because --file was used, and the author is lazy)\n")
                        return 44
-               game = ReplayThread(players, src_file, end=end, max_lines=max_lines)
+               game = ReplayThread(players, src_file, end=end, max_moves=max_moves)
        else:
                board = Board(style)
+               board.max_moves = max_moves
                game = GameThread(board, players) 
 
 
 
+
        # Initialise GUI
        if graphics_enabled == True:
                try:
@@ -2326,12 +2579,14 @@ def main(argv):
                error = game.error
        
 
-       if log_file != None and log_file != sys.stdout:
-               log_file.close()
+       for l in log_files:
+               l.close()
 
        if src_file != None and src_file != sys.stdin:
                src_file.close()
 
+       sys.stdout.write(game.final_result + "\n")
+
        return error
 
 # This is how python does a main() function...
@@ -2352,4 +2607,4 @@ if __name__ == "__main__":
                sys.exit(102)
 
 # --- main.py --- #
-# EOF - created from make on Wed Jan 30 19:58:45 WST 2013
+# EOF - created from make on Thu Mar 14 22:36:37 WST 2013

UCC git Repository :: git.ucc.asn.au