Oh god, I was assuming scores were integers
[progcomp2012.git] / judge / simulator / simulate.py
index b84a525..7664a2c 100755 (executable)
@@ -10,6 +10,7 @@
 
        Now (sortof) generates .html files to display results in a prettiful manner.
        
+       THIS FILE IS TERRIBLE
 
  author Sam Moore (matches) [SZM]
  website http://matches.ucc.asn.au/stratego
@@ -27,6 +28,8 @@ 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
 
+timeoutValue = 2
+
 if len(sys.argv) >= 2:
        nRounds = int(sys.argv[1])
 if len(sys.argv) >= 3:
@@ -48,7 +51,7 @@ if len(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":(0.3,0.1, "DEFEAT"), "DEFEAT":(0.1,0.3, "VICTORY"), "SURRENDER":(0,0.3, "VICTORY"), "DRAW":(0.2,0.2, "DRAW"), "DRAW_DEFAULT":(0.1,0.1, "DRAW_DEFAULT"), "ILLEGAL":(-0.1,0.2, "DEFAULT"), "DEFAULT":(0.2,-0.1, "ILLEGAL"), "BOTH_ILLEGAL":(-0.1,-0.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 talking on irc...)
@@ -125,7 +128,7 @@ for name in agentNames:
                        break
        infoFile.close()
        
-       if os.path.exists(agentExecutable) == False:
+       if os.path.exists(agentExecutable.split(" ")[0]) == False:
                if verbose:
                        sys.stdout.write(" Invalid! (Path: \""+agentExecutable+"\" does not exist!)\n")
                continue
@@ -150,6 +153,26 @@ if verbose:
        print "Preparing .html results files..."
 
 
+if os.path.exists(resultsDirectory + "index.html") == True:
+       os.remove(resultsDirectory + "index.html") #Delete the file
+totalFile = open(resultsDirectory + "index.html", "w")
+totalFile.write("<html>\n<head>\n <title> Round in progress... </title>\n</head>\n<body>\n")
+if nRounds > 1:
+       totalFile.write("<h1> Rounds " + str(totalRounds) + " to " + str(totalRounds + nRounds-1) + " in progress...</h1>\n")
+else:
+       totalFile.write("<h1> Round " + str(totalRounds) + " in progress...</h1>\n")
+totalFile.write("<p> Please wait for the rounds to finish. You can view the current progress by watching the <a href = \"../log\"/>Log Files</a> </p>")
+if totalRounds > 1:
+       totalFile.write("<h2> Round Summaries </h2>\n")
+       totalFile.write("<table border=\"0\" cellpadding=\"10\">\n")
+       for i in range(1, totalRounds):
+               totalFile.write("<tr> <td> <a href=round"+str(i)+".html>Round " + str(i) + "</a> </td> </tr>\n")
+       totalFile.write("</table>\n")
+
+totalFile.write("</body>\n<!-- Total Results file autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
+totalFile.close()
+
+
 for agent in agents:
        if os.path.exists(resultsDirectory+agent["name"] + ".html") == False:
                agentFile = open(resultsDirectory+agent["name"] + ".html", "w")
@@ -171,19 +194,24 @@ for agent in agents:
        while line != "":
                #if verbose:
                #       print "Interpreting line \"" + line.strip() + "\""
-               if line.strip() == "</body>":
+               if line.strip() == "</body>" or line.strip() == "<!--end-->":
                        break
-               elif line == "<tr> <th> Score </th> <th> Wins </th> <th> Losses </th> <th> Draws </th> <th> Illegal </th> <th> Errors </th></tr>\n":
+               elif line == "<h3> Round Overview </h3>\n":
                        agentFile.write(line)
                        line = oldFile.readline()
-                       
-                       values = line.split(' ')
-                       agent["totalScore"] += int(values[2].strip())
-                       agent["Wins"] += int(values[5].strip())
-                       agent["Losses"] += int(values[8].strip())
-                       agent["Draws"] += int(values[11].strip())
-                       agent["Illegal"] += int(values[14].strip())
-                       agent["Errors"] += int(values[17].strip())
+                       agentFile.write(line)
+                       line = oldFile.readline()
+                       if line == "<tr> <th> Score </th> <th> Wins </th> <th> Losses </th> <th> Draws </th> <th> Illegal </th> <th> Errors </th></tr>\n":
+                               #sys.stdout.write("Adding scores... " + line + "\n")
+                               agentFile.write(line)
+                               line = oldFile.readline()
+                               values = line.split(' ')
+                               agent["totalScore"] += float(values[2].strip())
+                               agent["Wins"] += int(values[5].strip())
+                               agent["Losses"] += int(values[8].strip())
+                               agent["Draws"] += int(values[11].strip())
+                               agent["Illegal"] += int(values[14].strip())
+                               agent["Errors"] += int(values[17].strip())
                agentFile.write(line)
                line = oldFile.readline()
 
@@ -208,7 +236,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
 
        
        print "Commencing ROUND " + str(roundNumber) + " combat!"
-       print "Total: " + str(totalGames) + " games to be played. This could take a while... (Estimate 60s/game)"
+       print "Total: " + str(totalGames) + " games to be played. This could take a while..."
 
 
 
@@ -219,14 +247,24 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                for blue in agents: #against each other agent, playing as blue
                        if red == blue:
                                continue #Exclude battles against self
-                       gameNumber += 1
-                       gameID = str(roundNumber) + "." + str(gameNumber)
+                       
+                       
                        for i in range(1, nGames/2 + 1):
+                               gameNumber += 1
+                               gameID = str(roundNumber) + "." + str(gameNumber)
                                #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 (ID: " + gameID + ") ... ")
                                logFile = logDirectory + "round"+str(roundNumber) + "/"+red["name"]+".vs."+blue["name"]+"."+str(gameID)
-                               outline = os.popen(managerPath + " -o " + logFile + " " + red["path"] + " " + blue["path"], "r").read()
+                               errorLog = [logDirectory + "error/" + red["name"] + "."+str(gameID), logDirectory + "error/" + blue["name"] + "."+str(gameID)]
+                               #Run the game, outputting to logFile; stderr of (both) AI programs is directed to logFile.stderr
+                               outline = os.popen(managerPath + " -m 1000 -o " + logFile + " -T " + str(timeoutValue) + " \"" + red["path"] + "\" \"" + blue["path"] + "\" 2>> " + logFile+".stderr", "r").read()
+                               
+                               #os.system("mv tmp.mp4 " + logFile + ".mp4")
+                               
+                               #If there were no errors, get rid of the stderr file
+                               if os.stat(logFile+".stderr").st_size <= 0:
+                                       os.remove(logFile+".stderr")
                                results = outline.split(' ')
                        
                                if len(results) != 6:
@@ -264,6 +302,13 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                                                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))
+                                               #Write scores to raw text files
+                                               for agent in [endColour, otherColour]:
+                                                       scoreFile = open(resultsDirectory + agent["name"] + ".scores", "a")
+                                                       scoreFile.write(str(agent["totalScore"] + agent["score"][0]) + "\n")
+                                                       scoreFile.close()
+                                               
+                                               
 
                                        
                                        if verbose:
