Commit baf69b8d authored by Sam Moore's avatar Sam Moore

Fixed bugs, minor changes

Fixed segfault in manager caused by attempt to print invalid setups to log
Fixed SIGPIPE in manager caused by attempt to message non-existant programs.

Although I previously fixed a similar SIGPIPE, It is also possible for a file to exist but not have executable permissions set.
Controllers set to use such files as executables were returning true for Valid(), but were in fact, not valid at all.

Use the access function (thanks stack overflow!) to check for executable permissions
and existence in Program::Program. If they aren't set, or file doesn't exist, set
pid to -1 which is an "invalid" controller.

Discovered python trick which allows me to get rid of stupid "run.py" files for the python AIs.

Modified the simulate script to take the number of rounds as an argument.
Also made its output slightly prettier.

Currently testing simulation of 10 rounds on my laptop at home.

"./simulate 10; shutdown -h -P now"

I hope it doesn't set the desk on fire while I'm asleep... :S

Oh, and the VM is finally setup, hooray!
parent 56b7e695
......@@ -77,5 +77,9 @@ class Asmodeus(BasicAI):
else:
return self.suicideScores[attacker.rank]
if __name__ == "__main__":
asmodeus = Asmodeus()
if asmodeus.Setup():
while asmodeus.MoveCycle():
pass
#!/usr/bin/python -u
from asmodeus import *
asmodeus = Asmodeus()
if asmodeus.Setup():
while asmodeus.MoveCycle():
pass
......@@ -287,8 +287,9 @@ class BasicAI:
sys.stderr.write(str(self.board[x][y].rank));
sys.stderr.write("\n")
#basicAI = BasicAI()
#if basicAI.Setup():
# while basicAI.MoveCycle():
# pass
if __name__ == "__main__":
basicAI = BasicAI()
if basicAI.Setup():
while basicAI.MoveCycle():
pass
#!/usr/bin/python -u
from basic_python import *
basicAI = BasicAI()
if basicAI.Setup():
while basicAI.MoveCycle():
pass
......@@ -89,10 +89,14 @@ Piece::Colour Game::Setup(const char * redName, const char * blueName)
if (!red->Valid())
{
logMessage("Controller for Player RED is invalid!\n");
if (!red->HumanController())
logMessage("Check that program \"%s\" exists and has executable permissions set.\n", redName);
}
if (!blue->Valid())
{
logMessage("Controller for Player BLUE is invalid!\n");
if (!blue->HumanController())
logMessage("Check that program \"%s\" exists and has executable permissions set.\n", blueName);
}
if (!red->Valid())
{
......@@ -132,37 +136,57 @@ Piece::Colour Game::Setup(const char * redName, const char * blueName)
}
else
{
logMessage("Player RED gave an invalid setup!\n");
//logMessage("Player RED gave an invalid setup!\n");
result = Piece::RED;
}
}
else if (blueSetup != MovementResult::OK)
{
logMessage("Player BLUE gave an invalid setup!\n");
//logMessage("Player BLUE gave an invalid setup!\n");
result = Piece::BLUE;
}
logMessage("%s RED SETUP\n", red->name.c_str());
for (int y=0; y < 4; ++y)
if (redSetup == MovementResult::OK)
{
for (int x=0; x < theBoard.Width(); ++x)
for (int y=0; y < 4; ++y)
{
if (theBoard.GetPiece(x, y) != NULL)
logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
else
logMessage(".");
}
logMessage("\n");
}
for (int x=0; x < theBoard.Width(); ++x)
{
if (theBoard.GetPiece(x, y) != NULL)
logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
else
logMessage(".");
}
logMessage("\n");
}
}
else
{
logMessage("INVALID!\n");
}
logMessage("%s BLUE SETUP\n", blue->name.c_str());
for (int y=0; y < 4; ++y)
if (blueSetup == MovementResult::OK)
{
for (int y=0; y < 4; ++y)
{
for (int x=0; x < theBoard.Width(); ++x)
{
if (theBoard.GetPiece(x, theBoard.Height()-4+y) != NULL)
logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4+y)->type)]);
else
logMessage(".");
}
logMessage("\n");
}
}
else
{
for (int x=0; x < theBoard.Width(); ++x)
logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4 + y)->type)]);
logMessage("\n");
}
logMessage("INVALID!\n");
}
return result;
......
......@@ -253,7 +253,7 @@ void PrintResults(const MovementResult & result, string & buffer)
s << "DRAW_DEFAULT ";
break;
case MovementResult::BAD_SETUP:
s << "BOTH_ILLEGAL ";
s << "BAD_SETUP ";
break;
default:
s << "INTERNAL_ERROR ";
......
......@@ -22,13 +22,8 @@ using namespace std;
*/
Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0)
{
//See if file exists...
FILE * file = fopen(executablePath, "r");
if (file != NULL)
{
fclose(file);
}
else
//See if file exists and is executable...
if (access(executablePath, X_OK) != 0)
{
pid = -1;
return;
......@@ -55,10 +50,11 @@ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0
//If your wrapped program is not written in C/C++, you will probably have a problem
execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable
//fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
//exit(EXIT_FAILURE); //We will probably have to terminate the whole program if this happens
if (access(executablePath, X_OK) == 0) //Check we STILL have permissions to start the file
execl(executablePath, executablePath, (char*)(NULL)); ///Replace process with desired executable
fprintf(stderr, "Program::Program - Could not run program \"%s\"!\n", executablePath);
exit(EXIT_FAILURE); //We will probably have to terminate the whole program if this happens
}
else
{
......
......@@ -4,6 +4,7 @@
#include "thread_util.h"
#include <string>
#include <unistd.h> //Needed to check permissions
/**
* A wrapping class for an external program, which can exchange messages with the current process through stdin/stdout
......
......@@ -2,11 +2,11 @@
# Not used for building simulate.py
# Used for building/removing results
BASEDIR = /home/sam/Documents/progcomp2012/
RESULTSDIR = /home/sam/Documents/progcomp2012/results
LOGDIR = /home/sam/Documents/progcomp2012/log
AGENTSDIR = /home/sam/Documents/progcomp2012/samples
MANAGER = /home/sam/Documents/progcomp2012/manager/stratego
BASEDIR = /home/sam/Documents/progcomp2012/progcomp
RESULTSDIR = /home/sam/Documents/progcomp2012/progcomp/results
LOGDIR = /home/sam/Documents/progcomp2012/progcomp/log
AGENTSDIR = /home/sam/Documents/progcomp2012/progcomp/agents
MANAGER = /home/sam/Documents/progcomp2012/progcomp/judge/manager/stratego
......
......@@ -17,16 +17,27 @@
import os
import sys
from time import time
baseDirectory = "/home/sam/Documents/progcomp2012/"
baseDirectory = "/home/sam/Documents/progcomp2012/progcomp/"
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)
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+"manager/stratego" #Path to the manager program
managerPath = baseDirectory+"judge/manager/stratego" #Path to the manager program
nRounds = 1
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)} #Score dictionary
time()
if len(sys.argv) == 2:
nRounds = int(sys.argv[1])
elif len(sys.argv) != 1:
print "Useage: simulate.py [nRounds]"
sys.exit(1)
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 = True
......@@ -35,155 +46,177 @@ verbose = True
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
totalRounds = len(os.listdir(resultsDirectory)) + 1
if totalRounds > 1:
totalRounds -= 1
if os.path.exists(logDirectory) == False:
os.mkdir(logDirectory) #Make the log directory if it didn't exist
startTime = time()
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 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)+"\"... ")
if verbose:
sys.stdout.write("Scan \""+name+"\"... ")
if os.path.isdir(agentsDirectory+name) == False: #Remove non-directories
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)+"\"... ")
if verbose:
sys.stdout.write(" Invalid! (Not a directory)\n")
continue
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
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 verbose:
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])
if verbose:
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)
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... ("+str(nGames)+" games per pairing * " + str(len(agents) * len(agents)-1) + " pairings = " + str((len(agents) * len(agents)-1) * nGames) + " games)"
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
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("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(' ')
if len(results) != 6:
if verbose:
sys.stdout.write("Garbage output! " + outline)
else:
if results[1] == "RED":
red[2] += scores[results[2]][0]
blue[2] += scores[results[2]][1]
elif results[1] == "BLUE":
red[2] += scores[results[2]][1]
blue[2] += scores[results[2]][0]
elif results[1] == "BOTH":
red[2] += scores[results[2]][0]
blue[2] += scores[results[2]][1]
red[2] += scores[results[2]][1]
blue[2] += scores[results[2]][0]
sys.stdout.write(" Invalid! (No \"info\" file found)\n")
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())
if os.path.exists(agentExecutable) == False:
if verbose:
sys.stdout.write(" " + outline)
sys.stdout.write(" Invalid! (File \""+agentExecutable+"\" does not exist!)\n")
continue
if verbose:
sys.stdout.write(" Valid! (To run: \""+agentExecutable+"\")\n")
agents.append([name, agentExecutable, 0])
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... "
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
if verbose:
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(' ')
if len(results) != 6:
if verbose:
sys.stdout.write("Garbage output! \"" + outline + "\"\n")
managerErrors += 1
else:
if results[1] == "RED":
red[2] += scores[results[2]][0]
blue[2] += scores[results[2]][1]
normalGames += 1
elif results[1] == "BLUE":
red[2] += scores[results[2]][1]
blue[2] += scores[results[2]][0]
normalGames += 1
elif results[1] == "BOTH":
red[2] += scores[results[2]][0]
blue[2] += scores[results[2]][1]
red[2] += scores[results[2]][1]
blue[2] += scores[results[2]][0]
draws += 1
if verbose:
sys.stdout.write(" Result \"")
for ii in range(1, len(results)):
sys.stdout.write(results[ii].strip())
if ii < (len(results) - 1):
sys.stdout.write(" ")
sys.stdout.write("\"\n")
if verbose:
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."
if verbose:
print ""
#We should now have complete score values.
if verbose:
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
if verbose:
sys.stdout.write(" Complete!\n")
sys.stdout.write("Updating total scores... ");
if verbose:
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."
#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[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:
print ""
#We should now have complete score values.
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 ""
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
print "RESULTS FOR ROUND " + str(roundNumber)
print "Agent: [name, path, total_score, recent_score]"
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[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:
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 ""
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)
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.
#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."
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