Added image output to manager, added plots to results pages
[progcomp2012.git] / judge / simulator / simulate.py
index aead755..217a80e 100755 (executable)
@@ -10,6 +10,7 @@
 
        Now (sortof) generates .html files to display results in a prettiful manner.
        
 
        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
 
  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
 
 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:
 if len(sys.argv) >= 2:
        nRounds = int(sys.argv[1])
 if len(sys.argv) >= 3:
@@ -125,7 +128,7 @@ for name in agentNames:
                        break
        infoFile.close()
        
                        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
                if verbose:
                        sys.stdout.write(" Invalid! (Path: \""+agentExecutable+"\" does not exist!)\n")
                continue
@@ -150,6 +153,26 @@ if verbose:
        print "Preparing .html results files..."
 
 
        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")
 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() + "\""
        while line != "":
                #if verbose:
                #       print "Interpreting line \"" + line.strip() + "\""
-               if line.strip() == "</body>":
+               if line.strip() == "</body>" or line.strip() == "<!--end-->":
                        break
                        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()
                        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"] += 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()
 
                agentFile.write(line)
                line = oldFile.readline()
 
@@ -208,7 +236,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
 
        
        print "Commencing ROUND " + str(roundNumber) + " combat!"
 
        
        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,23 @@ 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
                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):
                        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)
                                #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 + " -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:
                                results = outline.split(' ')
                        
                                if len(results) != 6:
@@ -234,8 +271,8 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                                                sys.stdout.write("Garbage output! \"" + outline + "\"\n")
                                        red["INTERNAL_ERROR"].append((blue["name"], gameID, scores["INTERNAL_ERROR"][0]))
                                        blue["INTERNAL_ERROR"].append((red["name"], gameID, scores["INTERNAL_ERROR"][0]))
                                                sys.stdout.write("Garbage output! \"" + outline + "\"\n")
                                        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"))
+                                       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:
 
                                        managerErrors += 1
                                else:
 
@@ -264,6 +301,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))
                                                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:
 
                                        
                                        if verbose:
@@ -282,54 +326,14 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
        if verbose:
                print "" 
        #We should now have complete score values.
        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
        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:
                #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:
        
 
        if verbose:
@@ -354,9 +358,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
 
                for index in range(0, len(agent["ALL"])):
                        if agent["ALL"][index][4] == "RED":
 
                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:
                        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")
                
                        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 +379,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                agentFile.write("</table>\n")
 
 
                agentFile.write("</table>\n")
 
 
+               
+
+
                agentFile.close()       
 
        #Update round file
                agentFile.close()       
 
        #Update round file
@@ -387,7 +394,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")
        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()
 
        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 +430,32 @@ if verbose:
        print "Finalising .html files... "
 for agent in agents:
        agentFile = open(resultsDirectory + agent["name"]+".html", "a")
        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()
 
 
        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")
 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 +465,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("<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):
 totalFile.write("<h2> Round Summaries </h2>\n")
 totalFile.write("<table border=\"0\" cellpadding=\"10\">\n")
 for i in range(1, totalRounds+1):
@@ -427,6 +487,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()
 
 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!"
        
 if verbose:
        print "Done!"

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