Commit a6d91c8b authored by Sam Moore's avatar Sam Moore

Getting ready to run rounds

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
parent 3decbfd6
......@@ -2,6 +2,8 @@
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
......@@ -106,10 +108,17 @@ class AgentBishop_Graphics(GraphicsThread):
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)
graphics = AgentBishop_Graphics(agent.board, "Agent Bishop ("+agent.colour+") DEBUG")
graphics.start()
if graphics_enabled:
graphics = AgentBishop_Graphics(agent.board, "Agent Bishop ("+agent.colour+") DEBUG")
graphics.start()
run_agent(agent)
graphics.stop()
graphics.join()
if graphics_enabled:
graphics.stop()
graphics.join()
../../qchess/data/
\ No newline at end of file
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.
../../qchess/qchess.py
\ No newline at end of file
../qchess/data/
\ No newline at end of file
../qchess/qchess.py
\ No newline at end of file
../../qchess/data/
\ No newline at end of file
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.
../../qchess/qchess.py
\ No newline at end of file
......@@ -6,6 +6,8 @@
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):
......@@ -19,15 +21,17 @@ class AgentSample(InternalAgent):
#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.
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
sys.stderr.write(sys.argv[0] + " : " + str(self) + " : Selecting piece...\n")
if debug:
sys.stderr.write(sys.argv[0] + " : Selecting piece...\n")
# Here is a random choice algorithm to help you start
......@@ -73,7 +77,8 @@ class AgentSample(InternalAgent):
# TODO: Implement this
def get_move(self):
# debug message
sys.stderr.write(sys.argv[0] + " : " + str(self) + " : Moving piece ("+str(self.choice)+")\n")
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
......@@ -92,6 +97,14 @@ class AgentSample(InternalAgent):
# 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.
......
#!/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
......@@ -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
......@@ -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)
......
......@@ -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:
......
......@@ -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...
......
#!/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 "[email protected]" _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 [email protected]/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)"
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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment