diff --git a/progcomp/judge/simulator/simulate.py b/progcomp/judge/simulator/simulate.py index 269c8b88a244845437d85cf752ff096eeed4ba28..76ca0a56d11b23145250bb806a5a98d306aa8cd5 100755 --- a/progcomp/judge/simulator/simulate.py +++ b/progcomp/judge/simulator/simulate.py @@ -7,6 +7,8 @@ Plays exactly ONE round, but does not overwrite previously played rounds eg: run once to generate round1.results, twice to generate round2.results etc Also generates total.scores based on results from every round. + + Now (sortof) generates .html files to display results in a prettiful manner. author Sam Moore (matches) [SZM] @@ -49,9 +51,9 @@ if len(sys.argv) >= 5: 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")} -#Verbose - print lots of useless stuff about what you are doing (kind of like matches in irc...) +#Verbose - print lots of useless stuff about what you are doing (kind of like matches talking on irc...) verbose = True -makePrettyResults = False + #Check the manager program exists TODO: And is executable! @@ -74,74 +76,105 @@ if os.path.exists(logDirectory) == False: startTime = time() #Record time at which simulation starts -#Do each round... -for roundNumber in range(totalRounds, totalRounds + nRounds): - - if os.path.exists(logDirectory + "round"+str(roundNumber)) == False: - os.mkdir(logDirectory + "round"+str(roundNumber)) #Check there is a directory for this round's logs - +if verbose: + if nRounds > 1: + print "Simulating " + str(nRounds) + " rounds (" + str(totalRounds) + " to " + str(totalRounds + nRounds-1) + ")" + else: + print "Simulating one round." + print "" + print "Identifying possible agents in \""+agentsDirectory+"\"" + +#Get all agent names from agentsDirectory +#TODO: Move this part outside the loop? It only has to happen once +agentNames = os.listdir(agentsDirectory) +agents = [] +for name in agentNames: if verbose: - print "Simulating ROUND " +str(roundNumber) - print "Identifying possible agents in \""+agentsDirectory+"\"" - - #Get all agent names from agentsDirectory - #TODO: Move this part outside the loop? It only has to happen once - agentNames = os.listdir(agentsDirectory) - agents = [] - for name in agentNames: - #sys.stdout.write("\nLooking at Agent: \""+ str(name)+"\"... ") + sys.stdout.write("Scan \""+name+"\"... ") + if os.path.isdir(agentsDirectory+name) == False: #Remove non-directories if verbose: - sys.stdout.write("Scan \""+name+"\"... ") - if os.path.isdir(agentsDirectory+name) == False: #Remove non-directories - if verbose: - sys.stdout.write(" Invalid! (Not a directory)\n") - continue + sys.stdout.write(" Invalid! (Not a directory)\n") + continue - if os.path.exists(agentsDirectory+name+"/info") == False: #Try and find the special "info" file in each directory; ignore if it doesn't exist - if verbose: - sys.stdout.write(" Invalid! (No \"info\" file found)\n") - continue + if os.path.exists(agentsDirectory+name+"/info") == False: #Try and find the special "info" file in each directory; ignore if it doesn't exist + if verbose: + sys.stdout.write(" Invalid! (No \"info\" file found)\n") + continue + 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 verbose: - sys.stdout.write(" Invalid! (File \""+agentExecutable+"\" does not exist!)\n") - continue + if os.path.exists(agentExecutable) == False: + if verbose: + sys.stdout.write(" Invalid! (Path: \""+agentExecutable+"\" does not exist!)\n") + continue - if verbose: - sys.stdout.write(" Valid! (To run: \""+agentExecutable+"\")\n") - - #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: - print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents." - sys.exit(0) if verbose: - print "Total: " + str(len(agents)) + " valid agents found (From "+str(len(agentNames))+" possibilities)" - print "" - print "Commencing ROUND " + str(roundNumber) + " combat! This could take a while... " + sys.stdout.write(" Valid! (Path: \""+agentExecutable+"\")\n") + + #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":[], "ALL":[]}) + +if len(agents) == 0: + print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents." + sys.exit(0) +if verbose: + print "Total: " + str(len(agents)) + " valid agents found (From "+str(len(agentNames))+" possibilities)" + print "" + +#Prepare the pretty .html files if they don't exist +htmlDir = resultsDirectory + "pretty/" +if os.path.exists(htmlDir) == False: + os.mkdir(htmlDir) +if os.path.exists(htmlDir) == False: + print "Couldn't create directory \""+htmlDir+"\"." + sys.exit(1) + +for agent in agents: + if os.path.exists(htmlDir+agent["name"] + ".html") == False: + agentFile = open(htmlDir+agent["name"] + ".html", "w") + agentFile.write("\n\n " + agent["name"] + " results\n\n\n

