Messing with log files
authorSam Moore <matches@ucc.asn.au>
Thu, 31 Jan 2013 05:37:27 +0000 (13:37 +0800)
committerSam Moore <matches@ucc.asn.au>
Thu, 31 Jan 2013 05:37:27 +0000 (13:37 +0800)
- Fixed storing of whether pieces were revealed or not in log files
  - Just prepend '?' to the hidden types, removed the Piece.types_revealed list

- Implemented Agent resetting of board state from strings
  - ReplayPlayer will call the Agent.reset_board() function
  - run_agent() looks for lines between "BOARD" and "END BOARD"
  - This API will not be compulsory for entered agents
    - All games will start with the initial board state, it is not required

- Fixed other stuff with log files
  - Needed to work out whose turn it is when the game continues from a log
  - HttpLog -> ShortLog (since it just writes to a file)
  - To get a log from http, use --file=http://address
    - This works for either ShortLog or LogFile written logs
- But if the game hasn't ended there is a bug with the LogFile logs
  - Can now have multiple logs at the same time

- Hopefully nothing is borked

qchess/qchess.py
qchess/src/agent_bishop.py
qchess/src/board.py
qchess/src/game.py
qchess/src/log.py
qchess/src/main.py
qchess/src/piece.py
qchess/src/player.py

index d2ec1bb..ced16ce 100755 (executable)
@@ -14,12 +14,12 @@ 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
 
                
 
@@ -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
@@ -79,15 +78,16 @@ class Piece():
        def select(self):
                if self.current_type == "unknown":
                        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,8 @@ 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
                for c in ["black", "white"]:
                        del self.unrevealed_types[c]["unknown"]
 
@@ -127,7 +129,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 +166,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 +179,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,7 +278,6 @@ 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:
@@ -275,7 +308,8 @@ class Board():
                        piece.current_type = "queen"
 
                piece.deselect() # Uncollapse (?) the wavefunction!
-               self.verify()   
+               self.moves += 1
+               #self.verify()  
 
        # Update the board from a string
        # Guesses what to do based on the format of the string
@@ -357,7 +391,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]
@@ -385,7 +419,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]
@@ -498,6 +532,19 @@ 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...
@@ -524,6 +571,9 @@ class Player():
        def update(self, result):
                pass
 
+       def reset_board(self, s):
+               pass
+
 # Player that runs from another process
 class ExternalAgent(Player):
 
@@ -591,6 +641,12 @@ class ExternalAgent(Player):
                        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 +729,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 +783,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 +810,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}
@@ -905,6 +972,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 +984,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 +1267,7 @@ class StoppableThread(threading.Thread):
        def stopped(self):
                return self._stop.isSet()
 # --- thread_util.py --- #
-log_file = None
+log_files = []
 import datetime
 import urllib2
 
@@ -1230,11 +1298,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
 
@@ -1243,8 +1316,9 @@ 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)
 
@@ -1255,8 +1329,12 @@ 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):
@@ -1324,13 +1402,13 @@ class HttpReplay():
                self.getter.stop()
                                                
 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 --- #
 
@@ -1437,20 +1515,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
 
@@ -1466,70 +1539,71 @@ 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)
 
-               # Update the player's boards
        
        def run(self):
                move_count = 0
+               last_line = ""
                line = self.src.readline().strip(" \r\n")
                while line != "# EOF":
+
+
                        if self.stopped():
                                break
-
+                       
                                        
 
                        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
 
@@ -1541,6 +1615,7 @@ class ReplayThread(GameThread):
                        try:
                                [x,y] = map(int, tokens[0:2])
                        except:
+                               last_line = line
                                self.stop()
                                break
 
@@ -1585,10 +1660,15 @@ class ReplayThread(GameThread):
                        for p in self.players:
                                p.update(move)
 
+                       last_line = line
                        line = self.src.readline().strip(" \r\n")
                        
                        
-                                       
+                       end = self.board.end_condition()
+                       if end != None:
+                               self.final_result = end
+                               self.stop()
+                               break
                                        
                                                
                                                