@@ -282,54 +327,14 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
        if verbose:
                print "" 
        #We should now have complete score values.
-               
-       '''
-               Obselete, non prettified results
-       if verbose:
-               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
-       
-       resultsFile = open(resultsDirectory+"round"+str(roundNumber)+".results", "w") #Create a file to store all the scores for this round
-       for agent in agents:
-               resultsFile.write(agent["name"] + " " + str(agent["score"]) +"\n") #Write the agent names and scores into the file, in descending order
-
-       if verbose:
-               sys.stdout.write(" Complete!\n")
-               sys.stdout.write("Updating total scores... ");
-       
-       #Now update the total scores
-       if os.path.exists(resultsDirectory+"total.scores"):
-               if verbose:
-                       sys.stdout.write(" Reading from \""+resultsDirectory+"total.scores\" to update scores... ")
-               totalFile = open(resultsDirectory+"total.scores", "r") #Try to open the total.scores file
-               for line in totalFile: #For all entries, 
-                       data = line.split(' ')
-                       for agent in agents:
-                               if agent["name"] == data[0]:
-                                       agent["totalScore"] = int(data[1]) + agent["score"][0] #Simply increment the current score by the recorded total score of the matching file entry
-                                       break
-               totalFile.close() #Close the file, so we can delete it
-               os.remove(resultsDirectory+"total.scores") #Delete the file
-               #Sort the agents again
-               agents.sort(key = lambda e : e["totalScore"], reverse=True)
-
-       else:
-               if verbose:
-                       sys.stdout.write(" First round - creating \""+resultsDirectory+"total.scores\"... ")
-       if verbose:
-               sys.stdout.write(" Complete!\n")
-               print "Finished writing results for ROUND " + str(roundNumber)
-               print ""
-       '''
        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
                #if verbose:
