From a238aa7acac990bae67644d1dc7f518ce3e2e8c6 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Wed, 30 Jan 2013 21:00:50 +0800 Subject: [PATCH] It works! Need to tidy things up. Differ between 'short' log and full log. Make HttpGetter work for either. "short" log has the entire board state and most recent selection/move. "full" log has the original board state and all moves up to the current point. I started the "short" log so I could make it easy to watch games played on the server, but I think it might be useful for testing now. But I need to work on it first. Since short log prints the board state rather than all moves, agents don't know what is going on when short log is read back. If I implement an API for that, then people can write their own starting game states. Also need to indicate whether pieces are revealed or not in their string, and interpret correctly in reading the short logs Or not... perhaps this is getting too complicated? NEVER --- qchess/qchess.py | 132 ++++++++++++++++++++++++++++++++------------- qchess/src/game.py | 55 +++++++++++++------ qchess/src/log.py | 75 ++++++++++++++++++-------- 3 files changed, 187 insertions(+), 75 deletions(-) diff --git a/qchess/qchess.py b/qchess/qchess.py index 5e3e5c5..d2ec1bb 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -1208,6 +1208,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 +1216,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") @@ -1244,6 +1245,7 @@ class HttpLog(LogFile): if self.phase == 0: 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: @@ -1260,37 +1262,66 @@ class HttpLog(LogFile): 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() def log(s): if log_file != None: @@ -1480,6 +1511,8 @@ class ReplayThread(GameThread): self.board.pieces = pieces self.board.king = king self.board.grid = grid + + # Update the player's boards def run(self): move_count = 0 @@ -1511,33 +1544,56 @@ class ReplayThread(GameThread): 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: + graphics.state["moves"] = self.board.possible_moves(target) + 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) 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] + + + + + - 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) + @@ -2352,4 +2408,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 Wed Jan 30 21:00:29 WST 2013 diff --git a/qchess/src/game.py b/qchess/src/game.py index 66b782f..de2439b 100644 --- a/qchess/src/game.py +++ b/qchess/src/game.py @@ -176,6 +176,8 @@ class ReplayThread(GameThread): self.board.pieces = pieces self.board.king = king self.board.grid = grid + + # Update the player's boards def run(self): move_count = 0 @@ -207,33 +209,56 @@ class ReplayThread(GameThread): 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: + graphics.state["moves"] = self.board.possible_moves(target) + 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) 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] + + + + + - 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) + diff --git a/qchess/src/log.py b/qchess/src/log.py index 7451b3a..12b43b8 100644 --- a/qchess/src/log.py +++ b/qchess/src/log.py @@ -7,6 +7,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() @@ -14,7 +15,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") @@ -43,6 +44,7 @@ class HttpLog(LogFile): if self.phase == 0: 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: @@ -59,37 +61,66 @@ class HttpLog(LogFile): 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() + #sys.stderr.write(" HttpGetter got \'" + str(line) + "\'\n") - return line + 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() def log(s): if log_file != None: -- 2.20.1