Commit 345d8b1f authored by Sam Moore's avatar Sam Moore

Small changes to several things

Changed combat outcomes for equivelant ranks:
Up until now, victor was randomly chosen
Changed so that result is always "BOTHDIE"

Updated manual page for manager
Added section on unbuffered stdin/stdout

Modified sample agents to take into account MULTIPLIER
There is no way for a human player to move the scout multiple spaces yet.
Sample agents still play each other fine, but since none of them actually move scouts multiple spaces,
this doesn't prove the new code works.
TODO: Test properly (add scout movement to asmodeus and see if everything still works?)

Updated webpage.
Added section on unbuffered stdin/stdout
Added some other pointless waffle. Mmmm waffle.

TODO:
Make simulate.py keep track of the round number properly.
I'm sure this is simple to do, but I can't be bothered right now.
parent 47b6dbf9
......@@ -333,9 +333,21 @@ bool BasicAI::InterpretResult()
Direction dir = Helper::StrToDir(tokens[2]);
string & outcome = tokens[3];
int x2 = x; int y2 = y; Helper::MoveInDirection(x2,y2,dir);
//We might want to actually check for the multiplier in the sample agents! 20/12/11
unsigned int outIndex = 3;
int multiplier = atoi(tokens[outIndex].c_str());
if (multiplier == 0)
multiplier = 1;
else
outIndex += 1;
string & outcome = tokens[outIndex];
int x2 = x; int y2 = y; Helper::MoveInDirection(x2,y2,dir, multiplier);
Piece * attacker = board->Get(x,y);
if (attacker == NULL)
......@@ -357,12 +369,14 @@ bool BasicAI::InterpretResult()
//cerr << "No defender!\n";
return false;
}
if (tokens.size() < outIndex+2)
return false;
board->Set(x2,y2, attacker);
board->Set(x,y,NULL);
attacker->x = x2; attacker->y = y2;
attacker->rank = Piece::GetRank(tokens[4][0]);
attacker->rank = Piece::GetRank(tokens[outIndex+1][0]);
ForgetUnit(defender);
}
else if (outcome == "DIES")
......@@ -372,10 +386,12 @@ bool BasicAI::InterpretResult()
//cerr << "No defender!\n";
return false;
}
if (tokens.size() < outIndex+3)
return false;
board->Set(x,y,NULL);
defender->rank = Piece::GetRank(tokens[5][0]);
defender->rank = Piece::GetRank(tokens[outIndex+2][0]);
ForgetUnit(attacker);
......
......@@ -20,7 +20,15 @@ import random
ranks = ['B','1','2','3','4','5','6','7','8','9','s','F', '?', '+']
def move(x, y, direction):
def is_integer(s):
""" Using exceptions for this feels... wrong..."""
try:
int(s)
return True
except ValueError:
return False
def move(x, y, direction, multiplier):
""" Moves point (x,y) in direction, returns a pair """
if direction == "UP":
return (x,y-1)
......@@ -203,9 +211,16 @@ class BasicAI:
#sys.stderr.write(" Board position " + str(x) + " " + str(y) + " is OK!\n")
direction = result[2].strip()
multiplier = 1
outcome = result[3].strip()
outIndex = 3
if is_integer(outcome):
multiplier = int(outcome)
outcome = result[4].strip()
outIndex = 4
p = move(x,y,direction)
p = move(x,y,direction, multiplier)
......@@ -229,7 +244,7 @@ class BasicAI:
self.board[p[0]][p[1]] = self.board[x][y]
self.board[x][y].rank = result[4].strip()
self.board[x][y].rank = result[outIndex+1].strip()
self.board[x][y] = None
......@@ -242,7 +257,7 @@ class BasicAI:
elif self.board[x][y].colour == oppositeColour(self.colour):
self.enemyUnits.remove(self.board[x][y])
self.board[p[0]][p[1]].rank = result[5].strip()
self.board[p[0]][p[1]].rank = result[outIndex+2].strip()
self.board[x][y] = None
elif outcome == "BOTHDIE":
if self.board[p[0]][p[1]] == None:
......
......@@ -20,9 +20,19 @@ DESCRIPTION
NOTES
1. There is no plan to support AI programs named "human". Deal with it.
2. The graphical interface for human players is... basic. Deal with it.
blue_player
As red_player, except for controlling the Blue player.
A WARNING ABOUT BUFFERING
The AI programs must unbuffer their stdin and stdout streams, otherwise it will be seen to be non-responsive.
If you C and you know a way to force the process started by exec() to have unbuffered stdin/stdout, please email the author.
In C or C++, unbuffering is accomplished with the following lines, which should appear near the start of main()
setbuf(stdin, NULL);
setbuf(stdout, NULL);
In python, unbuffering is accomplished by passing the -u switch to the interpreter, ie: The first line of a script reads:
#!/usr/bin/python -u
OPTIONS
-g
......@@ -74,7 +84,7 @@ OPTIONS
GAME RULES
Each player controls up to 40 pieces on the Board. The pieces consist of the following:
Each player controls up to 40 pieces on the Board. The pieces are represented by the following characters:
Piece Name Rank Number Abilities
1 Marshal 1 1 Dies if attacked by Spy
......@@ -205,11 +215,7 @@ EXIT/OUTPUT
If possible, stratego will print the message "QUIT" to both AI programs, and they should exit as soon as possible.
BUGS
WARNING:
stratego has been observed to segfault occassionally after the end of a game. It is not yet known what is causing these errors.
They appear to occur most often when the result is a draw, however they have been observed to occur under all exit conditions except the Illegal case. The result is still printed to stdout. However this bug _must_ be fixed before stratego can be used by simulation scripts.
BUGS
stratego is still a work in progress. Report another bug to the AUTHOR (see below).
AUTHORS
......@@ -227,4 +233,7 @@ NOTES
3. IRC Channel
irc://irc.ucc.asn.au #progcomp
THIS PAGE LAST UPDATED
20/12/11 by Sam Moore
......@@ -200,7 +200,9 @@ void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal)
/**
* Draw the board state to graphics
* @param reveal - Pieces matching this colour will be revealed. All others will be shown as blank coloured squares.
* @param reveal - Pieces matching this colour will be revealed. If Piece::BOTH, all pieces will be revealed
* @param showRevealed - If true, then all pieces that have taken part in combat will be revealed, regardless of colour.
* If false, only pieces matching the colour reveal will be revealed
*/
void Board::Draw(const Piece::Colour & reveal, bool showRevealed)
{
......@@ -291,12 +293,12 @@ Piece * Board::GetPiece(int x, int y)
}
/**
* Moves a piece at a specified position in the specified direction, handles combat if necessary
* Moves a piece at a specified position in the specified direction, handles combat if necessary, updates state of the board
* @param x - x-coord of the piece
* @param y - y-coord of the piece
* @param direction - Direction in which to move (UP, DOWN, LEFT or RIGHT)
* @param colour - Colour which the piece must match for the move to be valid
* @returns A MovementResult which indicates the result of the move - OK is good, VICTORY means that a flag was captured, anything else is an error
* @returns A MovementResult which indicates the result of the move
*/
MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour)
{
......@@ -413,13 +415,15 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
board[x2][y2] = target;
return MovementResult(MovementResult::KILLS, attackerType, defenderType);
}
else if (target->operator==(*defender) && rand() % 2 == 0)
else if (target->operator==(*defender))// && rand() % 2 == 0)
{
RemovePiece(defender);
RemovePiece(target);
delete defender;
delete target;
board[x][y] = NULL;
board[x2][y2] = target;
return MovementResult(MovementResult::KILLS, attackerType, defenderType);
board[x2][y2] = NULL;
return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType);
}
else
{
......
......@@ -65,10 +65,16 @@ if os.path.exists(managerPath) == False:
if os.path.exists(resultsDirectory) == False:
os.mkdir(resultsDirectory) #Make the results directory if it didn't exist
'''
Obselete older version doesn't work with new .html files
#Identify the round number by reading the results directory
totalRounds = len(os.listdir(resultsDirectory)) + 1
if totalRounds > 1:
totalRounds -= 1
'''
totalRounds = 1
#TODO: Fix this bit!
if os.path.exists(logDirectory) == False:
os.mkdir(logDirectory) #Make the log directory if it didn't exist
......@@ -179,7 +185,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
os.mkdir(logDirectory + "round"+str(roundNumber)) #Check there is a directory for this round's logs
for agent in agents:
agent.update({"name":agent["name"], "path":agent["path"], "score":[0], "VICTORY":[], "DEFEAT":[], "DRAW":[], "ILLEGAL":[], "DEFAULT":[], "INTERNAL_ERROR":[], "SURRENDER":[], "DRAW_DEFAULT":[], "BOTH_ILLEGAL":[], "BAD_SETUP":[], "ALL":[], "totalScore":0, "Wins":0, "Losses":0, "Draws":0, "Illegal":0, "Errors":0})
agent.update({"name":agent["name"], "path":agent["path"], "score":[0], "VICTORY":[], "DEFEAT":[], "DRAW":[], "ILLEGAL":[], "DEFAULT":[], "INTERNAL_ERROR":[], "SURRENDER":[], "DRAW_DEFAULT":[], "BOTH_ILLEGAL":[], "BAD_SETUP":[], "ALL":[]})
print "Commencing ROUND " + str(roundNumber) + " combat!"
......@@ -343,7 +349,20 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
agentFile.write("</table>\n")
agentFile.close()
#Update round file
roundFile = open(htmlDir + "round"+str(roundNumber)+".html", "w")
roundFile.write("<html>\n<head>\n <title> Round " +str(roundNumber)+ " Overview </title>\n</head>\n<body>\n")
roundFile.write("<h1> Round " +str(roundNumber)+ " Overview </h1>\n")
roundFile.write("<table border=\"0\" cellpadding=\"10\">\n")
roundFile.write("<tr> <th> Name </th> <th> Score </th> <th> Total Score </th> </tr>\n")
agents.sort(key = lambda e : e["score"][0], reverse=True)
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</body>\n<!-- Results file for Round " + str(roundNumber) + " autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
roundFile.close()
if verbose:
......@@ -356,6 +375,20 @@ for agent in agents:
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(htmlDir + "total.html") == True:
os.remove(htmlDir + "total.html") #Delete the file
totalFile = open(htmlDir + "total.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("<tr> <th> Name </th> <th> Total Score </th> </tr>\n")
agents.sort(key = lambda e : e["totalScore"], reverse=True)
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</body>\n<!-- Total Results file autogenerated by \"" + sys.argv[0] + "\" at time " + str(time()) + " -->\n</html>\n\n")
totalFile.close()
if verbose:
print "Done!"
......
......@@ -45,6 +45,8 @@
<p> <b> Warning:</b> The accuracy of the above file depends on how recently I pulled it from git. To ensure you get the latest version, find it under "manager/manual.txt" in the <a href="http://git.ucc.asn.au/?p=progcomp2012.git;a=summary"/>git repository</a> </p>
<p> <b> Another Warning:</b> AI programs <b>must</b> unbuffer stdin and stdout themselves. This is explained in the manual page, but I figured no one would read it. It is fairly simple to unbuffer stdin/stdout in C/C++ and python, I have not investigated other languages yet. </p>
<h2> Long Term Scoring </h2>
<p> <b> WARNING: Work in progress </b> </p>
<p> It is currently planned to store all the AIs on a virtual machine, and periodically run a script to play a round robin </p>
......@@ -69,9 +71,19 @@
<h2> Submissions </h2>
<p> We (I?) are now accepting test submissions. </p>
<p> Please email [email protected] attaching your submission source code </p>
<p> You must submit the full source code, and build instructions or makefile(s) for your program. </p>
<p> Also include the name of the executable or script, the name of the AI, your name, and optionally a description of your AI and its tactics. </p>
<p> Please email [email protected] if you have a submission. </p>
<h2> Dates </h2>
<p> The competition will run in 2012. The exact dates have not been determined. I will consider whether it is worth waiting until freshers have a chance to make submissions March/April, or running the competition earlier in January/February. </p>
<h2> Involvement </h2>
<p> If you want to help set up the competition, email [email protected] </p>
<p> There isn't much left to do, but all help is appreciated. Maybe you can suggest something, and volunteer to implement it! </p>
<p> The most useful thing you can do is actually write an AI, and test the manager program. Please report any bugs (in the manager program, not in your AI!) to [email protected] (you can feel free to fix them, but won't be able to push unless you email matches). </p>
<p> <b>Last webpage update: 12/12/11</b></p>
<p> <b>Last webpage update: 20/12/11</b></p>
</body>
</html>
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