-                               print "Agent: " + str(agent)
+               #               print "Agent: " + str(agent)
        
 
        if verbose:
@@ -354,9 +359,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
 
                for index in range(0, len(agent["ALL"])):
                        if agent["ALL"][index][4] == "RED":
-                               logFile = logDirectory + "round"+str(roundNumber) + "/"+agent["name"]+".vs."+agent["ALL"][index][0]+"."+str(agent["ALL"][index][1])
+                               logFile = "../log/round"+str(roundNumber) + "/"+agent["name"]+".vs."+agent["ALL"][index][0]+"."+str(agent["ALL"][index][1])
                        else:
-                               logFile = logDirectory + "round"+str(roundNumber) + "/"+agent["ALL"][index][0]+".vs."+agent["name"]+"."+str(agent["ALL"][index][1])
+                               logFile = "../log/round"+str(roundNumber) + "/"+agent["ALL"][index][0]+".vs."+agent["name"]+"."+str(agent["ALL"][index][1])
                        agentFile.write("<tr> <td> <a href="+logFile+">" + str(agent["ALL"][index][1]) + " </a> </td> <td> <a href="+agent["ALL"][index][0]+".html>"+agent["ALL"][index][0] + " </a> </td> <td> " + agent["ALL"][index][4] + " </td> <td> " + agent["ALL"][index][3] + " </td> <td> " + str(agent["ALL"][index][2]) + "</td> <td> " + str(agent["score"][len(agent["score"])-index -2]) + " </td> </tr> </th>\n")
                agentFile.write("</table>\n")
                
@@ -375,6 +380,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                agentFile.write("</table>\n")
 
 
+               
+
+
                agentFile.close()       
 
        #Update round file
@@ -387,7 +395,31 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
        for agent in agents:
                roundFile.write("<tr> <td> <a href="+agent["name"]+".html>"+agent["name"] + " </a> </td> <td> " + str(agent["score"][0]) + " </td> <td> " + str(agent["totalScore"]) + " </td> </tr>\n")
        roundFile.write("</table>\n")
