From 345d8b1f49dfbc4f569c2dae992e896e6c685d55 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Tue, 20 Dec 2011 12:10:47 +0800 Subject: [PATCH] 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. --- progcomp/agents/basic_cpp/basic_cpp.cpp | 28 +++++++++++---- progcomp/agents/basic_python/basic_python.py | 23 +++++++++--- progcomp/judge/manager/manual.txt | 23 ++++++++---- progcomp/judge/manager/stratego.cpp | 16 +++++---- progcomp/judge/simulator/simulate.py | 37 ++++++++++++++++++-- progcomp/web/index.html | 16 +++++++-- 6 files changed, 116 insertions(+), 27 deletions(-) diff --git a/progcomp/agents/basic_cpp/basic_cpp.cpp b/progcomp/agents/basic_cpp/basic_cpp.cpp index ab00826..4312489 100644 --- a/progcomp/agents/basic_cpp/basic_cpp.cpp +++ b/progcomp/agents/basic_cpp/basic_cpp.cpp @@ -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); diff --git a/progcomp/agents/basic_python/basic_python.py b/progcomp/agents/basic_python/basic_python.py index 024ae55..849c6f7 100755 --- a/progcomp/agents/basic_python/basic_python.py +++ b/progcomp/agents/basic_python/basic_python.py @@ -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: diff --git a/progcomp/judge/manager/manual.txt b/progcomp/judge/manager/manual.txt index 3237241..120a6aa 100644 --- a/progcomp/judge/manager/manual.txt +++ b/progcomp/judge/manager/manual.txt @@ -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 diff --git a/progcomp/judge/manager/stratego.cpp b/progcomp/judge/manager/stratego.cpp index f2df0ff..62da170 100644 --- a/progcomp/judge/manager/stratego.cpp +++ b/progcomp/judge/manager/stratego.cpp @@ -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 { diff --git a/progcomp/judge/simulator/simulate.py b/progcomp/judge/simulator/simulate.py index 4429e4a..9b79194 100755 --- a/progcomp/judge/simulator/simulate.py +++ b/progcomp/judge/simulator/simulate.py @@ -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("\n") agentFile.close() - + #Update round file + roundFile = open(htmlDir + "round"+str(roundNumber)+".html", "w") + roundFile.write("\n\n Round " +str(roundNumber)+ " Overview \n\n\n") + roundFile.write("

Round " +str(roundNumber)+ " Overview

\n") + roundFile.write("\n") + roundFile.write("\n") + agents.sort(key = lambda e : e["score"][0], reverse=True) + for agent in agents: + roundFile.write("\n") + roundFile.write("
Name Score Total Score
"+agent["name"] + " " + str(agent["score"][0]) + " " + str(agent["totalScore"]) + "
\n\n\n\n\n") + roundFile.close() + + + if verbose: @@ -356,6 +375,20 @@ for agent in agents: agentFile.write("\n\n\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("\n\n Total Overview \n\n\n") +totalFile.write("

Total Overview

\n") +totalFile.write("\n") +totalFile.write("\n") +agents.sort(key = lambda e : e["totalScore"], reverse=True) +for agent in agents: + totalFile.write("\n") +totalFile.write("
Name Total Score
"+agent["name"] + " " + str(agent["totalScore"]) + "
\n\n\n\n\n") +totalFile.close() + if verbose: print "Done!" diff --git a/progcomp/web/index.html b/progcomp/web/index.html index 2a7fba8..ff1fea5 100644 --- a/progcomp/web/index.html +++ b/progcomp/web/index.html @@ -45,6 +45,8 @@

Warning: 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 git repository

+

Another Warning: AI programs must 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.

+

Long Term Scoring

WARNING: Work in progress

It is currently planned to store all the AIs on a virtual machine, and periodically run a script to play a round robin

@@ -69,9 +71,19 @@

Submissions

We (I?) are now accepting test submissions.

-

Please email matches@ attaching your submission source code

+

You must submit the full source code, and build instructions or makefile(s) for your program.

+

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.

+

Please email matches@ if you have a submission.

+ +

Dates

+

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.

+ +

Involvement

+

If you want to help set up the competition, email matches@

+

There isn't much left to do, but all help is appreciated. Maybe you can suggest something, and volunteer to implement it!

+

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 matches@ (you can feel free to fix them, but won't be able to push unless you email matches).

-

Last webpage update: 12/12/11

+

Last webpage update: 20/12/11

-- 2.20.1