From bfa63f1a2dc9c66399f8159857d4cc54f038eaa2 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Thu, 24 Jan 2013 03:07:26 +0800 Subject: [PATCH] Mostly networking It is pretty much a hack Fixed dodgy symlinks from agents directory, thanks [SLX] Need to fix argument parsing for qchess program, but can't be bothered right now. --- agents/data | 2 +- agents/qchess.py | 2 +- qchess/board.py | 2 +- qchess/game.py | 8 +- qchess/main.py | 49 +++++++------ qchess/network.py | 118 ++++++++++++++++++++++++++++++ qchess/qchess.py | 181 +++++++++++++++++++++++++++++++++++++++------- qchess/update.sh | 8 +- 8 files changed, 317 insertions(+), 53 deletions(-) create mode 100644 qchess/network.py diff --git a/agents/data b/agents/data index eed2d0b..09607df 120000 --- a/agents/data +++ b/agents/data @@ -1 +1 @@ -../data/ \ No newline at end of file +../qchess/data/ \ No newline at end of file diff --git a/agents/qchess.py b/agents/qchess.py index daafe05..385f472 120000 --- a/agents/qchess.py +++ b/agents/qchess.py @@ -1 +1 @@ -../qchess.py \ No newline at end of file +../qchess/qchess.py \ No newline at end of file diff --git a/qchess/board.py b/qchess/board.py index 4858168..d028442 100644 --- a/qchess/board.py +++ b/qchess/board.py @@ -124,7 +124,7 @@ class Board(): raise Exception("EMPTY") if colour != None and piece.colour != colour: - raise Exception("COLOUR") + raise Exception("COLOUR " + str(piece.colour) + " not " + str(colour)) # I'm not quite sure why I made this return a string, but screw logical design return str(x) + " " + str(y) + " " + str(piece.select()) + " " + str(piece.current_type) diff --git a/qchess/game.py b/qchess/game.py index 1b568a0..393672d 100644 --- a/qchess/game.py +++ b/qchess/game.py @@ -18,13 +18,19 @@ class GameThread(StoppableThread): for p in self.players: with self.lock: - self.state["turn"] = p # "turn" contains the player who's turn it is + if isinstance(p, NetworkSender): + self.state["turn"] = p.base_player # "turn" contains the player who's turn it is + else: + self.state["turn"] = p #try: if True: [x,y] = p.select() # Player selects a square if self.stopped(): break + + + result = self.board.select(x, y, colour = p.colour) for p2 in self.players: p2.update(result) # Inform players of what happened diff --git a/qchess/main.py b/qchess/main.py index a0a40db..3f5d52e 100644 --- a/qchess/main.py +++ b/qchess/main.py @@ -30,31 +30,36 @@ def main(argv): global graphics # Magical argument parsing goes here - if len(argv) == 1: - players = [HumanPlayer("saruman", "white"), AgentRandom("sabbath", "black")] - elif len(argv) == 2: - players = [AgentPlayer(argv[1], "white"), HumanPlayer("shadow", "black"), ] - elif len(argv) == 3: - players = [AgentPlayer(argv[1], "white"), AgentPlayer(argv[2], "black")] +# if len(argv) == 1: +# players = [HumanPlayer("saruman", "white"), AgentRandom("sabbath", "black")] +# elif len(argv) == 2: +# players = [AgentPlayer(argv[1], "white"), HumanPlayer("shadow", "black"), ] +# elif len(argv) == 3: +# players = [AgentPlayer(argv[1], "white"), AgentPlayer(argv[2], "black")] + - # Construct the board! board = Board(style = "quantum") + # Construct the board! + if len(argv) == 1: + players = [NetworkSender(HumanPlayer("saruman", "white"), board), NetworkReceiver("black", board, 'localhost')] + + else: + players = [NetworkReceiver("white", board, 'localhost'), NetworkSender(HumanPlayer("sabbath", "black"), board)] + + + + + graphics = GraphicsThread(board, grid_sz = [64,64]) # Construct a GraphicsThread! I KNOW WHAT I'M DOING! BEAR WITH ME! + + + + game = GameThread(board, players) # Construct a GameThread! Make it global! Damn the consequences! - #try: - if True: - graphics = GraphicsThread(board, grid_sz = [64,64]) # Construct a GraphicsThread! I KNOW WHAT I'M DOING! BEAR WITH ME! - game.start() # This runs in a new thread - #except NameError: - # print "Run game in main thread" - # game.run() # Run game in the main thread (no need for joining) - # return game.error - #except Exception, e: - # raise e - #else: - # print "Normal" - graphics.run() - game.join() - return game.error + graphics.error + game.start() # This runs in a new thread + + graphics.run() + game.join() + return game.error + graphics.error # This is how python does a main() function... diff --git a/qchess/network.py b/qchess/network.py new file mode 100644 index 0000000..74a8b72 --- /dev/null +++ b/qchess/network.py @@ -0,0 +1,118 @@ +import socket + +class Network(): + def __init__(self, colour, address = None): + self.socket = socket.socket() + + if colour == "white": + self.port = 4563 + else: + self.port = 4564 + + self.src = None + + if address == None: + self.host = 'localhost' #socket.gethostname() + self.socket.bind((self.host, self.port)) + self.socket.listen(5) + + self.src, self.address = self.socket.accept() + else: + self.host = address + self.socket.connect(('localhost', self.port)) + self.src = self.socket + + def getline(self): + s = self.src.recv(1) + while s[len(s)-1] != '\n': + s += self.src.recv(1) + return s + + + + +class NetworkSender(Player,Network): + def __init__(self, base_player, board, address = None): + self.base_player = base_player + Player.__init__(self, base_player.name, base_player.colour) + Network.__init__(self, base_player.colour, address) + + self.board = board + + def select(self): + [x,y] = self.base_player.select() + choice = self.board.grid[x][y] + s = str(x) + " " + str(y) + print str(self) + ".select sends " + s + self.src.send(s + "\n") + return [x,y] + + def get_move(self): + [x,y] = self.base_player.get_move() + s = str(x) + " " + str(y) + print str(self) + ".get_move sends " + s + self.src.send(s + "\n") + return [x,y] + + def update(self, s): + self.base_player.update(s) + s = s.split(" ") + [x,y] = map(int, s[0:2]) + selected = self.board.grid[x][y] + if selected != None and selected.colour == self.colour and len(s) > 2 and not "->" in s: + s = " ".join(s[0:3]) + for i in range(2): + if selected.types_revealed[i] == True: + s += " " + str(selected.types[i]) + else: + s += " unknown" + print str(self) + ".update sends " + s + self.src.send(s + "\n") + + + def quit(self, final_result): + self.base_player.quit(final_result) + self.src.close() + +class NetworkReceiver(Player,Network): + def __init__(self, colour, board, address=None): + + Player.__init__(self, address, colour) + + Network.__init__(self, colour, address) + + self.board = board + + + def select(self): + s = self.getline().strip(" \r\n") + return map(int,s.split(" ")) + def get_move(self): + s = self.getline().strip(" \r\n") + print str(self) + ".get_move gets " + s + return map(int, s.split(" ")) + + def update(self, result): + + result = result.split(" ") + [x,y] = map(int, result[0:2]) + selected = self.board.grid[x][y] + if selected != None and selected.colour == self.colour and len(result) > 2 and not "->" in result: + s = self.getline().strip(" \r\n") + print str(self) + ".update - receives " + str(s) + s = s.split(" ") + selected.choice = int(s[2]) + for i in range(2): + selected.types[i] = str(s[3+i]) + if s[3+i] == "unknown": + selected.types_revealed[i] = False + else: + selected.types_revealed[i] = True + selected.current_type = selected.types[selected.choice] + else: + print str(self) + ".update - ignore result " + str(result) + + + def quit(self, final_result): + self.src.close() + diff --git a/qchess/qchess.py b/qchess/qchess.py index 51e7304..aca4601 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -217,7 +217,7 @@ class Board(): raise Exception("EMPTY") if colour != None and piece.colour != colour: - raise Exception("COLOUR") + raise Exception("COLOUR " + str(piece.colour) + " not " + str(colour)) # I'm not quite sure why I made this return a string, but screw logical design return str(x) + " " + str(y) + " " + str(piece.select()) + " " + str(piece.current_type) @@ -655,6 +655,126 @@ class AgentRandom(Player): def quit(self, final_result): pass # --- player.py --- # +# +++ network.py +++ # +import socket + +class Network(): + def __init__(self, colour, address = None): + self.socket = socket.socket() + + if colour == "white": + self.port = 4563 + else: + self.port = 4564 + + self.src = None + + if address == None: + self.host = 'localhost' #socket.gethostname() + self.socket.bind((self.host, self.port)) + self.socket.listen(5) + + self.src, self.address = self.socket.accept() + else: + self.host = address + self.socket.connect(('localhost', self.port)) + self.src = self.socket + + def getline(self): + s = self.src.recv(1) + while s[len(s)-1] != '\n': + s += self.src.recv(1) + return s + + + + +class NetworkSender(Player,Network): + def __init__(self, base_player, board, address = None): + self.base_player = base_player + Player.__init__(self, base_player.name, base_player.colour) + Network.__init__(self, base_player.colour, address) + + self.board = board + + def select(self): + [x,y] = self.base_player.select() + choice = self.board.grid[x][y] + s = str(x) + " " + str(y) + print str(self) + ".select sends " + s + self.src.send(s + "\n") + return [x,y] + + def get_move(self): + [x,y] = self.base_player.get_move() + s = str(x) + " " + str(y) + print str(self) + ".get_move sends " + s + self.src.send(s + "\n") + return [x,y] + + def update(self, s): + self.base_player.update(s) + s = s.split(" ") + [x,y] = map(int, s[0:2]) + selected = self.board.grid[x][y] + if selected != None and selected.colour == self.colour and len(s) > 2 and not "->" in s: + s = " ".join(s[0:3]) + for i in range(2): + if selected.types_revealed[i] == True: + s += " " + str(selected.types[i]) + else: + s += " unknown" + print str(self) + ".update sends " + s + self.src.send(s + "\n") + + + def quit(self, final_result): + self.base_player.quit(final_result) + self.src.close() + +class NetworkReceiver(Player,Network): + def __init__(self, colour, board, address=None): + + Player.__init__(self, address, colour) + + Network.__init__(self, colour, address) + + self.board = board + + + def select(self): + s = self.getline().strip(" \r\n") + return map(int,s.split(" ")) + def get_move(self): + s = self.getline().strip(" \r\n") + print str(self) + ".get_move gets " + s + return map(int, s.split(" ")) + + def update(self, result): + + result = result.split(" ") + [x,y] = map(int, result[0:2]) + selected = self.board.grid[x][y] + if selected != None and selected.colour == self.colour and len(result) > 2 and not "->" in result: + s = self.getline().strip(" \r\n") + print str(self) + ".update - receives " + str(s) + s = s.split(" ") + selected.choice = int(s[2]) + for i in range(2): + selected.types[i] = str(s[3+i]) + if s[3+i] == "unknown": + selected.types_revealed[i] = False + else: + selected.types_revealed[i] = True + selected.current_type = selected.types[selected.choice] + else: + print str(self) + ".update - ignore result " + str(result) + + + def quit(self, final_result): + self.src.close() + +# --- network.py --- # # +++ thread_util.py +++ # import threading @@ -693,13 +813,19 @@ class GameThread(StoppableThread): for p in self.players: with self.lock: - self.state["turn"] = p # "turn" contains the player who's turn it is + if isinstance(p, NetworkSender): + self.state["turn"] = p.base_player # "turn" contains the player who's turn it is + else: + self.state["turn"] = p #try: if True: [x,y] = p.select() # Player selects a square if self.stopped(): break + + + result = self.board.select(x, y, colour = p.colour) for p2 in self.players: p2.update(result) # Inform players of what happened @@ -1111,35 +1237,40 @@ def main(argv): global graphics # Magical argument parsing goes here - if len(argv) == 1: - players = [HumanPlayer("saruman", "white"), AgentRandom("sabbath", "black")] - elif len(argv) == 2: - players = [AgentPlayer(argv[1], "white"), HumanPlayer("shadow", "black"), ] - elif len(argv) == 3: - players = [AgentPlayer(argv[1], "white"), AgentPlayer(argv[2], "black")] +# if len(argv) == 1: +# players = [HumanPlayer("saruman", "white"), AgentRandom("sabbath", "black")] +# elif len(argv) == 2: +# players = [AgentPlayer(argv[1], "white"), HumanPlayer("shadow", "black"), ] +# elif len(argv) == 3: +# players = [AgentPlayer(argv[1], "white"), AgentPlayer(argv[2], "black")] + - # Construct the board! board = Board(style = "quantum") + # Construct the board! + if len(argv) == 1: + players = [NetworkSender(HumanPlayer("saruman", "white"), board), NetworkReceiver("black", board, 'localhost')] + + else: + players = [NetworkReceiver("white", board, 'localhost'), NetworkSender(HumanPlayer("sabbath", "black"), board)] + + + + + graphics = GraphicsThread(board, grid_sz = [64,64]) # Construct a GraphicsThread! I KNOW WHAT I'M DOING! BEAR WITH ME! + + + + game = GameThread(board, players) # Construct a GameThread! Make it global! Damn the consequences! - #try: - if True: - graphics = GraphicsThread(board, grid_sz = [64,64]) # Construct a GraphicsThread! I KNOW WHAT I'M DOING! BEAR WITH ME! - game.start() # This runs in a new thread - #except NameError: - # print "Run game in main thread" - # game.run() # Run game in the main thread (no need for joining) - # return game.error - #except Exception, e: - # raise e - #else: - # print "Normal" - graphics.run() - game.join() - return game.error + graphics.error + game.start() # This runs in a new thread + + graphics.run() + game.join() + return game.error + graphics.error # This is how python does a main() function... if __name__ == "__main__": sys.exit(main(sys.argv)) # --- main.py --- # -# EOF - created from update.sh on Wed Jan 23 22:01:52 WST 2013 +# EOF - created from update.sh on Thu Jan 24 03:04:38 WST 2013 diff --git a/qchess/update.sh b/qchess/update.sh index a60ca80..6993e39 100755 --- a/qchess/update.sh +++ b/qchess/update.sh @@ -5,7 +5,7 @@ # (This can't be done with gnu make, because of circular dependency issues) target=qchess.py -components="piece.py board.py player.py thread_util.py game.py graphics.py main.py" +components="piece.py board.py player.py network.py thread_util.py game.py graphics.py main.py" # The below seems nicer, but doesn't work because things need to be imported in the right order :( #components=$(ls *.py | tr '\t' '\n' | grep -v $target) @@ -20,8 +20,10 @@ target_mod=$(stat -c %Y $target 2>/dev/null) if [ $? -ne 0 ]; then merge_required=true else - merge_required=false + merge_required=true + + echo " for f in $components; do component_mod=$(stat -c %Y $f 2>/dev/null) @@ -49,6 +51,8 @@ else merge_required=true fi done + " > /dev/null + fi # If any components were modified more recently than the target, merge the components into the target -- 2.20.1