-       roundFile.write("<p> <a href=total.html>Current Scoreboard</a></p>\n")
+
+       command = "cp scores.plt " + resultsDirectory + "scores.plt;"
+       os.system(command)
+
+       scorePlot = open(resultsDirectory + "scores.plt", "a")
+       scorePlot.write("plot ")
+       for i in range(0, len(agents)):
+               if i > 0:
+                       scorePlot.write(", ")
+               scorePlot.write("\""+agents[i]["name"]+".scores\" using ($0+1):1 with linespoints title \""+agents[i]["name"]+"\"")
+
+       scorePlot.write("\nexit\n")
+       scorePlot.close()
+
+       command = "d=$(pwd); cd " + resultsDirectory + ";"
+       command += "gnuplot scores.plt;"
+       command += "rm -f scores.plt;"
+       command += "mv scores.png round"+str(roundNumber)+".png;"
+       command += "cd $d;"
+       os.system(command)
+
+       roundFile.write("<h2> Accumulated Scores - up to Round " + str(roundNumber)+" </h2>\n")
+       roundFile.write("<img src=\"round"+str(roundNumber)+".png\" alt = \"round"+str(roundNumber)+".png\" title = \"round"+str(roundNumber)+".png\" width = \"640\" height = \"480\"/>\n")
+
+       roundFile.write("<p> <a href=index.html>Current Scoreboard</a></p>\n")
        roundFile.write("</body>\n<!-- Results file for Round " + str(roundNumber) + " autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
        roundFile.close()
 
@@ -399,16 +431,32 @@ if verbose:
        print "Finalising .html files... "
 for agent in agents:
        agentFile = open(resultsDirectory + agent["name"]+".html", "a")
-
-       #Write the "total" statistics
+       agentFile.write("<!--end-->\n")
+       #Write a graph
+       #Comment out if you don't have gnuplot
+
+       command  = "rm -f " + agent["name"] + ".png;"
+       command += "cp template.plt " + resultsDirectory + agent["name"] + ".plt;"
+       command += "d=$(pwd); cd " + resultsDirectory + ";"
+       command += "sed -i \"s:\[NAME\]:"+agent["name"]+":g\" " +resultsDirectory + agent["name"]+".plt;"
+       command += "gnuplot " + resultsDirectory + agent["name"]+".plt;"
+       command += "rm -f " + resultsDirectory + agent["name"] + ".plt;"
+       command += "cd $d;"
+       os.system(command)
+       agentFile.write("<!--end-->\n")
+       agentFile.write("<h3> Score Graph </h3>\n")
+       agentFile.write("<img src=\""+agent["name"]+".png\" alt=\""+agent["name"]+".png\" title=\""+agent["name"]+".png\" width=\"640\" height=\"480\"/>\n")
+
+       #Link to main file
+       agentFile.write("<p> <a href=\"index.html\"/>Total Statistics</a> </p>\n")
 
        agentFile.write("</body>\n<!-- Results file for \"" + agent["name"] + "\" autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
        agentFile.close()
 
-       if os.path.exists(resultsDirectory + "total.html") == True:
-               os.remove(resultsDirectory + "total.html") #Delete the file
+if os.path.exists(resultsDirectory + "index.html") == True:
+       os.remove(resultsDirectory + "index.html") #Delete the file
 
-totalFile = open(resultsDirectory + "total.html", "w")
+totalFile = open(resultsDirectory + "index.html", "w")
 totalFile.write("<html>\n<head>\n <title> Total Overview </title>\n</head>\n<body>\n")
 totalFile.write("<h1> Total Overview </h1>\n")
 totalFile.write("<table border=\"0\" cellpadding=\"10\">\n")
@@ -418,6 +466,19 @@ for agent in agents:
        totalFile.write("<tr> <td> <a href="+agent["name"]+".html>"+agent["name"] + " </a> </td> <td> " + str(agent["totalScore"]) + " </td> </tr>\n")
 totalFile.write("</table>\n")
 
+totalFile.write("<h2> Score Graph </h2>\n")
+
+
+command = "d=$(pwd);"
+command += "cd " + resultsDirectory + ";"
+command += "rm -f scores.png;"
+command += "cp round"+str(roundNumber)+".png scores.png;"
+command += "cd $d;"
+os.system(command)
+
+totalFile.write("<img src=\"scores.png\" alt=\"scores.png\" title=\"scores.png\" width=\"640\" height=\"480\"/>\n")
+
+
 totalFile.write("<h2> Round Summaries </h2>\n")
 totalFile.write("<table border=\"0\" cellpadding=\"10\">\n")
 for i in range(1, totalRounds+1):
@@ -427,6 +488,11 @@ totalFile.write("</table>\n")
 totalFile.write("</body>\n<!-- Total Results file autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
 totalFile.close()
 
+#Write results to a raw text file as well
+textResults = open(resultsDirectory + "total.txt", "w")
+for agent in agents:
+       textResults.write(agent["name"] + " " + str(agent["totalScore"]) + "\n")
+textResults.close()
        
 if verbose:
        print "Done!"

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