Results for " + agent["name"]+"

\n\n\n") + agentFile.close() + + os.rename(htmlDir+agent["name"] + ".html", "tmpfile") + + oldFile = open("tmpfile") + agentFile = open(htmlDir+agent["name"] + ".html", "w") + for line in oldFile: + if line.strip() == "": + break + agentFile.write(line + "\n") + oldFile.close() + agentFile.close() + os.remove("tmpfile") + +#Do each round... +totalGames = nGames/2 * len(agents) * (len(agents)-1) +for roundNumber in range(totalRounds, totalRounds + nRounds): + + if os.path.exists(logDirectory + "round"+str(roundNumber)) == False: + os.mkdir(logDirectory + "round"+str(roundNumber)) #Check there is a directory for this round's logs + + + print "Commencing ROUND " + str(roundNumber) + " combat!" + print "Total: " + str(totalGames) + " games to be played. This could take a while... (Estimate 60s/game)" + - normalGames = 0 - draws = 0 - aiErrors = 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. - gameID = 0 + gameNumber = 0 for red in agents: #for each agent playing as red, for blue in agents: #against each other agent, playing as blue if red == blue: continue #Exclude battles against self - gameID += 1 + gameNumber += 1 + gameID = str(roundNumber) + "." + str(gameNumber) 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 if verbose: - sys.stdout.write("Agents: \""+red["name"]+"\" and \""+blue["name"]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ") + sys.stdout.write("Agents: \""+red["name"]+"\" and \""+blue["name"]+"\" playing game (ID: " + gameID + ") ... ") logFile = logDirectory + "round"+str(roundNumber) + "/"+red["name"]+".vs."+blue["name"]+"."+str(i) outline = os.popen(managerPath + " -o " + logFile + " " + red["path"] + " " + blue["path"], "r").read() results = outline.split(' ') @@ -149,24 +182,40 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): if len(results) != 6: if verbose: sys.stdout.write("Garbage output! \"" + outline + "\"\n") - red["manager_errors"].append((gameID, blue["name"])) + red["INTERNAL_ERROR"].append((blue["name"], gameID, scores["INTERNAL_ERROR"][0])) + blue["INTERNAL_ERROR"].append((red["name"], gameID, scores["INTERNAL_ERROR"][0])) + red["ALL"].append((blue["name"], gameID, scores["INTERNAL_ERROR"][0], "INTERNAL_ERROR")) + blue["ALL"].append((red["name"], gameID, scores["INTERNAL_ERROR"][0], "INTERNAL_ERROR")) managerErrors += 1 else: if results[1] == "RED": endColour = red otherColour = blue + endStr = "RED" + otherStr = "BLUE" elif results[1] == "BLUE": endColour = blue otherColour = red + endStr = "BLUE" + otherStr = "RED" + + if results[1] == "BOTH": - pass + red["INTERNAL_ERROR"].append((blue["name"], gameID, scores["INTERNAL_ERROR"][0])) + blue["INTERNAL_ERROR"].append((red["name"], gameID, scores["INTERNAL_ERROR"][0])) + red["ALL"].append((blue["name"], gameID, scores["INTERNAL_ERROR"][0], "INTERNAL_ERROR", "RED")) + blue["ALL"].append((red["name"], gameID, scores["INTERNAL_ERROR"][0], "INTERNAL_ERROR", "BLUE")) + managerErrors += 1 else: endColour["score"].insert(0,endColour["score"][0] + scores[results[2]][0]) endColour[results[2]].append((otherColour["name"], gameID, scores[results[2]][0])) + endColour["ALL"].append((otherColour["name"], gameID, scores[results[2]][0], results[2], endStr)) otherColour["score"].insert(0, otherColour["score"][0] + scores[results[2]][1]) otherColour[scores[results[2]][2]].append((endColour["name"], gameID, scores[results[2]][1])) + otherColour["ALL"].append((endColour["name"], gameID, scores[results[2]][1], scores[results[2]][2], otherStr)) + if verbose: sys.stdout.write(" Result \"") for ii in range(1, len(results)): @@ -176,16 +225,16 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): sys.stdout.write("\"\n") if verbose: - print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. " + print "Completed combat. Total of " + str(gameNumber) + " games played. " if managerErrors != 0: - print "WARNING: Recieved "+str(managerErrors)+" garbage outputs. Check the manager program." + print "WARNING: Registered "+str(managerErrors)+" errors. Check the manager program." if verbose: print "" #We should now have complete score values. if verbose: - sys.stdout.write("Creating results files for ROUND " + str(roundNumber) + "... ") + sys.stdout.write("Creating raw results files for ROUND " + str(roundNumber) + "... ") agents.sort(key = lambda e : e["score"], reverse=True) #Sort the agents based on score @@ -221,24 +270,51 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): print "Finished writing results for ROUND " + str(roundNumber) print "" - - print "RESULTS FOR ROUND " + str(roundNumber) + if verbose: + print "RESULTS FOR ROUND " + str(roundNumber) totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file - for agent in agents: + for agent in agents: totalFile.write(agent["name"] + " " + str(agent["totalScore"]) +"\n") #Write the total scores in descending order - print "Agent: " + str(agent) + if verbose: + print "Agent: " + str(agent) + if verbose: + print "Updating pretty .html files... " - #I just want to say the even though I still think python is evil, it is much better than bash. Using bash makes me cry. -endTime = time() -print "Completed simulating " + str(nRounds) + " rounds in " + str(endTime - startTime) + " seconds." -if makePrettyResults: - if verbose: - print "Now creating prettiful .html files..." + for agent in agents: + agentFile = open(htmlDir + agent["name"]+".html", "a") + agentFile.write("