@@ -1602,18 +1682,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
 
                
 
@@ -2184,12 +2274,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"
@@ -2236,24 +2326,24 @@ def main(argv):
                                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)
 
-                               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:
@@ -2293,13 +2383,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:
@@ -2382,8 +2474,8 @@ 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()
@@ -2408,4 +2500,4 @@ if __name__ == "__main__":
                sys.exit(102)
 
 # --- main.py --- #
-# EOF - created from make on Wed Jan 30 21:00:29 WST 2013
+# EOF - created from make on Thu Jan 31 13:37:15 WST 2013
index 13be5bd..1464019 100644 (file)
@@ -1,7 +1,7 @@
 # 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}
@@ -163,6 +163,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]
        
@@ -174,5 +175,5 @@ 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)
 
index 5dbf1dd..a9825d0 100644 (file)
@@ -13,6 +13,8 @@ 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
                for c in ["black", "white"]:
                        del self.unrevealed_types[c]["unknown"]
 
@@ -30,7 +32,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)
@@ -68,11 +69,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):
@@ -82,6 +82,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]):
@@ -147,7 +181,6 @@ 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:
@@ -178,7 +211,8 @@ class Board():
                        piece.current_type = "queen"
 
                piece.deselect() # Uncollapse (?) the wavefunction!
-               self.verify()   
+               self.moves += 1
+               #self.verify()  
 
        # Update the board from a string
        # Guesses what to do based on the format of the string
@@ -260,7 +294,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]
@@ -288,7 +322,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]
@@ -401,6 +435,19 @@ 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...
index de2439b..16f26d7 100644 (file)
@@ -102,20 +102,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
 
@@ -131,70 +126,71 @@ 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)
 
-               # Update the player's boards
        
        def run(self):
                move_count = 0
+               last_line = ""
                line = self.src.readline().strip(" \r\n")
                while line != "# EOF":
+
+
                        if self.stopped():
                                break
-
+                       
                                        
 
                        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
 
@@ -206,6 +202,7 @@ class ReplayThread(GameThread):
                        try:
                                [x,y] = map(int, tokens[0:2])
                        except:
+                               last_line = line
                                self.stop()
                                break
 
@@ -250,10 +247,15 @@ class ReplayThread(GameThread):
                        for p in self.players:
                                p.update(move)
 
+                       last_line = line
                        line = self.src.readline().strip(" \r\n")
                        
                        
-                                       
+                       end = self.board.end_condition()
+                       if end != None:
+                               self.final_result = end
+                               self.stop()
+                               break
                                        
                                                
                                                
@@ -267,18 +269,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
 
                
 
index 12b43b8..1ef8145 100644 (file)
@@ -1,4 +1,4 @@
-log_file = None
+log_files = []
 import datetime
 import urllib2
 
@@ -29,11 +29,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
 
@@ -42,8 +47,9 @@ 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)
 
@@ -54,8 +60,12 @@ 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):
@@ -123,11 +133,11 @@ class HttpReplay():
                self.getter.stop()
                                                
 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)
 
index 61e030b..cbc07f7 100644 (file)
@@ -64,12 +64,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"
@@ -116,24 +116,24 @@ def main(argv):
                                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)
 
-                               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:
@@ -173,13 +173,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:
@@ -262,8 +264,8 @@ 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()
index 400a79a..81fbb56 100644 (file)
@@ -13,12 +13,12 @@ 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
 
                
 
@@ -29,8 +29,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
 
@@ -58,7 +57,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
@@ -78,15 +77,16 @@ class Piece():
        def select(self):
                if self.current_type == "unknown":
                        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:
index 0a4ddd6..0cc56c2 100644 (file)
@@ -18,6 +18,9 @@ class Player():
        def update(self, result):
                pass
 
+       def reset_board(self, s):
+               pass
+
 # Player that runs from another process
 class ExternalAgent(Player):
 
@@ -85,6 +88,12 @@ class ExternalAgent(Player):
                        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)
@@ -167,6 +176,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
 
@@ -218,6 +230,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

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