Getting ready to run rounds
authorSam Moore <[email protected]>
Tue, 12 Feb 2013 09:08:39 +0000 (17:08 +0800)
committerSam Moore <[email protected]>
Tue, 12 Feb 2013 09:08:39 +0000 (17:08 +0800)
Got sidetracked writing "swarm" to parallelise rounds.
It's not ready yet, but I wrote run.sh to run a round.
Which should work even if I never finish swarm.
It'll just be ridiculously slow.

Changed structure of agents directory (same as last year).

Minor changes to qchess. Added yet another wrapper class for replaying logs.
FileReplayer replaces the standard python file; if a game is still in progress you can use that.

I noticed the Http log replay was breaking a while ago, but I haven't investigated.

TODO: - Finish swarm
      - Generate pretty html pages from results
        (but hopefully make the script nicer than last years)
      - Handle errors/illegal moves properly. Enforce the timeouts.
      - Include draws/stalemate
      - events? prizes? profit?
      - BUG FIXING
      - Read TODO lists more often, because I usually just write them and then never read them

21 files changed:
agents/bishop.py [deleted file]
agents/bishop/bishop.py [new file with mode: 0755]
agents/bishop/data [new symlink]
agents/bishop/info [new file with mode: 0644]
agents/bishop/qchess.py [new symlink]
agents/data [deleted symlink]
agents/qchess.py [deleted symlink]
agents/sample.py [deleted file]
agents/sample/data [new symlink]
agents/sample/info [new file with mode: 0644]
agents/sample/qchess.py [new symlink]
agents/sample/sample.py [new file with mode: 0755]
clean.sh [new file with mode: 0755]
qchess/build/exe.linux-x86_64-2.7.zip
qchess/build/exe.win32-2.7.zip
qchess/qchess.py
qchess/src/game.py
qchess/src/log.py
qchess/src/main.py
run.sh [new file with mode: 0755]
vars [new file with mode: 0644]