Round " + str(roundNumber) + "

\n") + agentFile.write("

Summary

\n") + agentFile.write("\n") + agentFile.write("\n") + agentFile.write("\n") + + agentFile.write("
Score Wins Losses Draws Illegal Errors
"+str(agent["score"][0])+" "+str(len(agent["VICTORY"]))+" "+str(len(agent["DEFEAT"]))+" "+str(len(agent["DRAW"]))+" "+str(len(agent["ILLEGAL"]))+" " +str(len(agent["INTERNAL_ERROR"]))+"
\n") + + agentFile.write("

Detailed

\n") + agentFile.write("\n") + agentFile.write("\n") + + for index in range(0, len(agent["ALL"])): + agentFile.write("\n") + agentFile.write("
Game ID Opponent Played as Outcome Score Accumulated Score
" + str(agent["ALL"][index][1]) + " "+agent["ALL"][index][0] + " " + agent["ALL"][index][4] + " " + agent["ALL"][index][3] + " " + str(agent["ALL"][index][2]) + " " + str(agent["score"][len(agent["score"])-index -2]) + "
\n") + agentFile.close() + + +if verbose: + print "Finalising .html files... " +for agent in agents: + agentFile = open(htmlDir + agent["name"]+".html", "a") + agentFile.write("\n\n\n\n") + agentFile.close() + if verbose: print "Done!" + +endTime = time() +print "Completed simulating " + str(nRounds) + " rounds in " + str(endTime - startTime) + " seconds." sys.exit(0)