Commit 85cfed04 authored by Sam Moore's avatar Sam Moore

[RULE CHANGE] "NO_MOVE" is no longer a legal

Previously AIs could respond with "NO_MOVE" whenever they felt like.
Officially, now they can only respond with "NO_MOVE" when they have no mobile pieces left.
(That is, only Bombs and the Flag are left).

However the game should end by a VICTORY_ATTRITION condition as soon as either player loses its last mobile piece.
So technically, "NO_MOVE" can't ever be legally printed, because the game should have ended. If it doesn't, there is a bug.

Updated webpage, updated manual, updated README

Going to email the list later today.

Goodluck!

PS: The rule change is due to a mean initial setup, for example:

**********
**********
**********
BB**BB**BB
..++..++..
..++..++..
etc

Here, Red has placed Bombs in all three "lanes". Red is unable to move.
However, as long as Red can use "NO_MOVE", an unsuspecting Blue will lose most of its pieces on the Bombs.
(Unless Blue puts a miner up the front...) But anyway, being able to not move is silly and not allowed in the real game.
parent e1153eeb
...@@ -51,10 +51,6 @@ description ...@@ -51,10 +51,6 @@ description
Please do not allow paths such as "../../" etc - but that is common sense! Please do not allow paths such as "../../" etc - but that is common sense!
=== TODO ===
Add a user for each submission for extra security
Web upload?
[SZM] (matches) 22/12/2011 [SZM] (matches) 22/12/2011
...@@ -80,6 +80,8 @@ MovementResult Controller::MakeMove(string & buffer) ...@@ -80,6 +80,8 @@ MovementResult Controller::MakeMove(string & buffer)
if (query != MovementResult::OK) if (query != MovementResult::OK)
return query; return query;
/*
//Removed 3/01/12 NO_MOVE now not allowed, SURRENDER is undocumented and not necessary
if (buffer == "NO_MOVE") if (buffer == "NO_MOVE")
{ {
buffer += " OK"; buffer += " OK";
...@@ -90,6 +92,7 @@ MovementResult Controller::MakeMove(string & buffer) ...@@ -90,6 +92,7 @@ MovementResult Controller::MakeMove(string & buffer)
buffer += " OK"; buffer += " OK";
return MovementResult::SURRENDER; return MovementResult::SURRENDER;
} }
*/
int x; int y; string direction=""; int x; int y; string direction="";
stringstream s(buffer); stringstream s(buffer);
......
...@@ -442,9 +442,24 @@ void Game::PrintEndMessage(const MovementResult & result) ...@@ -442,9 +442,24 @@ void Game::PrintEndMessage(const MovementResult & result)
} }
} }
/** Checks for victory by attrition (destroying all mobile pieces)
*
* @returns OK for no victory,
* DRAW if both players have no pieces, or
* VICTORY_ATTRITION if the current player has won by attrition
*/
MovementResult Game::CheckVictoryAttrition()
{
if (theBoard.MobilePieces(Piece::OppositeColour(turn)) == 0)
{
if (theBoard.MobilePieces(turn) == 0)
return MovementResult::DRAW;
else
return MovementResult::VICTORY_ATTRITION;
}
return MovementResult::OK;
}
MovementResult Game::Play() MovementResult Game::Play()
{ {
...@@ -483,22 +498,26 @@ MovementResult Game::Play() ...@@ -483,22 +498,26 @@ MovementResult Game::Play()
#endif //BUILD_GRAPHICS #endif //BUILD_GRAPHICS
turn = Piece::RED; turn = Piece::RED;
if (!Board::HaltResult(result))
{
result = CheckVictoryAttrition();
}
if (Board::HaltResult(result))
break;
logMessage( "%d RED: ", turnCount); logMessage( "%d RED: ", turnCount);
result = red->MakeMove(buffer); result = red->MakeMove(buffer);
red->Message(buffer); red->Message(buffer);
blue->Message(buffer); blue->Message(buffer);
logMessage( "%s\n", buffer.c_str()); logMessage( "%s\n", buffer.c_str());
if (Board::HaltResult(result))
break;
if (theBoard.MobilePieces(Piece::BLUE) == 0) if (!Board::HaltResult(result))
{ {
if (theBoard.MobilePieces(Piece::RED) == 0) result = CheckVictoryAttrition();
result = MovementResult::DRAW;
else
result = MovementResult::VICTORY_ATTRITION;
break;
} }
if (Board::HaltResult(result))
break;
if (stallTime >= 0) if (stallTime >= 0)
Wait(stallTime); Wait(stallTime);
...@@ -523,12 +542,24 @@ MovementResult Game::Play() ...@@ -523,12 +542,24 @@ MovementResult Game::Play()
turn = Piece::BLUE; turn = Piece::BLUE;
if (!Board::HaltResult(result))
{
result = CheckVictoryAttrition();
}
if (Board::HaltResult(result))
break;
logMessage( "%d BLU: ", turnCount); logMessage( "%d BLU: ", turnCount);
result = blue->MakeMove(buffer); result = blue->MakeMove(buffer);
blue->Message(buffer); blue->Message(buffer);
red->Message(buffer); red->Message(buffer);
logMessage( "%s\n", buffer.c_str()); logMessage( "%s\n", buffer.c_str());
if (!Board::HaltResult(result))
{
result = CheckVictoryAttrition();
}
if (Board::HaltResult(result)) if (Board::HaltResult(result))
break; break;
......
...@@ -23,6 +23,7 @@ class Game ...@@ -23,6 +23,7 @@ class Game
void Wait(double wait); void Wait(double wait);
Piece::Colour Setup(const char * redName, const char * blueName); Piece::Colour Setup(const char * redName, const char * blueName);
MovementResult CheckVictoryAttrition();
MovementResult Play(); MovementResult Play();
void PrintEndMessage(const MovementResult & result); void PrintEndMessage(const MovementResult & result);
......
...@@ -57,6 +57,27 @@ Piece::Type Piece::GetType(char fromToken) ...@@ -57,6 +57,27 @@ Piece::Type Piece::GetType(char fromToken)
return Piece::BOULDER; return Piece::BOULDER;
} }
/**
* Gets the opposite to the indicated colour
*/
Piece::Colour Piece::OppositeColour(const Colour & colour)
{
switch (colour)
{
case Piece::RED:
return Piece::BLUE;
break;
case Piece::BLUE:
return Piece::RED;
break;
case Piece::BOTH:
return Piece::BOTH;
break;
case Piece::NONE:
return Piece::NONE;
}
}
/** /**
* Construct a new, empty board * Construct a new, empty board
* @param newWidth - the width of the board * @param newWidth - the width of the board
......
...@@ -28,6 +28,9 @@ class Piece ...@@ -28,6 +28,9 @@ class Piece
typedef enum {RED=0, BLUE=1, NONE=2, BOTH=3} Colour; //Used for the allegiance of the pieces - terrain counts as NONE. typedef enum {RED=0, BLUE=1, NONE=2, BOTH=3} Colour; //Used for the allegiance of the pieces - terrain counts as NONE.
static Colour OppositeColour(const Colour & compare);
Piece(const Type & newType, const Colour & newColour) : type(newType), colour(newColour), beenRevealed(false) {} Piece(const Type & newType, const Colour & newColour) : type(newType), colour(newColour), beenRevealed(false) {}
virtual ~Piece() {} virtual ~Piece() {}
......
...@@ -328,10 +328,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -328,10 +328,10 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
print "RESULTS FOR ROUND " + str(roundNumber) print "RESULTS FOR ROUND " + str(roundNumber)
#totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file #totalFile = open(resultsDirectory+"total.scores", "w") #Recreate the file
for agent in agents: #for agent in agents:
#totalFile.write(agent["name"] + " " + str(agent["totalScore"]) +"\n") #Write the total scores in descending order #totalFile.write(agent["name"] + " " + str(agent["totalScore"]) +"\n") #Write the total scores in descending order
#if verbose: #if verbose:
print "Agent: " + str(agent) # print "Agent: " + str(agent)
if verbose: if verbose:
...@@ -356,9 +356,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds): ...@@ -356,9 +356,9 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
for index in range(0, len(agent["ALL"])): for index in range(0, len(agent["ALL"])):
if agent["ALL"][index][4] == "RED": if agent["ALL"][index][4] == "RED":
logFile = logDirectory + "round"+str(roundNumber) + "/"+agent["name"]+".vs."+agent["ALL"][index][0]+"."+str(agent["ALL"][index][1]) logFile = "log/round"+str(roundNumber) + "/"+agent["name"]+".vs."+agent["ALL"][index][0]+"."+str(agent["ALL"][index][1])
else: else:
logFile = logDirectory + "round"+str(roundNumber) + "/"+agent["ALL"][index][0]+".vs."+agent["name"]+"."+str(agent["ALL"][index][1]) logFile = "log/round"+str(roundNumber) + "/"+agent["ALL"][index][0]+".vs."+agent["name"]+"."+str(agent["ALL"][index][1])
agentFile.write("<tr> <td> <a href="+logFile+">" + str(agent["ALL"][index][1]) + " </a> </td> <td> <a href="+agent["ALL"][index][0]+".html>"+agent["ALL"][index][0] + " </a> </td> <td> " + agent["ALL"][index][4] + " </td> <td> " + agent["ALL"][index][3] + " </td> <td> " + str(agent["ALL"][index][2]) + "</td> <td> " + str(agent["score"][len(agent["score"])-index -2]) + " </td> </tr> </th>\n") agentFile.write("<tr> <td> <a href="+logFile+">" + str(agent["ALL"][index][1]) + " </a> </td> <td> <a href="+agent["ALL"][index][0]+".html>"+agent["ALL"][index][0] + " </a> </td> <td> " + agent["ALL"][index][4] + " </td> <td> " + agent["ALL"][index][3] + " </td> <td> " + str(agent["ALL"][index][2]) + "</td> <td> " + str(agent["score"][len(agent["score"])-index -2]) + " </td> </tr> </th>\n")
agentFile.write("</table>\n") agentFile.write("</table>\n")
......
...@@ -157,16 +157,14 @@ PROTOCOL ...@@ -157,16 +157,14 @@ PROTOCOL
as described in the GAME_RULES section. Each line ends with the newline character. as described in the GAME_RULES section. Each line ends with the newline character.
RESPONSE: X Y DIRECTION [MULTIPLIER=1] | NO_MOVE RESPONSE: X Y DIRECTION [MULTIPLIER=1]
X and Y are the coords (starting from 0) of the piece to move X and Y are the coords (starting from 0) of the piece to move
DIRECTION is either UP, DOWN, LEFT or RIGHT DIRECTION is either UP, DOWN, LEFT or RIGHT
MULTIPLIER is optional and only valid for units of type Scout. Scouts may move through any number of unblocked squares MULTIPLIER is optional and only valid for units of type Scout. Scouts may move through any number of unblocked squares
in one direction. in one direction.
The AI program should print "NO_MOVE" if it is unable to determine a move.
This will typically occur when the only pieces belonging to the AI program are Bombs and the Flag.
CONFIRMATION: X Y DIRECTION [MULTIPLIER=1] OUTCOME | NO_MOVE {OK | ILLEGAL} | QUIT [RESULT] CONFIRMATION: X Y DIRECTION [MULTIPLIER=1] OUTCOME | QUIT [RESULT]
OUTCOME may be either OK, ILLEGAL, KILLS or DIES OUTCOME may be either OK, ILLEGAL, KILLS or DIES
OK - Move was successful OK - Move was successful
...@@ -174,14 +172,7 @@ PROTOCOL ...@@ -174,14 +172,7 @@ PROTOCOL
KILLS ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and killed the defender. KILLS ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and killed the defender.
DIES ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and was killed by the defender. DIES ATTACKER_RANK DEFENDER_RANK - The piece moved into an occupied square and was killed by the defender.
Most turns will be confirmed with: "X Y DIRECTION [MULTIPLIER=1] OUTCOME" QUIT will only be sent when the game is about to end.
A confirmation of "NO_MOVE OK" occurs when the AI program made no move for a legitimate reason.
"NO_MOVE ILLEGAL" is printed if the AI program made no move for an illegitimate reason.
If both AI programs successively make a "NO_MOVE" response, then the game will end.
The player with the highest piece value will win, or a draw will be declared if the values are equal.
3. END GAME 3. END GAME
If the CONFIRMATION line is of the form: If the CONFIRMATION line is of the form:
QUIT [RESULT] QUIT [RESULT]
...@@ -277,5 +268,5 @@ NOTES ...@@ -277,5 +268,5 @@ NOTES
irc://irc.ucc.asn.au #progcomp irc://irc.ucc.asn.au #progcomp
THIS PAGE LAST UPDATED THIS PAGE LAST UPDATED
23/12/11 by Sam Moore 3/01/12 by Sam Moore
...@@ -39,42 +39,31 @@ ...@@ -39,42 +39,31 @@
<h3> Protocol </h3> <h3> Protocol </h3>
<p> For the sake of simplicity and keeping things in one place, the protocol is now entirely described in the <a href="doc/manager_manual.txt"/>manual page</a> of the manager program. All updates to the protocol will be reflected in that file. </p> <p> For the sake of simplicity and keeping things in one place, the protocol is now entirely described in the <a href="doc/manager_manual.txt"/>manual page</a> of the manager program. All updates to the protocol will be reflected in that file. </p>
<p> Major updates to the manager program or protocol will be accompanied by an email to the mailing list. However, it is probably a good idea to clone the git repository, and regularly pull from it. </p>
<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 "web/doc/manager_manual.txt" in the <a href="http://git.ucc.asn.au/?p=progcomp2012.git;a=summary"/>git repository</a> </p> <p> <b> 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>
<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> Scoring and Results </h2>
<p> The competition will be a round robin, with every AI playing three (3) games against each possible opponent. A points system is used to score each AI, 3 points for a Win, 2 for a Draw, 1 for a Loss or -1 for an Illegal response (counts as a Win for the opponent). Scores accumulate between rounds. </p>
<p> The winning AI will be the AI with the highest score after all games have been played. In the event of a tied score, the two highest scoring AI's will play one more round consisting of three games. If the scores are still tied, the official outcome will be a Draw. </p>
<p> When the competition officially runs, results will appear <a href="results"/>here</a>. There may (or may not) be test results there now. </p> <p>
<h2> Long Term Scoring </h2> <h2> Sample AI Programs </h2>
<p> Several rounds will be played (depending on the number of entries), with contestants given time to improve their entries between rounds. </p> <p> Several sample AI programs are currently available. No guarantees are provided about the functioning of these programs. The sample programs can be downloaded from the <a href="http://git.ucc.asn.au/?p=progcomp2012.git;a=summary"/>git repository </a>
<p> Each round is a round robin, with every AI playing several games against each possible opponent. A points system is used to score each AI, 3 points for a Win, 2 for a Draw, 1 for a Loss or -1 for an Illegal response (counts as a Win for the opponent). Scores accumulate between rounds. </p>
<p> The winning AI will be the AI with the highest score after all rounds have been played. In the event of a tied score, the two highest scoring AI's will play one more round consisting of three games. If the scores are still tied, the official outcome will be a Draw. </p>
<p> When the competition officially runs, results will appear <a href="results"/>here</a>. Preliminary test results might occasionally appear there for the next few weeks. </p> <p>
<h2> Sample AI Programs </h2>>
<p> The following sample programs are currently available (and in a semi-working state - refer to the git repository): </p>
<table border="0">
<tr> <th>Name</th> <th>Language</th> <th> Moves </th> <th> Considers... </th> </tr>
<tr> <td>basic_python</td> <td>Python</td> <td>Randomised</td> </tr>
<tr> <td>basic_cpp</td> <td>C++</td> <td>Randomised</td> </tr>
<tr> <td>asmodeus</td> <td>Python</td> <td>Scored</td> <td>Path finding, known combat results, piece values</td> </th>
<tr> <td>vixen</td> <td>Python</td> <td>Scored</td> <td>Asmodeus + Probabilities for unknown combat results </td> </th>
</table>
<p> It is planned to implement the equivelants of these samples in C++ and Python at least, possibly other languages later. </p>
<h2> Submissions </h2> <h2> Submissions </h2>
<p> You must submit the full source code, and build instructions or makefile(s) for your program. </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> 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> <p> Please email [email protected] if you have a submission. </p>
<p> <b> Code which attempts to comprimise the host machine, or interfere directly with the functioning of other programs will be disqualified. </b> </p> <p> <b> Code which attempts to comprimise the host machine, or interfere interfere either directly or indirectly with the functioning of other programs will be disqualified. </b> </p>
<h2> Dates </h2> <h2> Dates </h2>
<p> The competition will run in 2012. The exact dates have not been determined. An email will be sent to the list and messages sent to the irc channel. </p> <p> The competition is now officially open. Submissions will be accepted until midday, Saturday the 10th of March, 2012. Results will be announced as soon as they are available (depending on the number of entries it may take several days to simulate the competition). </p>
<h2> Involvement </h2>
<p> If you want to help set up the competition, email [email protected] </p>
<h2> FAQ </h2>
<p> No one has asked any questions yet. If there is anything not covered or vague on this page, please email [email protected] </p>
<p> <b>Last webpage update: 22/12/11</b></p> <p> <b>Last webpage update: 06/01/12</b></p>
</body> </body>
</html> </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