diff --git a/agents/bishop.py b/agents/bishop.py
deleted file mode 100755 (executable)
index ea96c2c..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/python -u
-
-from qchess import *
-
-"""
-       This is a wrapper to AgentBishop, which can now be found directly in qchess as one of the internal agents
-       As well as wrapping, it will also show AgentBishop's thought processes in graphics, which is kind of cool
-
-       So basically, using `./qchess.py @internal:AgentBishop` is better, unless you want to see the graphics
-"""
-
-       
-# Horrible messy graphics class that draws what the agent is doing, kind of useful for testing
-class AgentBishop_Graphics(GraphicsThread):
-       def __init__(self, board, title):
-               GraphicsThread.__init__(self, board, title, grid_sz = [64,64])
-               self.choice = None
-               self.moves = None
-
-       def run(self):
-               square_img = pygame.Surface((self.grid_sz[0], self.grid_sz[1]),pygame.SRCALPHA) # A square image
-               while not self.stopped():
-               
-                       self.board.display_grid(window = self.window, grid_sz = self.grid_sz)   
-
-                       # Draw choice of the AI
-                       if agent.choice != None:
-                               mp = [self.grid_sz[i] * [agent.choice.x, agent.choice.y][i] for i in range(2)]
-                               square_img.fill(pygame.Color(0,255,0,64))
-                               self.window.blit(square_img, mp)
-
-                       # Draw calculated choices for the piece clicked on
-                       if self.choice != None:
-                               mp = [self.grid_sz[i] * [self.choice.x, self.choice.y][i] for i in range(2)]
-                               square_img.fill(pygame.Color(0,0,255,128))
-                               self.window.blit(square_img, mp)
-
-                       # Draw the choices the AI calculated from the selection of the chosen piece
-                       if agent.choice != None and agent.choice.selected_moves != None:
-                               for m in agent.choice.selected_moves:
-                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
-                                       square_img.fill(pygame.Color(128,128,255,128))
-                                       self.window.blit(square_img, mp)
-                                       font = pygame.font.Font(None, 14)
-                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(255,0,0))
-                                       mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
-                                       mp[1] = mp[1] + self.grid_sz[1] - text.get_height()
-                                       self.window.blit(text, mp)
-
-
-                       # Draw the choice the AI's chosen piece could have actually made
-                       if agent.choice != None and agent.choice.last_moves != None:
-                               for m in agent.choice.last_moves:
-                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
-                                       square_img.fill(pygame.Color(255,0,0,128))
-                                       self.window.blit(square_img, mp)
-                                       font = pygame.font.Font(None, 14)
-                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,255))
-                                       mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
-                                       self.window.blit(text, mp)
-
-                       
-
-
-                       if self.moves != None:
-                               for m in self.moves:
-                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
-                                       square_img.fill(pygame.Color(255,0,255,128))
-                                       self.window.blit(square_img, mp)
-                                       font = pygame.font.Font(None, 14)
-                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,0))
-                                       self.window.blit(text, mp)
-                       
-                       
-       
-                       self.board.display_pieces(window = self.window, grid_sz = self.grid_sz)
-
-                       pygame.display.flip()
-                       
-                       for event in pygame.event.get():
-                               if event.type == pygame.QUIT:
-                                       self.stop()
-                                       break
-                               elif event.type == pygame.MOUSEBUTTONDOWN:
-                                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
-                                       p = agent.board.grid[m[0]][m[1]]
-                                       if p == None:
-                                               continue
-                                       self.choice = p
-                                       self.last_moves = self.choice.last_moves
-                                       self.selected_moves = self.choice.selected_moves
-                                       if event.button == 3 or self.choice.last_moves == None:
-                                               self.moves = agent.prioritise_moves(self.choice)
-                                       else:
-                                               self.moves = self.choice.last_moves
-                                       
-                               elif event.type == pygame.MOUSEBUTTONUP:
-                                       if self.choice == None:
-                                               continue
-                                       self.choice.last_moves = self.last_moves
-                                       self.choice.selected_moves = self.selected_moves
-                                       self.choice = None
-                                       self.moves = None
-                                       
-               pygame.display.quit()                           
-
-if __name__ == "__main__":
-       
-       colour = sys.stdin.readline().strip("\r\n")
-       agent = AgentBishop(sys.argv[0], colour)
-       graphics = AgentBishop_Graphics(agent.board, "Agent Bishop ("+agent.colour+") DEBUG")
-       graphics.start()
-       run_agent(agent)
-       graphics.stop()
-       graphics.join()
diff --git a/agents/bishop/bishop.py b/agents/bishop/bishop.py
new file mode 100755 (executable)
index 0000000..88f3c49
--- /dev/null
@@ -0,0 +1,124 @@
+#!/usr/bin/python -u
+
+from qchess import *
+
+graphics_enabled = True
+
+"""
+       This is a wrapper to AgentBishop, which can now be found directly in qchess as one of the internal agents
+       As well as wrapping, it will also show AgentBishop's thought processes in graphics, which is kind of cool
+
+       So basically, using `./qchess.py @internal:AgentBishop` is better, unless you want to see the graphics
+"""
+
+       
+# Horrible messy graphics class that draws what the agent is doing, kind of useful for testing
+class AgentBishop_Graphics(GraphicsThread):
+       def __init__(self, board, title):
+               GraphicsThread.__init__(self, board, title, grid_sz = [64,64])
+               self.choice = None
+               self.moves = None
+
+       def run(self):
+               square_img = pygame.Surface((self.grid_sz[0], self.grid_sz[1]),pygame.SRCALPHA) # A square image
+               while not self.stopped():
+               
+                       self.board.display_grid(window = self.window, grid_sz = self.grid_sz)   
+
+                       # Draw choice of the AI
+                       if agent.choice != None:
+                               mp = [self.grid_sz[i] * [agent.choice.x, agent.choice.y][i] for i in range(2)]
+                               square_img.fill(pygame.Color(0,255,0,64))
+                               self.window.blit(square_img, mp)
+
+                       # Draw calculated choices for the piece clicked on
+                       if self.choice != None:
+                               mp = [self.grid_sz[i] * [self.choice.x, self.choice.y][i] for i in range(2)]
+                               square_img.fill(pygame.Color(0,0,255,128))
+                               self.window.blit(square_img, mp)
+
+                       # Draw the choices the AI calculated from the selection of the chosen piece
+                       if agent.choice != None and agent.choice.selected_moves != None:
+                               for m in agent.choice.selected_moves:
+                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
+                                       square_img.fill(pygame.Color(128,128,255,128))
+                                       self.window.blit(square_img, mp)
+                                       font = pygame.font.Font(None, 14)
+                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(255,0,0))
+                                       mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
+                                       mp[1] = mp[1] + self.grid_sz[1] - text.get_height()
+                                       self.window.blit(text, mp)
+
+
+                       # Draw the choice the AI's chosen piece could have actually made
+                       if agent.choice != None and agent.choice.last_moves != None:
+                               for m in agent.choice.last_moves:
+                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
+                                       square_img.fill(pygame.Color(255,0,0,128))
+                                       self.window.blit(square_img, mp)
+                                       font = pygame.font.Font(None, 14)
+                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,255))
+                                       mp[0] = mp[0] + self.grid_sz[0] - text.get_width()
+                                       self.window.blit(text, mp)
+
+                       
+
+
+                       if self.moves != None:
+                               for m in self.moves:
+                                       mp = [m[0][i] * self.grid_sz[i] for i in range(2)]
+                                       square_img.fill(pygame.Color(255,0,255,128))
+                                       self.window.blit(square_img, mp)
+                                       font = pygame.font.Font(None, 14)
+                                       text = font.render("{0:.2f}".format(round(m[1],2)), 1, pygame.Color(0,0,0))
+                                       self.window.blit(text, mp)
+                       
+                       
+       
+                       self.board.display_pieces(window = self.window, grid_sz = self.grid_sz)
+
+                       pygame.display.flip()
+                       
+                       for event in pygame.event.get():
+                               if event.type == pygame.QUIT:
+                                       self.stop()
+                                       break
+                               elif event.type == pygame.MOUSEBUTTONDOWN:
+                                       m = [event.pos[i] / self.grid_sz[i] for i in range(len(event.pos))]
+                                       p = agent.board.grid[m[0]][m[1]]
+                                       if p == None:
+                                               continue
+                                       self.choice = p
+                                       self.last_moves = self.choice.last_moves
+                                       self.selected_moves = self.choice.selected_moves
+                                       if event.button == 3 or self.choice.last_moves == None:
+                                               self.moves = agent.prioritise_moves(self.choice)
+                                       else:
+                                               self.moves = self.choice.last_moves
+                                       
+                               elif event.type == pygame.MOUSEBUTTONUP:
+                                       if self.choice == None:
+                                               continue
+                                       self.choice.last_moves = self.last_moves
+                                       self.choice.selected_moves = self.selected_moves
+                                       self.choice = None
+                                       self.moves = None
+                                       
+               pygame.display.quit()                           
+
+if __name__ == "__main__":
+       
+       if sys.argv[1] == "--no-graphics":
+               graphics_enabled = False
+
+       colour = sys.stdin.readline().strip("\r\n")
+       agent = AgentBishop(sys.argv[0], colour)
+
+       if graphics_enabled:
+               graphics = AgentBishop_Graphics(agent.board, "Agent Bishop ("+agent.colour+") DEBUG")
+               graphics.start()
+       run_agent(agent)
+       
+       if graphics_enabled:
+               graphics.stop()
+               graphics.join()
diff --git a/agents/bishop/data b/agents/bishop/data
new file mode 120000 (symlink)
index 0000000..75a080a
--- /dev/null
@@ -0,0 +1 @@
+../../qchess/data/
\ No newline at end of file
diff --git a/agents/bishop/info b/agents/bishop/info
new file mode 100644 (file)
index 0000000..9ac962d
--- /dev/null
@@ -0,0 +1,5 @@
+bishop.py --no-graphics
+Sam Moore
+python
+A wrapper to qchess.AgentBishop (allows it to run as an external agent). See qchess/src/agent_bishop.py.
+This agent uses a min/max probability based scoring algorithm with a recursion depth of a couple of turns.
diff --git a/agents/bishop/qchess.py b/agents/bishop/qchess.py
new file mode 120000 (symlink)
index 0000000..35c6d6e
--- /dev/null
@@ -0,0 +1 @@
+../../qchess/qchess.py
\ No newline at end of file
diff --git a/agents/data b/agents/data
deleted file mode 120000 (symlink)
index 09607df..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../qchess/data/
\ No newline at end of file
diff --git a/agents/qchess.py b/agents/qchess.py
deleted file mode 120000 (symlink)
index 385f472..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../qchess/qchess.py
\ No newline at end of file
diff --git a/agents/sample.py b/agents/sample.py
deleted file mode 100755 (executable)
index 34ce858..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/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/agents/sample/data b/agents/sample/data
new file mode 120000 (symlink)
index 0000000..75a080a
--- /dev/null
@@ -0,0 +1 @@
+../../qchess/data/
\ No newline at end of file
diff --git a/agents/sample/info b/agents/sample/info
new file mode 100644 (file)
index 0000000..77784fc
--- /dev/null
@@ -0,0 +1,4 @@
+sample.py --no-debug
+Sam Moore
+python
+Sample agent; makes random moves. Basically a copy of the internal agent that makes random moves. With comments.
diff --git a/agents/sample/qchess.py b/agents/sample/qchess.py
new file mode 120000 (symlink)
index 0000000..35c6d6e
--- /dev/null
@@ -0,0 +1 @@
+../../qchess/qchess.py
\ No newline at end of file
diff --git a/agents/sample/sample.py b/agents/sample/sample.py
new file mode 100755 (executable)
index 0000000..55572a2
--- /dev/null
@@ -0,0 +1,124 @@
+#!/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
+
+debug = False
+
+# 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:
+               if debug:
+                       sys.stderr.write(sys.argv[0] + " : Initialised agent\n")
+               
+
+       # 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
+               if debug:
+                       sys.stderr.write(sys.argv[0] + " : 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
+               if debug:
+                       sys.stderr.write(sys.argv[0] + " : 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__":
+
+       # Parse arguments here
+       for i in range(len(sys.argv)):
+               if sys.argv[i] == "--debug":
+                       debug = True
+               elif sys.argv[i] == "--no-debug":
+                       debug = False
+
+       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/clean.sh b/clean.sh
new file mode 100755 (executable)
index 0000000..f3301c4
--- /dev/null
+++ b/clean.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# This script can be used to remove all results
+# For testing purposes
+
+. vars
+
+rm -f web/current.log
+
+rm -rf $results_dir
+
+for s in *.result; do
+       rm -f $s
+done
+
+cd $agent_dir
+for s in $(find . | grep score.dat); do
+       rm -f $s
+done
+               
+
+
index 5b52214..5b7b25c 100644 (file)
Binary files a/qchess/build/exe.linux-x86_64-2.7.zip and b/qchess/build/exe.linux-x86_64-2.7.zip differ
index 9d1041b..9250604 100644 (file)
Binary files a/qchess/build/exe.win32-2.7.zip and b/qchess/build/exe.win32-2.7.zip differ
index ced16ce..ced6001 100755 (executable)
@@ -1400,6 +1400,43 @@ class HttpReplay():
                        
        def close(self):
                self.getter.stop()
+
+class FileReplay():
+       def __init__(self, filename):
+               self.f = open(filename, "r", 0)
+               self.filename = filename
+               self.mod = os.path.getmtime(filename)
+               self.count = 0
+       
+       def readline(self):
+               line = self.f.readline()
+               
+               while line == "":
+                       mod2 = os.path.getmtime(self.filename)
+                       if mod2 > self.mod:
+                               #sys.stderr.write("File changed!\n")
+                               self.mod = mod2
+                               self.f.close()
+                               self.f = open(self.filename, "r", 0)
+                               
+                               new_line = self.f.readline()
+                               
+                               if " ".join(new_line.split(" ")[0:3]) != "# Short log":
+                                       for i in range(self.count):
+                                               new_line = self.f.readline()
+                                               #sys.stderr.write("Read back " + str(i) + ": " + str(new_line) + "\n")
+                                       new_line = self.f.readline()
+                               else:
+                                       self.count = 0
+                               
+                               line = new_line
+
+               self.count += 1
+               return line
+
+       def close(self):
+               self.f.close()
+               
                                                
 def log(s):
        for l in log_files:
@@ -1593,6 +1630,8 @@ class ReplayThread(GameThread):
                        if self.stopped():
                                break
                        
+                       if len(line) <= 0:
+                               continue
                                        
 
                        if line[0] == '#':
@@ -1640,7 +1679,10 @@ class ReplayThread(GameThread):
                                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)
+                                               if target.current_type != "unknown":
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                               else:
+                                                       graphics.state["moves"] = None
                                        time.sleep(turn_delay)
                        else:
                                self.board.update_move(x, y, x2, y2)
@@ -1798,7 +1840,7 @@ class GraphicsThread(StoppableThread):
                #print "Test font"
                pygame.font.Font(os.path.join(os.path.curdir, "data", "DejaVuSans.ttf"), 32).render("Hello", True,(0,0,0))
 
-               #load_images()
+               #create_images(grid_sz)
                create_images(grid_sz)
 
                """
@@ -2319,7 +2361,9 @@ def main(argv):
                elif arg[1] == '-' and arg[2:] == "reveal":
                        always_reveal_states = True
                elif (arg[1] == '-' and arg[2:] == "graphics"):
-                       graphics_enabled = not graphics_enabled
+                       graphics_enabled = True
+               elif (arg[1] == '-' and arg[2:] == "no-graphics"):
+                       graphics_enabled = False
                elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"):
                        # Load game from file
                        if len(arg[2:].split("=")) == 1:
@@ -2329,7 +2373,7 @@ def main(argv):
                                if f[0:7] == "http://":
                                        src_file = HttpReplay(f)
                                else:
-                                       src_file = open(f.split(":")[0], "r", 0)
+                                       src_file = FileReplay(f.split(":")[0])
 
                                        if len(f.split(":")) == 2:
                                                max_moves = int(f.split(":")[1])
@@ -2480,6 +2524,8 @@ def main(argv):
        if src_file != None and src_file != sys.stdin:
                src_file.close()
 
+       sys.stdout.write(game.final_result + "\n")
+
        return error
 
 # This is how python does a main() function...
@@ -2500,4 +2546,4 @@ if __name__ == "__main__":
                sys.exit(102)
 
 # --- main.py --- #
-# EOF - created from make on Thu Jan 31 13:37:15 WST 2013
+# EOF - created from make on Tue Feb 12 17:06:37 WST 2013
index 16f26d7..4eebc76 100644 (file)
@@ -180,6 +180,8 @@ class ReplayThread(GameThread):
                        if self.stopped():
                                break
                        
+                       if len(line) <= 0:
+                               continue
                                        
 
                        if line[0] == '#':
@@ -227,7 +229,10 @@ class ReplayThread(GameThread):
                                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)
+                                               if target.current_type != "unknown":
+                                                       graphics.state["moves"] = self.board.possible_moves(target)
+                                               else:
+                                                       graphics.state["moves"] = None
                                        time.sleep(turn_delay)
                        else:
                                self.board.update_move(x, y, x2, y2)
index 1ef8145..af0c2a7 100644 (file)
@@ -131,6 +131,43 @@ class HttpReplay():
                        
        def close(self):
                self.getter.stop()
+
+class FileReplay():
+       def __init__(self, filename):
+               self.f = open(filename, "r", 0)
+               self.filename = filename
+               self.mod = os.path.getmtime(filename)
+               self.count = 0
+       
+       def readline(self):
+               line = self.f.readline()
+               
+               while line == "":
+                       mod2 = os.path.getmtime(self.filename)
+                       if mod2 > self.mod:
+                               #sys.stderr.write("File changed!\n")
+                               self.mod = mod2
+                               self.f.close()
+                               self.f = open(self.filename, "r", 0)
+                               
+                               new_line = self.f.readline()
+                               
+                               if " ".join(new_line.split(" ")[0:3]) != "# Short log":
+                                       for i in range(self.count):
+                                               new_line = self.f.readline()
+                                               #sys.stderr.write("Read back " + str(i) + ": " + str(new_line) + "\n")
+                                       new_line = self.f.readline()
+                               else:
+                                       self.count = 0
+                               
+                               line = new_line
+
+               self.count += 1
+               return line
+
+       def close(self):
+               self.f.close()
+               
                                                
 def log(s):
        for l in log_files:
index cbc07f7..748a459 100644 (file)
@@ -109,7 +109,9 @@ def main(argv):
                elif arg[1] == '-' and arg[2:] == "reveal":
                        always_reveal_states = True
                elif (arg[1] == '-' and arg[2:] == "graphics"):
-                       graphics_enabled = not graphics_enabled
+                       graphics_enabled = True
+               elif (arg[1] == '-' and arg[2:] == "no-graphics"):
+                       graphics_enabled = False
                elif (arg[1] == '-' and arg[2:].split("=")[0] == "file"):
                        # Load game from file
                        if len(arg[2:].split("=")) == 1:
@@ -119,7 +121,7 @@ def main(argv):
                                if f[0:7] == "http://":
                                        src_file = HttpReplay(f)
                                else:
-                                       src_file = open(f.split(":")[0], "r", 0)
+                                       src_file = FileReplay(f.split(":")[0])
 
                                        if len(f.split(":")) == 2:
                                                max_moves = int(f.split(":")[1])
@@ -270,6 +272,8 @@ def main(argv):
        if src_file != None and src_file != sys.stdin:
                src_file.close()
 
+       sys.stdout.write(game.final_result + "\n")
+
        return error
 
 # This is how python does a main() function...
diff --git a/run.sh b/run.sh
new file mode 100755 (executable)
index 0000000..2067aca
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,160 @@
+#!/bin/bash
+
+# This script runs a single round of the competition
+
+. vars
+
+agents=""
+
+
+
+# Copy messages to a log file
+if [ "$BASH_ARGV" != "_worker_" ]; then
+       # Get the round number
+       mkdir -p $results_dir
+       cd $results_dir
+       round=$(ls | grep "round" | sed -e "s:round::g" | sort -n | head --lines=1)
+       if [ "$round" == "" ]; then round=0; fi
+       round=$(( $round + 1 ))
+       mkdir -p round$round
+       cd $root_dir
+       exec $0 "$@" _worker_ 2>&1 | tee $results_dir/round$round/run.log
+       exit $?
+else
+       cd $results_dir
+       round=$(ls | grep "round" | sed -e "s:round::g" | sort -n | head --lines=1)
+fi
+
+echo "Start at $(date)"
+
+# Setup the swarm
+if [ "$swarm_hosts" != "" ]; then
+       swarm --daemon
+       for h in $swarm_hosts; do
+               swarm -c "#ABSORB $h#"
+       done
+       swarm -c "#.*# cd $root_dir; mkdir -p $results_dir/round$round"
+fi
+
+
+
+cd $root_dir/$agent_dir
+count=0
+for f in $(ls); do
+       if [ -d $f ]; then
+               info_file=$(ls $f | grep -w "info")
+               if [ "$info_file" == "" ]; then
+                       echo "Skipping agent $f (missing info file)"
+               else
+                       count=$(( $count + 1 ))
+                       agents="$agents $f"
+               fi
+       fi
+done
+echo "Found $count agents in $agent_dir/"
+
+
+
+# Add all the games to swarm
+cd $root_dir
+
+if [ "$agents" == "" ]; then
+       echo "No agents to run round $round with" 1>&2
+       rm -rf "$results_dir/round$round"
+       exit 1
+fi
+
+echo "Start round $round"
+
+game=0
+for a in $agents; do
+       runa="$agent_dir/$a/$(head --lines=1 $agent_dir/$a/info)"
+       for b in $agents; do
+               if [ "$a" == "$b" ]; then continue; fi
+               for ((i=1;i<=$games_per_pair;++i)); do
+                       runb="$agent_dir/$b/$(head --lines=1 $agent_dir/$b/info)"
+                       f="${a}_${b}_${i}"
+
+                       game=$(( $game + 1))    
+                       l="$results_dir/round$round/$f.log"
+                       err="$results_dir/round$round/$f.err"
+
+                       echo "Game #$game: $a .vs. $b ($i of $games_per_pair)"
+                       if [ "$swarm_hosts" != "" ]; then
+                               swarm -c "$qchess --no-graphics \"$runa\" \"$runb\" --log=$l --log=@web/current.log 2>$err" -o $f.result
+                       else
+                               $qchess --no-graphics "$runa" "$runb" --log=$l --log=@web/current.log 1> $f.result 2> $err
+                               if [ "$(wc -l $err | awk '{print $1}')" == "0" ]; then rm $err; fi
+                       fi
+               done
+       done
+done
+
+
+
+if [ "$swarm_hosts" != "" ]; then
+       swarm -c "#BARRIER BLOCK#" # Wait for all games to finish
+
+       #Copy over log files (start before updating scores as the scp may take some time)
+       for h in "local $swarm_hosts"; do
+               cmd="
+               if [ \"\$(hostname)\" != \"$webserver\" ]; then
+                       cd $root_dir/$results_dir/round$round;
+                       for i in *.log *.err; do
+                               if [ \"\$(wc -l \$i | awk '{print \$1}')\" != 0 ]; then
+                                       scp \$i $webserver/$root_dir/$results_dir/round$round/\$i
+                               fi
+                       done
+               fi"
+               swarm -c "#$h:.* \$# $cmd" # Execute once on each host
+       done
+fi
+
+echo "Completed $games games with $count agents"
+
+# A bash function. Yes, they do exist.
+function update_score
+{
+       if [ -e $agent_dir/$1/score.dat ]; then
+               score=$(tail --lines=1 $agent_dir/$1/score.dat | awk '{print $1}')
+       else
+               score=0
+       fi
+       
+
+       score=$(( $score + $3 ))
+       echo "$3 $score $2 $4 $5" >> $agent_dir/$1/score.dat
+       return $score
+}
+
+# Go through results
+for f in *.result; do
+       log=round$round/$(echo $f.log | sed -e "s:.result::g")
+       white=$(echo $f | tr '_' '\t' | awk '{print $1}')
+       black=$(echo $f | tr '_' '\t' | awk '{print $2}')
+       if [ "$(cat $f)" == "white" ]; then
+               update_score $white $black $win_score WIN $log
+               update_score $black $white $loss_score LOSS $log
+       elif [ "$(cat $f)" == "black" ]; then
+               update_score $white $black $loss_score LOSS $log
+               update_score $black $white $win_score WIN $log
+       elif [ "$(cat $f)" == "DRAW" ]; then
+               update_score $white $black $draw_score DRAW $log
+               update_score $black $white $draw_score DRAW $log
+       else
+               echo "Unrecognised result \"$(cat $f)\" in $f" 1>&2
+       fi
+
+       rm $f
+done
+
+echo "Updated scores"
+
+#Close the swarm
+if [ "$swarm_hosts" != "" ]; then
+       swarm -c "#BARRIER BLOCK#"
+       swarm -c "#.*# exit"
+fi
+
+echo "Finished at $(date)"
+
diff --git a/vars b/vars
new file mode 100644 (file)
index 0000000..981395d
--- /dev/null
+++ b/vars
@@ -0,0 +1,12 @@
+root_dir=$(pwd)
+results_dir="web/results"
+agent_dir="agents"
+qchess="qchess/qchess.py"
+webserver=$(hostname) # Where log files need to be copied
+swarm_hosts=""
+
+games_per_pair=1
+win_score=3
+loss_score=1
+draw_score=1
+illegal_score=0

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