From fe470c015d73d07c44f0e951a2bb205d95763f22 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Tue, 6 Dec 2011 02:59:51 +0800 Subject: [PATCH] Wrote python script to simulate a round simulate.py identifies agents, pits them against each other, and keeps track of scores using files. Needs the "info" files in AI directories to determine what file to execute. Spent a lot of time learning/failing at setting up vm on clownfish, called mufasa. Will finish setting up vm later. --- samples/asmodeus/info | 1 + samples/dummy/info | 1 + samples/forfax/info | 1 + simulator/simulate.py | 182 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 185 insertions(+) create mode 100644 samples/asmodeus/info create mode 100644 samples/dummy/info create mode 100644 samples/forfax/info create mode 100755 simulator/simulate.py diff --git a/samples/asmodeus/info b/samples/asmodeus/info new file mode 100644 index 0000000..da91d83 --- /dev/null +++ b/samples/asmodeus/info @@ -0,0 +1 @@ +asmodeus.py diff --git a/samples/dummy/info b/samples/dummy/info new file mode 100644 index 0000000..421376d --- /dev/null +++ b/samples/dummy/info @@ -0,0 +1 @@ +dummy diff --git a/samples/forfax/info b/samples/forfax/info new file mode 100644 index 0000000..8861587 --- /dev/null +++ b/samples/forfax/info @@ -0,0 +1 @@ +forfax diff --git a/simulator/simulate.py b/simulator/simulate.py new file mode 100755 index 0000000..5531143 --- /dev/null +++ b/simulator/simulate.py @@ -0,0 +1,182 @@ +#!/usr/bin/python -u + +''' + simulate.py - simulation script for the 2012 UCC Programming Competition + NOTE: This is not the manager program for a stratego game + It merely calls the manager program as appropriate, and records results + 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. + + + author Sam Moore (matches) [SZM] + website http://matches.ucc.asn.au/stratego + email progcomp@ucc.asn.au or matches@ucc.asn.au + git git.ucc.asn.au/progcomp2012.git +''' + +import os +import sys + +baseDirectory = "/home/sam/Documents/progcomp2012/" +resultsDirectory = baseDirectory+"results/" #Where results will go (results are in the form of text files of agent names and scores) +agentsDirectory = baseDirectory+"samples/" #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+"manager/stratego" #Path to the manager program + + +scores = {"WIN":3, "DRAW":2, "LOSS":1, "NONE":0} #Score dictionary +#NONE occurs if both programs crash. If only one program crashes the result is reported as a win-loss + + + +#Make necessary directories +if os.path.exists(resultsDirectory) == False: + os.mkdir(resultsDirectory) #Make the results directory if it didn't exist +#Identify the round number by reading the results directory +roundNumber = len(os.listdir(resultsDirectory)) + 1 +if roundNumber > 1: + roundNumber -= 1 + +if os.path.exists(logDirectory) == False: + os.mkdir(logDirectory) #Make the log directory if it didn't exist + + + +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 "Simulating ROUND " +str(roundNumber) +print "Identifying possible agents in \""+agentsDirectory+"\"" + +#Get all agent names from agentsDirectory +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 + 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 + sys.stdout.write(" Invalid! (No \"info\" file found)\n") + continue + sys.stdout.write(" Valid!") + #sys.stdout.write("OK") + #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()) + agents.append([name, agentExecutable, 0]) + sys.stdout.write(" (Run program \""+agentExecutable+"\")\n") + +if len(agents) == 0: + print "Couldn't find any agents! Check paths (Edit this script) or generate \"info\" files for agents." + sys.exit(0) + +print "Total: " + str(len(agents)) + " valid agents found (From "+str(len(agentNames))+" possibilities)" + +print "" + +print "Commencing ROUND " + str(roundNumber) + " combat! ("+str(nGames)+" games per pairing)" +print "Points values are: "+str(scores) +print "" + +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. +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 + 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 + sys.stdout.write("Agents: \""+red[0]+"\" and \""+blue[0]+"\" playing game " + str(i) + "/"+str(nGames/2) + "... ") + logFile = logDirectory + "round"+str(roundNumber) + "/"+red[0]+"_vs_"+blue[0]+"_"+str(i) + outline = os.popen(managerPath + " -o " + logFile + " " + red[1] + " " + blue[1], "r").read() + results = outline.split(' ') + #Look at who won, and adjust scores based on that + if results[0] == "NONE": + red[2] += scores["NONE"] + blue[2] += scores["NONE"] + sys.stdout.write(" No contest. (Check AI for errors).\n") + aiErrors += 1 + elif results[0] == "DRAW": + red[2] += scores["DRAW"] + blue[2] += scores["DRAW"] + sys.stdout.write(" Draw.\n") + draws += 1 + elif results[0] == red[1]: + red[2] += scores["WIN"] + blue[2] += scores["LOSS"] + sys.stdout.write(" \""+red[0]+"\"\n") + normalGames += 1 + elif results[0] == blue[1]: + red[2] += scores["LOSS"] + blue[2] += scores["WIN"] + sys.stdout.write(" \""+blue[0]+"\"\n") + normalGames += 1 + else: + sys.stdout.write(" Garbage output! \""+outline+"\" (log file \""+logFile+"\")\n") + managerErrors += 1 + + +print "Completed combat. Total of " + str(normalGames + draws + aiErrors + managerErrors) + " games played. " +if managerErrors != 0: + print " WARNING: Recieved "+str(managerErrors)+" garbage outputs. Check the manager program." + +print "" +#We should now have complete score values. + + +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 + +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[0] + " " + str(agent[2]) +"\n") #Write the agent names and scores into the file, in descending order + +sys.stdout.write(" Complete!\n") + +sys.stdout.write("Updating total scores... "); + +#Now update the total scores +if os.path.exists(resultsDirectory+"total.scores"): + 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[0] == data[0]: + agent.append(agent[2]) #Store the score achieved this round at the end of the list + agent[2] += int(data[1]) #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[2], reverse=True) + +else: + sys.stdout.write(" First round - creating \""+resultsDirectory+"total.scores\"... ") +sys.stdout.write(" Complete!\n") + +print "Finished writing results for ROUND " + str(roundNumber) +print "" + +print "RESULTS FOR ROUND " + str(roundNumber) +print "Agent: [name, path, total_score, recent_score]" + +totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file +for agent in agents: + totalFile.write(agent[0] + " " + str(agent[2]) +"\n") #Write the total scores in descending order + print "Agent: " + str(agent) + + +#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. + -- 2.20.1