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
+++ /dev/null
-#!/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()
--- /dev/null
+#!/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()
--- /dev/null
+../../qchess/data/
\ No newline at end of file
--- /dev/null
+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.
--- /dev/null
+../../qchess/qchess.py
\ No newline at end of file
+++ /dev/null
-../qchess/data/
\ No newline at end of file
+++ /dev/null
-../qchess/qchess.py
\ No newline at end of file
+++ /dev/null
-#!/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
-
-
-
--- /dev/null
+../../qchess/data/
\ No newline at end of file
--- /dev/null
+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.
--- /dev/null
+../../qchess/qchess.py
\ No newline at end of file
--- /dev/null
+#!/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
+
+
+
--- /dev/null
+#!/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
+
+
+
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:
if self.stopped():
break
+ if len(line) <= 0:
+ continue
if line[0] == '#':
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)
#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)
"""
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:
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])
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...
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
if self.stopped():
break
+ if len(line) <= 0:
+ continue
if line[0] == '#':
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)
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:
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:
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])
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...
--- /dev/null
+#!/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)"
+
--- /dev/null
+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