Commit 6515461b authored by Samuel Moore's avatar Samuel Moore

Improved simulate.py

I want to generate semi-useful results .html pages using simulate.py
It doesn't do this yet, but now it stores all the information I might need in a dictionary.
The dictionary for each agent replaces the array which I was previously using.

I also made some more of the global variables into optional arguments with default values.
parent b9ca61b4
...@@ -19,30 +19,48 @@ import os ...@@ -19,30 +19,48 @@ import os
import sys import sys
from time import time from time import time
baseDirectory = "/home/sam/Documents/progcomp2012/progcomp/" #Global variables/arguments
resultsDirectory = baseDirectory+"results/" #Where results will go (results are in the form of text files of agent names and scores)
agentsDirectory = baseDirectory+"agents/" #Where agents are found (each agent has its own directory)
logDirectory = baseDirectory+"log/" #Where log files go
nGames = 10 #Number of games played by each agent against each opponent. Half will be played as RED, half as BLUE
managerPath = baseDirectory+"judge/manager/stratego" #Path to the manager program
baseDirectory = "../.." #Base directory for results, logs, agents
nGames = 2 #Number of games played by each agent against each opponent. Half will be played as RED, half as BLUE. If nGames <= 1, then no games will be played (useful for dry run?)
nRounds = 1 nRounds = 1
time() if len(sys.argv) >= 2:
if len(sys.argv) == 2:
nRounds = int(sys.argv[1]) nRounds = int(sys.argv[1])
elif len(sys.argv) != 1: if len(sys.argv) >= 3:
print "Useage: simulate.py [nRounds]" nGames = int(sys.argv[2])
if nGames % 2 != 0:
print "Warning: nGames should be even. "+str(nGames)+" specified, but only " + str(int(nGames/2) * 2)+" will be played!"
if len(sys.argv) >= 4:
baseDirectory = sys.argv[3]
if len(sys.argv) >= 6:
print "Useage: " +sys.argv[0] + " [nRounds=1] [nGames=10] [baseDirectory=\""+baseDirectory+"\"] [managerPath=baseDirectory+\"/judge/manager/stratego\"]"
sys.exit(1) sys.exit(1)
resultsDirectory = baseDirectory+"/results/" #Where results will go (results are in the form of text files of agent names and scores)
logDirectory = baseDirectory+"/log/" #Where log files go (direct output of manager program)
agentsDirectory = baseDirectory+"/agents/" #Where agents are found (each agent has its own subdirectory within this directory)
managerPath = baseDirectory+"/judge/manager/stratego" #Path to the executable that plays the games
if len(sys.argv) >= 5:
managerPath = sys.argv[5]
#Score dictionary - Tuple is of the form: (end score, other score, other result) where end is the player on whose turn the result occurs, other is the other player, other result indicates what to record the outcome as for the other player.
scores = {"VICTORY":(3,1, "DEFEAT"), "DEFEAT":(1,3, "VICTORY"), "SURRENDER":(1,3, "VICTORY"), "DRAW":(2,2, "DRAW"), "DRAW_DEFAULT":(1,1, "DRAW_DEFAULT"), "ILLEGAL":(-1,2, "DEFAULT"), "DEFAULT":(2,-1, "ILLEGAL"), "BOTH_ILLEGAL":(-1,-1, "BOTH_ILLEGAL"), "INTERNAL_ERROR":(0,0, "INTERNAL_ERROR"), "BAD_SETUP":(0,0,"BAD_SETUP")}
scores = {"VICTORY":(3,1), "DEFEAT":(1,3), "SURRENDER":(0,3), "DRAW":(2,2), "DRAW_DEFAULT":(1,1), "ILLEGAL":(-1,2), "DEFAULT":(2,-1), "BOTH_ILLEGAL":(-1,-1), "INTERNAL_ERROR":(0,0), "BAD_SETUP":(0,0)} #Score dictionary
#Verbose - print lots of useless stuff about what you are doing (kind of like matches in irc...)
verbose = True verbose = True
makePrettyResults = False
#Check the manager program exists TODO: And is executable!
if os.path.exists(managerPath) == False:
print "Manager program at \""+managerPath+"\" doesn't exist!"
sys.exit(1)
#Make necessary directories #Make necessary directories
if os.path.exists(resultsDirectory) == False: if os.path.exists(resultsDirectory) == False:
os.mkdir(resultsDirectory) #Make the results directory if it didn't exist os.mkdir(resultsDirectory) #Make the results directory if it didn't exist
#Identify the round number by reading the results directory #Identify the round number by reading the results directory
...@@ -53,8 +71,10 @@ if totalRounds > 1: ...@@ -53,8 +71,10 @@ if totalRounds > 1:
if os.path.exists(logDirectory) == False: if os.path.exists(logDirectory) == False:
os.mkdir(logDirectory) #Make the log directory if it didn't exist os.mkdir(logDirectory) #Make the log directory if it didn't exist
startTime = time()
startTime = time() #Record time at which simulation starts
#Do each round...
for roundNumber in range(totalRounds, totalRounds + nRounds): for roundNumber in range(totalRounds, totalRounds + nRounds):
if os.path.exists(logDirectory + "round"+str(roundNumber)) == False: if os.path.exists(logDirectory + "round"+str(roundNumber)) == False:
...@@ -65,6 +85,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -65,6 +85,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
print "Identifying possible agents in \""+agentsDirectory+"\"" print "Identifying possible agents in \""+agentsDirectory+"\""
#Get all agent names from agentsDirectory #Get all agent names from agentsDirectory
#TODO: Move this part outside the loop? It only has to happen once
agentNames = os.listdir(agentsDirectory) agentNames = os.listdir(agentsDirectory)
agents = [] agents = []
for name in agentNames: for name in agentNames:
...@@ -82,11 +103,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -82,11 +103,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
continue continue
#Convert the array of names to an array of triples
#agents[0] - The name of the agent (its directory)
#agents[1] - The path to the program for the agent (typically agentsDirectory/agent/agent). Read from agentsDirectory/agent/info file
#agents[2] - The score the agent achieved in _this_ round. Begins at zero
agentExecutable = agentsDirectory+name+"/"+(open(agentsDirectory+name+"/info").readline().strip()) agentExecutable = agentsDirectory+name+"/"+(open(agentsDirectory+name+"/info").readline().strip())
if os.path.exists(agentExecutable) == False: if os.path.exists(agentExecutable) == False:
...@@ -97,8 +114,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -97,8 +114,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
if verbose: if verbose:
sys.stdout.write(" Valid! (To run: \""+agentExecutable+"\")\n") sys.stdout.write(" Valid! (To run: \""+agentExecutable+"\")\n")
agents.append([name, agentExecutable, 0])
#Convert array of valid names into array of dictionaries containing information about each agent
#I'm starting to like python...
agents.append({"name":name, "path":agentExecutable,"score":[0], "totalScore":0, "VICTORY":[], "DEFEAT":[], "DRAW":[], "ILLEGAL":[], "INTERNAL_ERROR":[]})
if len(agents) == 0: if len(agents) == 0:
print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents." print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents."
sys.exit(0) sys.exit(0)
...@@ -113,37 +132,41 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -113,37 +132,41 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
aiErrors = 0 aiErrors = 0
managerErrors = 0 managerErrors = 0
#This double for loop simulates a round robin, with each agent getting the chance to play as both red and blue against every other agent. #This double for loop simulates a round robin, with each agent getting the chance to play as both red and blue against every other agent.
gameID = 0
for red in agents: #for each agent playing as red, for red in agents: #for each agent playing as red,
for blue in agents: #against each other agent, playing as blue for blue in agents: #against each other agent, playing as blue
if red == blue: if red == blue:
continue #Exclude battles against self continue #Exclude battles against self
gameID += 1
for i in range(1, nGames/2 + 1): for i in range(1, nGames/2 + 1):
#Play a game and read the result. Note the game is logged to a file based on the agent's names #Play a game and read the result. Note the game is logged to a file based on the agent's names
if verbose: if verbose:
sys.stdout.write("Agents: \""+red[0]+"\" and \""+blue[0]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ") sys.stdout.write("Agents: \""+red["name"]+"\" and \""+blue["name"]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ")
logFile = logDirectory + "round"+str(roundNumber) + "/"+red[0]+"_vs_"+blue[0]+"_"+str(i) logFile = logDirectory + "round"+str(roundNumber) + "/"+red["name"]+".vs."+blue["name"]+"."+str(i)
outline = os.popen(managerPath + " -o " + logFile + " " + red[1] + " " + blue[1], "r").read() outline = os.popen(managerPath + " -o " + logFile + " " + red["path"] + " " + blue["path"], "r").read()
results = outline.split(' ') results = outline.split(' ')
if len(results) != 6: if len(results) != 6:
if verbose: if verbose:
sys.stdout.write("Garbage output! \"" + outline + "\"\n") sys.stdout.write("Garbage output! \"" + outline + "\"\n")
red["manager_errors"].append((gameID, blue["name"]))
managerErrors += 1 managerErrors += 1
else: else:
if results[1] == "RED": if results[1] == "RED":
red[2] += scores[results[2]][0] endColour = red
blue[2] += scores[results[2]][1] otherColour = blue
normalGames += 1
elif results[1] == "BLUE": elif results[1] == "BLUE":
red[2] += scores[results[2]][1] endColour = blue
blue[2] += scores[results[2]][0] otherColour = red
normalGames += 1 if results[1] == "BOTH":
elif results[1] == "BOTH": pass
red[2] += scores[results[2]][0] else:
blue[2] += scores[results[2]][1] endColour["score"].insert(0,endColour["score"][0] + scores[results[2]][0])
red[2] += scores[results[2]][1] endColour[results[2]].append((otherColour["name"], gameID, scores[results[2]][0]))
blue[2] += scores[results[2]][0] otherColour["score"].insert(0, otherColour["score"][0] + scores[results[2]][1])
draws += 1 otherColour[scores[results[2]][2]].append((endColour["name"], gameID, scores[results[2]][1]))
if verbose: if verbose:
sys.stdout.write(" Result \"") sys.stdout.write(" Result \"")
for ii in range(1, len(results)): for ii in range(1, len(results)):
...@@ -151,12 +174,6 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -151,12 +174,6 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
if ii < (len(results) - 1): if ii < (len(results) - 1):
sys.stdout.write(" ") sys.stdout.write(" ")
sys.stdout.write("\"\n") sys.stdout.write("\"\n")
if verbose: if verbose:
print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. " print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. "
...@@ -170,11 +187,11 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -170,11 +187,11 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
if verbose: if verbose:
sys.stdout.write("Creating results files for ROUND " + str(roundNumber) + "... ") sys.stdout.write("Creating results files for ROUND " + str(roundNumber) + "... ")
agents.sort(key = lambda e : e[2], reverse=True) #Sort the agents based on score agents.sort(key = lambda e : e["score"], reverse=True) #Sort the agents based on score
resultsFile = open(resultsDirectory+"round"+str(roundNumber)+".results", "w") #Create a file to store all the scores for this round resultsFile = open(resultsDirectory+"round"+str(roundNumber)+".results", "w") #Create a file to store all the scores for this round
for agent in agents: for agent in agents:
resultsFile.write(agent[0] + " " + str(agent[2]) +"\n") #Write the agent names and scores into the file, in descending order resultsFile.write(agent["name"] + " " + str(agent["score"]) +"\n") #Write the agent names and scores into the file, in descending order
if verbose: if verbose:
sys.stdout.write(" Complete!\n") sys.stdout.write(" Complete!\n")
...@@ -188,14 +205,13 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -188,14 +205,13 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
for line in totalFile: #For all entries, for line in totalFile: #For all entries,
data = line.split(' ') data = line.split(' ')
for agent in agents: for agent in agents:
if agent[0] == data[0]: if agent["name"] == data[0]:
agent.append(agent[2]) #Store the score achieved this round at the end of the list agent["totalScore"] = int(data[1]) + agent["score"][0] #Simply increment the current score by the recorded total score of the matching file entry
agent[2] += int(data[1]) #Simply increment the current score by the recorded total score of the matching file entry
break break
totalFile.close() #Close the file, so we can delete it totalFile.close() #Close the file, so we can delete it
os.remove(resultsDirectory+"total.scores") #Delete the file os.remove(resultsDirectory+"total.scores") #Delete the file
#Sort the agents again #Sort the agents again
agents.sort(key = lambda e : e[2], reverse=True) agents.sort(key = lambda e : e["totalScore"], reverse=True)
else: else:
if verbose: if verbose:
...@@ -207,11 +223,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -207,11 +223,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
print "RESULTS FOR ROUND " + str(roundNumber) print "RESULTS FOR ROUND " + str(roundNumber)
print "Agent: [name, path, total_score, recent_score]"
totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file
for agent in agents: for agent in agents:
totalFile.write(agent[0] + " " + str(agent[2]) +"\n") #Write the total scores in descending order totalFile.write(agent["name"] + " " + str(agent["totalScore"]) +"\n") #Write the total scores in descending order
print "Agent: " + str(agent) print "Agent: " + str(agent)
...@@ -219,4 +234,11 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -219,4 +234,11 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
endTime = time() endTime = time()
print "Completed simulating " + str(nRounds) + " rounds in " + str(endTime - startTime) + " seconds." print "Completed simulating " + str(nRounds) + " rounds in " + str(endTime - startTime) + " seconds."
if makePrettyResults:
if verbose:
print "Now creating prettiful .html files..."
if verbose:
print "Done!"
sys.exit(0) sys.exit(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