diff --git a/agents/sample.py b/agents/sample.py new file mode 100755 index 0000000000000000000000000000000000000000..34ce85895fc9bb3b3db51cde9daec3e52c199bbb --- /dev/null +++ b/agents/sample.py @@ -0,0 +1,111 @@ +#!/usr/bin/python -u + +# Sample agent +# Copy this file, change the agent as needed + +from qchess import * # This is normally considered bad practice in python, but good practice in UCC::Progcomp +import random # For the example which makes random moves + +# The first thing to do is pick a cool name... +class AgentSample(InternalAgent): + def __init__(self, name, colour): + InternalAgent.__init__(self, name, colour) # The InternalAgent class gives you some useful stuff + + # You can access self.board to get a qchess.Board that stores the state as recorded by the agent + # This board is automatically updated by the InternalAgent base class + # As well as a grid of pieces, qchess.Board gives you lists of pieces and other useful functions; see qchess/src/board.py + + + #TODO: Any extra initialisation + + # You should print debug messages like this: + sys.stderr.write(sys.argv[0] + " : " + str(self) + " : Initialised agent\n") + # I would appreciate it if you removed them before submitting an entry though. + + # Must return [x,y] of selected piece + # Your agent will call select(), followed by get_move() and so on + # TODO: Implement + def select(self): + # debug message + sys.stderr.write(sys.argv[0] + " : " + str(self) + " : Selecting piece...\n") + + + # Here is a random choice algorithm to help you start + # It is a slight improvement on purely random; it will pick a piece that has at least one known possible move + # BUT it has a possibility to loop infinitely! You should fix that. + + while True: + # Randomly pick a piece + # Use self.board.pieces[self.colour] to get a list of your pieces + # Use self.board.pieces[opponent(self.colour)] to get opponent pieces + # Use self.board.king[self.colour], vice versa, to get the king + + choices = self.board.pieces[self.colour] # All the agent's pieces + choice_index = random.randint(0, len(choices)-1) # Get the index in the list of the chosen piece + self.choice = choices[choice_index] # Choose the piece, and remember it + + # Find all known possible moves for the piece + # Use self.board.possible_moves(piece) to get a list of possible moves for a piece + # *BUT* Make sure the type of the piece is known (you can temporarily set it) first! + # Use Piece.current_type to get/set the current type of a piece + + all_moves = [] # Will store all possible moves for the piece + tmp = self.choice.current_type # Remember the chosen piece's current type + + if tmp == "unknown": # For pieces that are in a supperposition, try both types + for t in self.choice.types: + if t == "unknown": + continue # Ignore unknown types + self.choice.current_type = t # Temporarily overwrite the piece's type + all_moves += self.board.possible_moves(self.choice) # Add the possible moves for that type + else: + all_moves = self.board.possible_moves(self.choice) # The piece is in a classical state; add possible moves + self.choice.current_type = tmp # Reset the piece's current type + if len(all_moves) > 0: + break # If the piece had *any* possible moves, it is a good choice; leave the loop + # Otherwise the loop will try again + # End while loop + + return [self.choice.x, self.choice.y] # Return the position of the selected piece + + # Must return [x,y] of square to move the piece previously selected into + # Your agent will call select(), followed by get_move() and so on + # TODO: Implement this + def get_move(self): + # debug message + sys.stderr.write(sys.argv[0] + " : " + str(self) + " : Moving piece ("+str(self.choice)+")\n") + # As an example we will just pick a random move for the piece previously chosen in select() + + # Note that whichever piece was previously selected will have collapsed into a classical state + + # self.board.possible_moves(piece) will return a list of [x,y] pairs for valid moves + + moves = self.board.possible_moves(self.choice) # Get all moves for the selected piece + move_index = random.randint(0, len(moves)-1) # Get the index in the list of the chosen move + return moves[move_index] # This is a randomly chosen [x,y] pair for a valid move of the piece + + +# Hints: +# select will probably have to be more complicated than get_move, because by the time get_move is called, the piece's state is known +# If you want to see if a square is threatened/defended, you can call self.board.coverage([x,y]); see qchess/src/board.py +# A good approach is min/max. For each move, associate a score. Then subtract the scores for moves that the opponent could make. Then pick the move with the highest score. +# Look at qchess/src/agent_bishop.py for a more effective (but less explained) agent + +if __name__ == "__main__": + colour = sys.stdin.readline().strip("\r\n") + agent = AgentSample(sys.argv[0], colour) # Change the class name here + run_agent(agent) # This is provided by qchess. It calls the functions of your agent as required during the game. + +# You can run this as an external agent with the qchess program +# Just run ./qchess.py and apply common sense (or read the help file) + +# If you are feeling adventurous you can add it to the qchess program as an internal agent +# This might give better performance... unless you use the --timeout switch, in which case there is absolutely no point +# 1. Delete the lines that run the agent (the block that starts with if __name__ == "__main__") +# 2. Copy the file to qchess/src/agent_sample.py (or whatever you want to call it) +# 3. Edit qchess/src/Makefile so that agent_sample.py appears as one of the files in COMPONENTS +# 4. Rebuild by running make in qchess +# Again, run ./qchess.py and apply common sense + + + diff --git a/qchess/Makefile b/qchess/Makefile index c6a748348bc9acb225cbff2dd59e2cf7d0f56409..6a6e81c0144a0b02d8620d685aacbd01a97dbffd 100644 --- a/qchess/Makefile +++ b/qchess/Makefile @@ -3,14 +3,16 @@ SCRIPT=qchess.py DLL_PATH=win32_dll +python_native : + make -C src + mv src/$(SCRIPT) ./ + + all : python_native frozen frozen : win32_frozen linux64_frozen cd build; for d in $$(ls); do if [ -d $$d ]; then zip -r $$d.zip $$d; rm -r $$d; fi; done -python_native : - make -C src - mv src/$(SCRIPT) ./ images : cd tools; python image_builder.py diff --git a/qchess/build/exe.linux-x86_64-2.7.zip b/qchess/build/exe.linux-x86_64-2.7.zip index 80e181927a9d41f66f39b41927f338a1bcf4c507..5b5221480b15bbb71407f309567a312495212f1b 100644 Binary files a/qchess/build/exe.linux-x86_64-2.7.zip and b/qchess/build/exe.linux-x86_64-2.7.zip differ diff --git a/qchess/build/exe.win32-2.7.zip b/qchess/build/exe.win32-2.7.zip index 402948b4cc498bb32ceda96da05d3194bd76e392..9d1041ba3ab84dcf734950128645afac6cff72f3 100644 Binary files a/qchess/build/exe.win32-2.7.zip and b/qchess/build/exe.win32-2.7.zip differ diff --git a/qchess/data/help.txt b/qchess/data/help.txt index c0a8b6f9dbeb0178dab76457257ad1c704d57700..892a7ec8f506f9a13025370e5e473b155e7077c8 100644 --- a/qchess/data/help.txt +++ b/qchess/data/help.txt @@ -64,9 +64,23 @@ OPTIONS If graphics are enabled (default), then the user will be prompted to choose any of the two players not supplied as arguments. + --reveal + If graphics are enabled, the two states for pieces will always be shown, regardless of whether both states have been revealed. + Note that this switch only affects the GUI and does not provide any information to agent players. - --file[=filename] + If graphics are disabled, has no effect. + + --file[=filename][:events] Replay a game saved in file, or read from stdin if no filename given + If a number of events is supplied, the game will advance that many events before stopping. + + If no players are given, the GUI will NOT ask for player selections. + The game will exit after the replay finishes. Events in the replay will be subject to the normal delay (see --delay). + + If black and white players are supplied, the game will continue using those players. + In this case, there will be no delays between events in the replay (the game starts at the end of the replay) + + (We hope that) this feature will be useful for comparing how different versions of an agent respond to the same situation. --log[=filename] Log moves to a file or stdout if no filename given diff --git a/qchess/qchess.py b/qchess/qchess.py index 219b34f7575bdef46077bfbdc7353259c120afba..02a724ab2ea05a25dce5ea6e31d748c0a8d42f64 100755 --- a/qchess/qchess.py +++ b/qchess/qchess.py @@ -39,7 +39,7 @@ class Piece(): # Make a string for the piece (used for debug) def __str__(self): - return str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y) + return str(self.colour) + " " + str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y) # Draw the piece in a pygame surface def draw(self, window, grid_sz = [80,80], style="quantum"): @@ -59,7 +59,7 @@ class Piece(): # Draw the two possible types underneath the current_type image for i in range(len(self.types)): - if self.types_revealed[i] == True: + if always_reveal_states == True or self.types_revealed[i] == True: 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 @@ -97,6 +97,8 @@ class Piece(): # --- piece.py --- # [w,h] = [8,8] # Width and height of board(s) +always_reveal_states = False + # Class to represent a quantum chess board class Board(): # Initialise; if master=True then the secondary piece types are assigned @@ -111,6 +113,9 @@ class Board(): for c in ["black", "white"]: del self.unrevealed_types[c]["unknown"] + if style == "empty": + return + # Add all the pieces with known primary types for i in range(0, 2): @@ -704,8 +709,6 @@ class AgentRandom(InternalAgent): def run_agent(agent): #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n") - colour = sys.stdin.readline().strip(" \r\n") - agent.colour = colour while True: line = sys.stdin.readline().strip(" \r\n") if line == "SELECTION?": @@ -730,7 +733,7 @@ def run_agent(agent): class ExternalWrapper(ExternalAgent): def __init__(self, agent): - run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.exit(run_agent(agent))\"" + run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\"" # str(run) ExternalAgent.__init__(self, run, agent.colour) @@ -1205,7 +1208,20 @@ def log(s): import datetime log_file.write(str(datetime.datetime.now()) + " : " + s + "\n") +def log_init(board, players): + if log_file != None: + import datetime + log_file.write("# Log starts " + str(datetime.datetime.now()) + "\n") + for p in players: + log_file.write("# " + p.colour + " : " + p.name + "\n") + + log_file.write("# Initial board\n") + for x in range(0, w): + for y in range(0, h): + if board.grid[x][y] != None: + log_file.write(str(board.grid[x][y]) + "\n") + log_file.write("# Start game\n") # A thread that runs the game @@ -1219,6 +1235,8 @@ class GameThread(StoppableThread): self.lock = threading.RLock() #lock for access of self.state self.cond = threading.Condition() # conditional for some reason, I forgot self.final_result = "" + + # Run the game (run in new thread with start(), run in current thread with run()) def run(self): @@ -1330,20 +1348,53 @@ class GameThread(StoppableThread): # A thread that replays a log file class ReplayThread(GameThread): - def __init__(self, players, src): - self.board = Board(style="agent") + def __init__(self, players, src, end=False,max_lines=None): + self.board = Board(style="empty") GameThread.__init__(self, self.board, players) self.src = src + self.max_lines = max_lines + self.line_number = 0 + self.end = end - self.ended = False + try: + while self.src.readline().strip(" \r\n") != "# Initial board": + self.line_number += 1 + + line = self.src.readline().strip(" \r\n") + + while line != "# Start game": + #print "Reading line " + str(line) + self.line_number += 1 + [x,y] = map(int, line.split("at")[1].strip(" \r\n").split(",")) + colour = line.split(" ")[0] + current_type = line.split(" ")[1] + types = map(lambda e : e.strip(" [],'"), line.split(" ")[2:4]) + p = Piece(colour, x, y, types) + if current_type != "unknown": + p.current_type = current_type + p.choice = types.index(current_type) + + self.board.pieces[colour].append(p) + self.board.grid[x][y] = p + if current_type == "king": + self.board.king[colour] = p + + line = self.src.readline().strip(" \r\n") + + except Exception, e: + raise Exception("FILE line: " + str(self.line_number) + " \""+str(line)+"\"") #\n" + e.message) def run(self): i = 0 phase = 0 - for line in self.src: + count = 0 + line = self.src.readline().strip(" \r\n") + while line != "# EOF": + count += 1 + if self.max_lines != None and count > self.max_lines: + self.stop() if self.stopped(): - self.ended = True break with self.lock: @@ -1356,10 +1407,8 @@ class ReplayThread(GameThread): try: self.board.update(result) except: - self.ended = True self.final_result = result - if isinstance(graphics, GraphicsThread): - graphics.stop() + self.stop() break [x,y] = map(int, result.split(" ")[0:2]) @@ -1371,14 +1420,16 @@ class ReplayThread(GameThread): graphics.state["moves"] = self.board.possible_moves(target) graphics.state["select"] = target - time.sleep(turn_delay) + if self.end: + time.sleep(turn_delay) elif phase == 1: [x2,y2] = map(int, result.split(" ")[3:5]) with graphics.lock: graphics.state["moves"] = [[x2,y2]] - time.sleep(turn_delay) + if self.end: + time.sleep(turn_delay) with graphics.lock: graphics.state["select"] = None @@ -1396,6 +1447,21 @@ class ReplayThread(GameThread): if phase == 0: i = (i + 1) % 2 + line = self.src.readline().strip(" \r\n") + + 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: + global game + game = GameThread(self.board, self.players) + game.run() + + def opponent(colour): @@ -1965,8 +2031,9 @@ def main(argv): global log_file global src_file global graphics_enabled + global always_reveal_states - + max_lines = None src_file = None style = "quantum" @@ -2003,6 +2070,8 @@ def main(argv): style = "classical" elif arg[1] == '-' and arg[2:] == "quantum": style = "quantum" + elif arg[1] == '-' and arg[2:] == "reveal": + always_reveal_states = True elif (arg[1] == '-' and arg[2:] == "graphics"): graphics_enabled = not graphics_enabled elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"): @@ -2010,7 +2079,11 @@ def main(argv): if len(arg[2:].split("=")) == 1: src_file = sys.stdin else: - src_file = open(arg[2:].split("=")[1]) + src_file = open(arg[2:].split("=")[1].split(":")[0]) + + if len(arg[2:].split(":")) == 2: + max_lines = int(arg[2:].split(":")[1]) + elif (arg[1] == '-' and arg[2:].split("=")[0] == "log"): # Log file if len(arg[2:].split("=")) == 1: @@ -2042,9 +2115,21 @@ def main(argv): # Construct a GameThread! Make it global! Damn the consequences! if src_file != None: - if len(players) == 0: + # Hack to stop ReplayThread from exiting + #if len(players) == 0: + # players = [HumanPlayer("dummy", "white"), HumanPlayer("dummy", "black")] + + # Normally the ReplayThread exits if there are no players + # TODO: Decide which behaviour to use, and fix it + end = (len(players) == 0) + if end: players = [Player("dummy", "white"), Player("dummy", "black")] - game = ReplayThread(players, src_file) + elif len(players) != 2: + sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n") + 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) else: board = Board(style) game = GameThread(board, players) @@ -2117,17 +2202,24 @@ def main(argv): + log_init(game.board, players) + if graphics != None: game.start() # This runs in a new thread graphics.run() - game.join() + if game.is_alive(): + game.join() + + error = game.error + graphics.error else: game.run() error = game.error + if log_file != None and log_file != sys.stdout: + log_file.write("# EOF\n") log_file.close() if src_file != None and src_file != sys.stdin: @@ -2137,6 +2229,20 @@ def main(argv): # This is how python does a main() function... if __name__ == "__main__": - sys.exit(main(sys.argv)) + try: + sys.exit(main(sys.argv)) + except KeyboardInterrupt: + sys.stderr.write(sys.argv[0] + " : Got KeyboardInterrupt. Stopping everything\n") + if isinstance(graphics, StoppableThread): + graphics.stop() + graphics.run() # Will clean up graphics because it is stopped, not run it (a bit dodgy) + + if isinstance(game, StoppableThread): + game.stop() + if game.is_alive(): + game.join() + + sys.exit(102) + # --- main.py --- # -# EOF - created from make on Tue Jan 29 18:10:18 WST 2013 +# EOF - created from make on Wed Jan 30 00:45:46 WST 2013 diff --git a/qchess/src/board.py b/qchess/src/board.py index 0d96d1ae928f878edde7344059d318319dadaa62..5dbf1dd2a9486f64a8636815b999ccb89fd0c357 100644 --- a/qchess/src/board.py +++ b/qchess/src/board.py @@ -1,5 +1,7 @@ [w,h] = [8,8] # Width and height of board(s) +always_reveal_states = False + # Class to represent a quantum chess board class Board(): # Initialise; if master=True then the secondary piece types are assigned @@ -14,6 +16,9 @@ class Board(): for c in ["black", "white"]: del self.unrevealed_types[c]["unknown"] + if style == "empty": + return + # Add all the pieces with known primary types for i in range(0, 2): diff --git a/qchess/src/game.py b/qchess/src/game.py index e3f1c7cd3bdca0d421c952184836819f9f1b02ac..07a1325a9d96940b54820681139b6b17f0ef2309 100644 --- a/qchess/src/game.py +++ b/qchess/src/game.py @@ -7,7 +7,20 @@ def log(s): import datetime log_file.write(str(datetime.datetime.now()) + " : " + s + "\n") +def log_init(board, players): + if log_file != None: + import datetime + log_file.write("# Log starts " + str(datetime.datetime.now()) + "\n") + for p in players: + log_file.write("# " + p.colour + " : " + p.name + "\n") + + log_file.write("# Initial board\n") + for x in range(0, w): + for y in range(0, h): + if board.grid[x][y] != None: + log_file.write(str(board.grid[x][y]) + "\n") + log_file.write("# Start game\n") # A thread that runs the game @@ -21,6 +34,8 @@ class GameThread(StoppableThread): self.lock = threading.RLock() #lock for access of self.state self.cond = threading.Condition() # conditional for some reason, I forgot self.final_result = "" + + # Run the game (run in new thread with start(), run in current thread with run()) def run(self): @@ -132,20 +147,53 @@ class GameThread(StoppableThread): # A thread that replays a log file class ReplayThread(GameThread): - def __init__(self, players, src): - self.board = Board(style="agent") + def __init__(self, players, src, end=False,max_lines=None): + self.board = Board(style="empty") GameThread.__init__(self, self.board, players) self.src = src + self.max_lines = max_lines + self.line_number = 0 + self.end = end - self.ended = False + try: + while self.src.readline().strip(" \r\n") != "# Initial board": + self.line_number += 1 + + line = self.src.readline().strip(" \r\n") + + while line != "# Start game": + #print "Reading line " + str(line) + self.line_number += 1 + [x,y] = map(int, line.split("at")[1].strip(" \r\n").split(",")) + colour = line.split(" ")[0] + current_type = line.split(" ")[1] + types = map(lambda e : e.strip(" [],'"), line.split(" ")[2:4]) + p = Piece(colour, x, y, types) + if current_type != "unknown": + p.current_type = current_type + p.choice = types.index(current_type) + + self.board.pieces[colour].append(p) + self.board.grid[x][y] = p + if current_type == "king": + self.board.king[colour] = p + + line = self.src.readline().strip(" \r\n") + + except Exception, e: + raise Exception("FILE line: " + str(self.line_number) + " \""+str(line)+"\"") #\n" + e.message) def run(self): i = 0 phase = 0 - for line in self.src: + count = 0 + line = self.src.readline().strip(" \r\n") + while line != "# EOF": + count += 1 + if self.max_lines != None and count > self.max_lines: + self.stop() if self.stopped(): - self.ended = True break with self.lock: @@ -158,10 +206,8 @@ class ReplayThread(GameThread): try: self.board.update(result) except: - self.ended = True self.final_result = result - if isinstance(graphics, GraphicsThread): - graphics.stop() + self.stop() break [x,y] = map(int, result.split(" ")[0:2]) @@ -173,14 +219,16 @@ class ReplayThread(GameThread): graphics.state["moves"] = self.board.possible_moves(target) graphics.state["select"] = target - time.sleep(turn_delay) + if self.end: + time.sleep(turn_delay) elif phase == 1: [x2,y2] = map(int, result.split(" ")[3:5]) with graphics.lock: graphics.state["moves"] = [[x2,y2]] - time.sleep(turn_delay) + if self.end: + time.sleep(turn_delay) with graphics.lock: graphics.state["select"] = None @@ -198,6 +246,21 @@ class ReplayThread(GameThread): if phase == 0: i = (i + 1) % 2 + line = self.src.readline().strip(" \r\n") + + 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: + global game + game = GameThread(self.board, self.players) + game.run() + + def opponent(colour): diff --git a/qchess/src/main.py b/qchess/src/main.py index 0adecb0e5c1cd362e9315dadcf897ba903cc8899..137d1cb7f77a19395459012138d00d764bb707f7 100644 --- a/qchess/src/main.py +++ b/qchess/src/main.py @@ -67,8 +67,9 @@ def main(argv): global log_file global src_file global graphics_enabled + global always_reveal_states - + max_lines = None src_file = None style = "quantum" @@ -105,6 +106,8 @@ def main(argv): style = "classical" elif arg[1] == '-' and arg[2:] == "quantum": style = "quantum" + elif arg[1] == '-' and arg[2:] == "reveal": + always_reveal_states = True elif (arg[1] == '-' and arg[2:] == "graphics"): graphics_enabled = not graphics_enabled elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"): @@ -112,7 +115,11 @@ def main(argv): if len(arg[2:].split("=")) == 1: src_file = sys.stdin else: - src_file = open(arg[2:].split("=")[1]) + src_file = open(arg[2:].split("=")[1].split(":")[0]) + + if len(arg[2:].split(":")) == 2: + max_lines = int(arg[2:].split(":")[1]) + elif (arg[1] == '-' and arg[2:].split("=")[0] == "log"): # Log file if len(arg[2:].split("=")) == 1: @@ -144,9 +151,21 @@ def main(argv): # Construct a GameThread! Make it global! Damn the consequences! if src_file != None: - if len(players) == 0: + # Hack to stop ReplayThread from exiting + #if len(players) == 0: + # players = [HumanPlayer("dummy", "white"), HumanPlayer("dummy", "black")] + + # Normally the ReplayThread exits if there are no players + # TODO: Decide which behaviour to use, and fix it + end = (len(players) == 0) + if end: players = [Player("dummy", "white"), Player("dummy", "black")] - game = ReplayThread(players, src_file) + elif len(players) != 2: + sys.stderr.write(sys.argv[0] + " : Usage " + sys.argv[0] + " white black\n") + 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) else: board = Board(style) game = GameThread(board, players) @@ -219,17 +238,24 @@ def main(argv): + log_init(game.board, players) + if graphics != None: game.start() # This runs in a new thread graphics.run() - game.join() + if game.is_alive(): + game.join() + + error = game.error + graphics.error else: game.run() error = game.error + if log_file != None and log_file != sys.stdout: + log_file.write("# EOF\n") log_file.close() if src_file != None and src_file != sys.stdin: @@ -239,4 +265,18 @@ def main(argv): # This is how python does a main() function... if __name__ == "__main__": - sys.exit(main(sys.argv)) + try: + sys.exit(main(sys.argv)) + except KeyboardInterrupt: + sys.stderr.write(sys.argv[0] + " : Got KeyboardInterrupt. Stopping everything\n") + if isinstance(graphics, StoppableThread): + graphics.stop() + graphics.run() # Will clean up graphics because it is stopped, not run it (a bit dodgy) + + if isinstance(game, StoppableThread): + game.stop() + if game.is_alive(): + game.join() + + sys.exit(102) + diff --git a/qchess/src/piece.py b/qchess/src/piece.py index d9acef27eca98b2acf89a14cf2826c98d1deeb32..400a79a991ee7a2ba8d6b7eede0e71982bba50ff 100644 --- a/qchess/src/piece.py +++ b/qchess/src/piece.py @@ -38,7 +38,7 @@ class Piece(): # Make a string for the piece (used for debug) def __str__(self): - return str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y) + return str(self.colour) + " " + str(self.current_type) + " " + str(self.types) + " at " + str(self.x) + ","+str(self.y) # Draw the piece in a pygame surface def draw(self, window, grid_sz = [80,80], style="quantum"): @@ -58,7 +58,7 @@ class Piece(): # Draw the two possible types underneath the current_type image for i in range(len(self.types)): - if self.types_revealed[i] == True: + if always_reveal_states == True or self.types_revealed[i] == True: 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 diff --git a/qchess/src/player.py b/qchess/src/player.py index b3f0eb70b641beb9c01e9f9a8f75f3f7f801557e..0a4ddd6c971453cab68011061b92c6193ddae0e4 100644 --- a/qchess/src/player.py +++ b/qchess/src/player.py @@ -203,8 +203,6 @@ class AgentRandom(InternalAgent): def run_agent(agent): #sys.stderr.write(sys.argv[0] + " : Running agent " + str(agent) + "\n") - colour = sys.stdin.readline().strip(" \r\n") - agent.colour = colour while True: line = sys.stdin.readline().strip(" \r\n") if line == "SELECTION?": @@ -229,7 +227,7 @@ def run_agent(agent): class ExternalWrapper(ExternalAgent): def __init__(self, agent): - run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.exit(run_agent(agent))\"" + run = "python -u -c \"import sys;import os;from qchess import *;agent = " + agent.__class__.__name__ + "('" + agent.name + "','"+agent.colour+"');sys.stdin.readline();sys.exit(run_agent(agent))\"" # str(run) ExternalAgent.__init__(self, run, agent.colour)