diff --git a/progcomp/agents/basic_cpp/basic_cpp.cpp b/progcomp/agents/basic_cpp/basic_cpp.cpp index ab008264b8193a19b062f197b77ec4134335e448..4312489474fcac107c87533afce60655388b8864 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 024ae551a69231dfa62452e1e111a47f0fea4db6..849c6f7a84da75f98412529c191cd18712458c8e 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 3237241b31552eac5293f4d86386a648fd0997bf..120a6aafece21eeb7e6229124bee6dfc8a84ea28 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 f2df0ffc29719cda5a4e91b4e129580e4b2b5237..62da170281d797837fc2ed98899592b38b024d8e 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 4429e4ae01b2d0609a14badf0e6d376ad06ec703..9b79194e686c043a3ff47059eb4367c9b0111c25 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("</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!" diff --git a/progcomp/web/index.html b/progcomp/web/index.html index 2a7fba8338259110f930000e5bbdfdcf7b4063bb..ff1fea505097c5145c62755ea4bc9df2d4e8eba5 100644 --- a/progcomp/web/index.html +++ b/progcomp/web/index.html @@ -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 matches@ 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 matches@ 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 matches@ </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 matches@ (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>