[RULE CHANGE] *Victory by "attrition"* + Bug fixes
authorSam Moore <[email protected]>
Sat, 24 Dec 2011 10:59:38 +0000 (18:59 +0800)
committerSam Moore <[email protected]>
Sat, 24 Dec 2011 10:59:38 +0000 (18:59 +0800)
Minor bugs in the manager program fixed.
Changed some messages for clarity, can't remember what, look at diff.

Added VICTORY_ATTRITION; victory by destroying all of the opponents _mobile_ pieces
 (ie: Everything except Bombs/Flag)

This means we don't get results of DRAW or DRAW_DEFAULT when one AI destroys all the other's mobile pieces.
Since those games would last up to 5000 turns, this saves a lot of wasted time.

AI should still respond with "NO_MOVE" when they have no mobile pieces.

Made timeout value adjustable by an argument switch, '-T'
Altered simulate.py to use a timeout variable and supply the switch to the manager program.

So now I don't need to recompile and commit the manager program every time I want to test a different timeout value on mufasa!

Mufasa is now on game 3 of the test round, out of 12. After FIVE HOURS.
This particular game has lasted 1132 turns, with BLUE making "NO_MOVE" for the last 600 or so.
The new victory condition will stop this sort of thing :)

Merry Christmas!

12 files changed:
judge/manager/Makefile
judge/manager/controller.cpp
judge/manager/game.cpp
judge/manager/game.h
judge/manager/graphics.h
judge/manager/main.cpp
judge/manager/movementresult.h
judge/manager/program.cpp
judge/manager/stratego.cpp
judge/manager/stratego.h
judge/simulator/simulate.py
web/doc/manager_manual.txt

index 37b2c29..67ffda9 100644 (file)
@@ -1,9 +1,9 @@
 #Makefile for Stratego
 
 #Use this to build with graphics
 #Makefile for Stratego
 
 #Use this to build with graphics
-#CPP = g++ -Wall -pedantic -lSDL -lGL -lpthread -g
+CPP = g++ -Wall -pedantic -lSDL -lGL -lpthread -g
 #Use this to build without graphics
 #Use this to build without graphics
-CPP = g++ -Wall -pedantic -lpthread -g
+#CPP = g++ -Wall -pedantic -lpthread -g
 OBJ = main.o controller.o ai_controller.o human_controller.o program.o thread_util.o stratego.o graphics.o game.o
 
 BIN = stratego
 OBJ = main.o controller.o ai_controller.o human_controller.o program.o thread_util.o stratego.o graphics.o game.o
 
 BIN = stratego
index 1b0a35d..f5c99ce 100644 (file)
@@ -138,8 +138,11 @@ MovementResult Controller::MakeMove(string & buffer)
                case MovementResult::OK:
                        buffer += " OK";
                        break;
                case MovementResult::OK:
                        buffer += " OK";
                        break;
-               case MovementResult::VICTORY:
-                       buffer += " FLAG";
+               case MovementResult::VICTORY_FLAG:
+                       buffer += " VICTORY_FLAG";
+                       break;
+               case MovementResult::VICTORY_ATTRITION:
+                       buffer += " VICTORY_ATTRITION";
                        break;
                case MovementResult::KILLS:
                        buffer += " KILLS ";
                        break;
                case MovementResult::KILLS:
                        buffer += " KILLS ";
index df7a061..3df968c 100644 (file)
@@ -7,7 +7,7 @@ using namespace std;
 Game* Game::theGame = NULL;
 bool Game::gameCreated = false;
 
 Game* Game::theGame = NULL;
 bool Game::gameCreated = false;
 
-Game::Game(const char * redPath, const char * bluePath, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const  Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard) : red(NULL), blue(NULL), turn(Piece::RED), theBoard(10,10), graphicsEnabled(enableGraphics), stallTime(newStallTime), allowIllegalMoves(allowIllegal), log(newLog), reveal(newReveal), turnCount(0), input(NULL), maxTurns(newMaxTurns), printBoard(newPrintBoard)
+Game::Game(const char * redPath, const char * bluePath, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const  Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard, double newTimeoutTime) : red(NULL), blue(NULL), turn(Piece::RED), theBoard(10,10), graphicsEnabled(enableGraphics), stallTime(newStallTime), allowIllegalMoves(allowIllegal), log(newLog), reveal(newReveal), turnCount(0), input(NULL), maxTurns(newMaxTurns), printBoard(newPrintBoard), timeoutTime(newTimeoutTime)
 {
        gameCreated = false;
        if (gameCreated)
 {
        gameCreated = false;
        if (gameCreated)
@@ -28,18 +28,18 @@ Game::Game(const char * redPath, const char * bluePath, const bool enableGraphic
        if (strcmp(redPath, "human") == 0)
                red = new Human_Controller(Piece::RED, graphicsEnabled);
        else
        if (strcmp(redPath, "human") == 0)
                red = new Human_Controller(Piece::RED, graphicsEnabled);
        else
-               red = new AI_Controller(Piece::RED, redPath);
+               red = new AI_Controller(Piece::RED, redPath, timeoutTime);
        
        
        if (strcmp(bluePath, "human") == 0)
                blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
        else
        
        
        if (strcmp(bluePath, "human") == 0)
                blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
        else
-               blue = new AI_Controller(Piece::BLUE, bluePath);
+               blue = new AI_Controller(Piece::BLUE, bluePath, timeoutTime);
 
 
 }
 
 
 
 }
 
-Game::Game(const char * fromFile, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const  Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard) : red(NULL), blue(NULL), turn(Piece::RED), theBoard(10,10), graphicsEnabled(enableGraphics), stallTime(newStallTime), allowIllegalMoves(allowIllegal), log(newLog), reveal(newReveal), turnCount(0), input(NULL), maxTurns(newMaxTurns), printBoard(newPrintBoard)
+Game::Game(const char * fromFile, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const  Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard, double newTimeoutTime) : red(NULL), blue(NULL), turn(Piece::RED), theBoard(10,10), graphicsEnabled(enableGraphics), stallTime(newStallTime), allowIllegalMoves(allowIllegal), log(newLog), reveal(newReveal), turnCount(0), input(NULL), maxTurns(newMaxTurns), printBoard(newPrintBoard), timeoutTime(newTimeoutTime)
 {
        gameCreated = false;
        if (gameCreated)
 {
        gameCreated = false;
        if (gameCreated)
@@ -93,13 +93,13 @@ Piece::Colour Game::Setup(const char * redName, const char * blueName)
        {
                logMessage("Controller for Player RED is invalid!\n");
                if (!red->HumanController())
        {
                logMessage("Controller for Player RED is invalid!\n");
                if (!red->HumanController())
-                       logMessage("Check that program \"%s\" exists and has executable permissions set.\n", redName);
+                       logMessage("Check that executable \"%s\" exists and has executable permissions set.\n", redName);
        }
        if (!blue->Valid())
        {
                logMessage("Controller for Player BLUE is invalid!\n");
                if (!blue->HumanController())
        }
        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);
+                       logMessage("Check that executable \"%s\" exists and has executable permissions set.\n", blueName);
        }
        if (!red->Valid())
        {
        }
        if (!red->Valid())
        {
@@ -243,13 +243,15 @@ void Game::HandleBrokenPipe(int sig)
        if (theGame->turn == Piece::RED)
        {
                theGame->logMessage("Game ends on RED's turn - REASON: ");
        if (theGame->turn == Piece::RED)
        {
                theGame->logMessage("Game ends on RED's turn - REASON: ");
-               theGame->blue->Message("DEFAULT");      
+               if (theGame->blue->Valid()) //Should probably check this
+                       theGame->blue->Message("DEFAULT");      
        }
        else if (theGame->turn == Piece::BLUE)
        {
        
                theGame->logMessage("Game ends on BLUE's turn - REASON: ");
        }
        else if (theGame->turn == Piece::BLUE)
        {
        
                theGame->logMessage("Game ends on BLUE's turn - REASON: ");
-               theGame->red->Message("DEFAULT");
+               if (theGame->red->Valid()) //Should probably check this
+                       theGame->red->Message("DEFAULT");
        }
        else
        {
        }
        else
        {
@@ -257,7 +259,7 @@ void Game::HandleBrokenPipe(int sig)
                        
        }
        
                        
        }
        
-       theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
+       theGame->logMessage("SIGPIPE - Broken pipe (AI program no longer running)\n");
 
        if (Game::theGame->printBoard)
                Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH);
 
        if (Game::theGame->printBoard)
                Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH);
@@ -285,7 +287,7 @@ void Game::HandleBrokenPipe(int sig)
        else
        #endif //BUILD_GRAPHICS
        {
        else
        #endif //BUILD_GRAPHICS
        {
-               if (theGame->log == stdout)
+               if (theGame->log == stdout || theGame->log == stderr)
                {
                        theGame->logMessage( "PRESS ENTER TO EXIT\n");
                        theGame->theBoard.Print(theGame->log);
                {
                        theGame->logMessage( "PRESS ENTER TO EXIT\n");
                        theGame->theBoard.Print(theGame->log);
@@ -354,14 +356,17 @@ void Game::PrintEndMessage(const MovementResult & result)
                case MovementResult::POSITION_FULL:
                        logMessage("Attempted move into square occupied by neutral or allied piece\n");
                        break;
                case MovementResult::POSITION_FULL:
                        logMessage("Attempted move into square occupied by neutral or allied piece\n");
                        break;
-               case MovementResult::VICTORY:
+               case MovementResult::VICTORY_FLAG:
                        logMessage("Captured the flag\n");
                        break;
                        logMessage("Captured the flag\n");
                        break;
+               case MovementResult::VICTORY_ATTRITION:
+                       logMessage("Destroyed all mobile enemy pieces\n");
+                       break;
                case MovementResult::BAD_RESPONSE:
                        logMessage("Unintelligable response\n");
                        break;
                case MovementResult::NO_MOVE:
                case MovementResult::BAD_RESPONSE:
                        logMessage("Unintelligable response\n");
                        break;
                case MovementResult::NO_MOVE:
-                       logMessage("Did not make a move (may have exited)\n");
+                       logMessage("Response timeout after %2f seconds.\n", timeoutTime);
                        break;
                case MovementResult::COLOUR_ERROR:
                        logMessage("Internal controller error - COLOUR_ERROR\n");
                        break;
                case MovementResult::COLOUR_ERROR:
                        logMessage("Internal controller error - COLOUR_ERROR\n");
@@ -432,6 +437,7 @@ void Game::PrintEndMessage(const MovementResult & result)
                {
                        logMessage("PRESS ENTER TO EXIT\n");
                        while (fgetc(stdin) != '\n');
                {
                        logMessage("PRESS ENTER TO EXIT\n");
                        while (fgetc(stdin) != '\n');
+                       exit(EXIT_SUCCESS); //Might want to actually exit, you foolish fool
                }
        }
 
                }
        }
 
@@ -485,7 +491,16 @@ MovementResult Game::Play()
                if (Board::HaltResult(result))
                        break;
 
                if (Board::HaltResult(result))
                        break;
 
-               if (stallTime > 0)
+               if (theBoard.MobilePieces(Piece::BLUE) == 0)
+               {
+                       if (theBoard.MobilePieces(Piece::RED) == 0)
+                               result = MovementResult::DRAW;
+                       else
+                               result = MovementResult::VICTORY_ATTRITION;
+                       break;                  
+               }
+
+               if (stallTime >= 0)
                        Wait(stallTime);
                else
                        ReadUserCommand();
                        Wait(stallTime);
                else
                        ReadUserCommand();
@@ -517,17 +532,24 @@ MovementResult Game::Play()
                if (Board::HaltResult(result))
                        break;
 
                if (Board::HaltResult(result))
                        break;
 
-               
+               if (theBoard.MobilePieces(Piece::RED) == 0)
+                       result = MovementResult::DRAW;
 
 
-               
+               if (theBoard.MobilePieces(Piece::RED) == 0)
+               {
+                       if (theBoard.MobilePieces(Piece::BLUE) == 0)
+                               result = MovementResult::DRAW;
+                       else
+                               result = MovementResult::VICTORY_ATTRITION;
+                       break;                  
+               }
 
 
-               if (stallTime > 0)
+               if (stallTime >= 0)
                        Wait(stallTime);
                else
                        ReadUserCommand();
        
                        Wait(stallTime);
                else
                        ReadUserCommand();
        
-               if (theBoard.MobilePieces(Piece::BOTH) == 0)
-                       result = MovementResult::DRAW;
+               
 
                ++turnCount;
        }
 
                ++turnCount;
        }
@@ -569,12 +591,18 @@ int Game::logMessage(const char * format, ...)
  */
 void Game::ReadUserCommand()
 {
  */
 void Game::ReadUserCommand()
 {
-       fprintf(stdout, "Waiting for user to press enter...\n");
+       fprintf(stdout, "Waiting for user to press enter... (type QUIT to exit)\n");
        string command("");
        for (char c = fgetc(stdin); c != '\n' && (int)(c) != EOF; c = fgetc(stdin))
        {
                command += c;
        }
        string command("");
        for (char c = fgetc(stdin); c != '\n' && (int)(c) != EOF; c = fgetc(stdin))
        {
                command += c;
        }
+
+       if (command == "QUIT")
+       {
+               fprintf(stdout, "Ordered to quit... exiting...\n");
+               exit(EXIT_SUCCESS);
+       }
 }
 
 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
 }
 
 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
@@ -610,17 +638,86 @@ MovementResult FileController::QuerySetup(const char * opponentName, std::string
 
 MovementResult FileController::QueryMove(std::string & buffer)
 {
 
 MovementResult FileController::QueryMove(std::string & buffer)
 {
+       //This bit is kind of hacky and terrible, and yes I am mixing C with C++
+       //Yes I should have used fstream for the whole thing and it would be much easier.
+       //Oh well.
+
        char buf[BUFSIZ];
 
        fgets(buf, sizeof(buf), file);
        char * s = (char*)(buf);
        while (*s != ':' && *s != '\0')
                ++s;
        char buf[BUFSIZ];
 
        fgets(buf, sizeof(buf), file);
        char * s = (char*)(buf);
        while (*s != ':' && *s != '\0')
                ++s;
-
-       s += 2;
        
        
+       //Move forward to the start of the move information
+       for (int i=0; i < 2; ++i)
+       {
+               if (*s != '\0' && *s != '\n')
+                       ++s;
+       }
+       
+       //Unfortunately we can't just copy the whole line
        buffer = string(s);
        buffer = string(s);
+       //We have to remove the movement result tokens
+       
+
+       vector<string> tokens;
+       Game::Tokenise(tokens, buffer, ' ');
+       buffer.clear();
+
+       if (tokens.size() < 1)
+               return MovementResult::BAD_RESPONSE;
+       buffer += tokens[0];
+
+       
+       if (tokens[0] == "NO_MOVE") //tokens[0] is either the x coordinate, or "NO_MOVE"
+               return MovementResult::OK;
+       if (tokens.size() < 2)
+               return MovementResult::BAD_RESPONSE;
+       buffer += " ";
+       buffer += tokens[1]; //The y coordinate
+       buffer += " ";
+       buffer += tokens[2]; //The direction
+       
+       //Check for a possible multiplier. If tokens[3] is an integer it will be the multiplier, otherwise it won't be.
+       if (tokens.size() > 3 && atoi(tokens[3].c_str()) != 0)
+       {
+               buffer += " ";
+               buffer += tokens[3];
+       }
+       else
+       {
+               //(tokens[3] should include a new line)
+               //buffer += "\n";
+       }
+
+       
+
+       
+       
+       
        return MovementResult::OK;
 }
 
        return MovementResult::OK;
 }
 
+/**
+ * Tokenise a string
+ */
+int Game::Tokenise(std::vector<string> & buffer, std::string & str, char split)
+{
+       string token = "";
+       for (unsigned int x = 0; x < str.size(); ++x)
+       {
+               if (str[x] == split && token.size() > 0)
+               {
+                       buffer.push_back(token);
+                       token = "";
+               }
+               if (str[x] != split)
+                       token += str[x];
+       }
+       if (token.size() > 0)
+               buffer.push_back(token);
+       return buffer.size();
+}
+
 
 
index 43f4d0e..aebda9d 100644 (file)
@@ -9,12 +9,13 @@
 
 /**
  * Class to manage the game
 
 /**
  * Class to manage the game
+ * Bit messy since I keep adding on parameters :P
  */
 class Game
 {
        public:
  */
 class Game
 {
        public:
-               Game(const char * redPath, const char * bluePath, const bool enableGraphics, double newStallTime = 1.0, const bool allowIllegal=false, FILE * newLog = NULL, const Piece::Colour & newRevealed = Piece::BOTH, int maxTurns = 5000, const bool printBoard = false);
-               Game(const char * fromFile, const bool enableGraphics, double newStallTime = 1.0, const bool allowIllegal=false, FILE * newLog = NULL, const Piece::Colour & newRevealed = Piece::BOTH, int maxTurns = 5000, const bool printBoard = false);
+               Game(const char * redPath, const char * bluePath, const bool enableGraphics, double newStallTime = 1.0, const bool allowIllegal=false, FILE * newLog = NULL, const Piece::Colour & newRevealed = Piece::BOTH, int maxTurns = 5000, const bool printBoard = false, double newTimeoutTime = 2.0);
+               Game(const char * fromFile, const bool enableGraphics, double newStallTime = 1.0, const bool allowIllegal=false, FILE * newLog = NULL, const Piece::Colour & newRevealed = Piece::BOTH, int maxTurns = 5000, const bool printBoard = false, double newTimeoutTime = 2.0);
                virtual ~Game();
 
                
                virtual ~Game();
 
                
@@ -34,6 +35,7 @@ class Game
                int TurnCount() const {return turnCount;}
 
                static Game * theGame;
                int TurnCount() const {return turnCount;}
 
                static Game * theGame;
+               static int Tokenise(std::vector<std::string> & buffer, std::string & str, char split = ' '); //Helper - Split a string into tokens
        public:
                int logMessage(const char * format, ...);
                FILE * GetLogFile() const {return log;}
        public:
                int logMessage(const char * format, ...);
                FILE * GetLogFile() const {return log;}
@@ -63,6 +65,9 @@ class Game
 
                int maxTurns;
                const bool printBoard;
 
                int maxTurns;
                const bool printBoard;
+
+       private:
+               double timeoutTime;
                
 };
 
                
 };
 
index 2a96932..caa57c6 100644 (file)
@@ -1,4 +1,4 @@
-//#define BUILD_GRAPHICS
+#define BUILD_GRAPHICS
 #ifdef BUILD_GRAPHICS
 
 #ifndef GRAPHICS_H
 #ifdef BUILD_GRAPHICS
 
 #ifndef GRAPHICS_H
index 9d2cad1..ce4cd20 100644 (file)
@@ -62,8 +62,8 @@ int main(int argc, char ** argv)
 
 Piece::Colour SetupGame(int argc, char ** argv)
 {
 
 Piece::Colour SetupGame(int argc, char ** argv)
 {
-       char * red = NULL; char * blue = NULL; double timeout = 0.00001; bool graphics = false; bool allowIllegal = false; FILE * log = NULL;
-       Piece::Colour reveal = Piece::BOTH; char * inputFile = NULL; int maxTurns = 5000; bool printBoard = false;
+       char * red = NULL; char * blue = NULL; double stallTime = 0.0; bool graphics = false; bool allowIllegal = false; FILE * log = NULL;
+       Piece::Colour reveal = Piece::BOTH; char * inputFile = NULL; int maxTurns = 5000; bool printBoard = false; double timeoutTime = 2.0;
        for (int ii=1; ii < argc; ++ii)
        {
                if (argv[ii][0] == '-')
        for (int ii=1; ii < argc; ++ii)
        {
                if (argv[ii][0] == '-')
@@ -73,15 +73,29 @@ Piece::Colour SetupGame(int argc, char ** argv)
                                case 't':
                                        if (argc - ii <= 1)
                                        {
                                case 't':
                                        if (argc - ii <= 1)
                                        {
-                                               fprintf(stderr, "ARGUMENT_ERROR - Expected timeout value after -t switch!\n");
+                                               fprintf(stderr, "ARGUMENT_ERROR - Expected stall time value after -t switch!\n");
                                                exit(EXIT_FAILURE);
                                        }
                                        if (strcmp(argv[ii+1], "inf") == 0)
                                                exit(EXIT_FAILURE);
                                        }
                                        if (strcmp(argv[ii+1], "inf") == 0)
-                                               timeout = -1;
+                                               stallTime = -1;
                                        else
                                        else
-                                               timeout = atof(argv[ii+1]);
+                                               stallTime = atof(argv[ii+1]);
                                        ++ii;
                                        break;
                                        ++ii;
                                        break;
+
+                               case 'T':
+                                       if (argc - ii <= 1)
+                                       {
+                                               fprintf(stderr, "ARGUMENT_ERROR - Expected timeout value after -T switch!\n");
+                                               exit(EXIT_FAILURE);
+                                       }
+                                       if (strcmp(argv[ii+1], "inf") == 0)
+                                               timeoutTime = -1;
+                                       else
+                                               timeoutTime = atof(argv[ii+1]);
+                                       ++ii;
+                                       break;
+
                                case 'g':
                                        #ifdef BUILD_GRAPHICS
                                        graphics = !graphics;
                                case 'g':
                                        #ifdef BUILD_GRAPHICS
                                        graphics = !graphics;
@@ -192,7 +206,8 @@ Piece::Colour SetupGame(int argc, char ** argv)
                }
        }
 
                }
        }
 
-
+       if (graphics && stallTime == 0.0)
+               stallTime = 0.00001; //Hack so that SDL events (ie SDL_QUIT) will have time to be captured when graphics are enabled
 
        if (inputFile == NULL)
        {
 
        if (inputFile == NULL)
        {
@@ -201,11 +216,11 @@ Piece::Colour SetupGame(int argc, char ** argv)
                        fprintf(stderr, "ARGUMENT_ERROR - Did not recieve enough players (did you mean to use the -f switch?)\n");      
                        exit(EXIT_FAILURE);     
                }
                        fprintf(stderr, "ARGUMENT_ERROR - Did not recieve enough players (did you mean to use the -f switch?)\n");      
                        exit(EXIT_FAILURE);     
                }
-               Game::theGame = new Game(red,blue, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard);
+               Game::theGame = new Game(red,blue, graphics, stallTime, allowIllegal,log, reveal,maxTurns, printBoard, timeoutTime);
        }
        else
        {
        }
        else
        {
-               Game::theGame = new Game(inputFile, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard);
+               Game::theGame = new Game(inputFile, graphics, stallTime, allowIllegal,log, reveal,maxTurns, printBoard, timeoutTime);
        }
 
        if (Game::theGame == NULL)
        }
 
        if (Game::theGame == NULL)
@@ -247,7 +262,8 @@ void PrintResults(const MovementResult & result, string & buffer)
        {
                switch (result.type)
                {
        {
                switch (result.type)
                {
-                       case MovementResult::VICTORY:
+                       case MovementResult::VICTORY_FLAG:
+                       case MovementResult::VICTORY_ATTRITION: //It does not matter how you win, it just matters that you won!
                                s <<  "VICTORY ";
                                break;
                        case MovementResult::SURRENDER:
                                s <<  "VICTORY ";
                                break;
                        case MovementResult::SURRENDER:
index 5a2aed6..7cd9bf0 100644 (file)
@@ -13,7 +13,7 @@ class Piece;
 class MovementResult
 {
        public:
 class MovementResult
 {
        public:
-               typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, SURRENDER, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR, DRAW_DEFAULT, DRAW, BAD_SETUP} Type;
+               typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY_FLAG, VICTORY_ATTRITION, SURRENDER, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR, DRAW_DEFAULT, DRAW, BAD_SETUP} Type;
 
                MovementResult(const Type & result = OK, const Piece::Type & newAttackerRank = Piece::NOTHING, const Piece::Type & newDefenderRank = Piece::NOTHING)
                        : type(result), attackerRank(newAttackerRank), defenderRank(newDefenderRank) {}
 
                MovementResult(const Type & result = OK, const Piece::Type & newAttackerRank = Piece::NOTHING, const Piece::Type & newDefenderRank = Piece::NOTHING)
                        : type(result), attackerRank(newAttackerRank), defenderRank(newDefenderRank) {}
index 588f714..d5463f4 100644 (file)
@@ -140,12 +140,13 @@ bool Program::SendMessage(const char * print, ...)
  */
 bool Program::GetMessage(string & buffer, double timeout)
 {
  */
 bool Program::GetMessage(string & buffer, double timeout)
 {
-       if (!Running())
+       if (!Running() || timeout == 0)
                return false;
 
        assert(&buffer != NULL);
        GetterThread getterThread(input, buffer);
        assert(&(getterThread.buffer) != NULL);
                return false;
 
        assert(&buffer != NULL);
        GetterThread getterThread(input, buffer);
        assert(&(getterThread.buffer) != NULL);
+
        TimerThread timerThread(timeout*1000000);
 
        getterThread.Start();
        TimerThread timerThread(timeout*1000000);
 
        getterThread.Start();
@@ -164,7 +165,8 @@ bool Program::GetMessage(string & buffer, double timeout)
        }
 
        getterThread.Stop();
        }
 
        getterThread.Stop();
-       timerThread.Stop();
+       if (timeout > 0)
+               timerThread.Stop();
 
        
 
 
        
 
index e7cf60a..5acfaa3 100644 (file)
@@ -375,7 +375,7 @@ MovementResult Board::MovePiece(int x, int y, const Direction & direction, int m
                if (defender->type == Piece::FLAG)
                {
                        winner = target->colour;
                if (defender->type == Piece::FLAG)
                {
                        winner = target->colour;
-                       return MovementResult(MovementResult::VICTORY);
+                       return MovementResult(MovementResult::VICTORY_FLAG);
                }
                else if (defender->type == Piece::BOMB)
                {
                }
                else if (defender->type == Piece::BOMB)
                {
index c8f4f9d..d2e667f 100644 (file)
@@ -124,12 +124,12 @@ class Board
                
                static bool LegalResult(const MovementResult & result)
                {
                
                static bool LegalResult(const MovementResult & result)
                {
-                       return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE || result == MovementResult::VICTORY || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER);
+                       return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE || result == MovementResult::VICTORY_FLAG || result == MovementResult::VICTORY_ATTRITION || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER);
                }
 
                static bool HaltResult(const MovementResult & result)
                {
                }
 
                static bool HaltResult(const MovementResult & result)
                {
-                       return (result == MovementResult::VICTORY || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER || !LegalResult(result));
+                       return (result == MovementResult::VICTORY_FLAG || result == MovementResult::VICTORY_ATTRITION || result == MovementResult::DRAW || result == MovementResult::DRAW_DEFAULT || result == MovementResult::SURRENDER || !LegalResult(result));
                }               
 
                MovementResult MovePiece(int x, int y, const Direction & direction, int multiplier=1,const Piece::Colour & colour=Piece::NONE); //Move piece from position in direction
                }               
 
                MovementResult MovePiece(int x, int y, const Direction & direction, int multiplier=1,const Piece::Colour & colour=Piece::NONE); //Move piece from position in direction
index b84a525..b44012b 100755 (executable)
@@ -27,6 +27,8 @@ baseDirectory = "../.." #Base directory for results, logs, agents
 nGames = 2 #Number of games played by each agent against each opponent. Half will be played as RED, half as BLUE. If nGames <= 1, then no games will be played (useful for dry run?)
 nRounds = 1
 
 nGames = 2 #Number of games played by each agent against each opponent. Half will be played as RED, half as BLUE. If nGames <= 1, then no games will be played (useful for dry run?)
 nRounds = 1
 
+timeoutValue = 2
+
 if len(sys.argv) >= 2:
        nRounds = int(sys.argv[1])
 if len(sys.argv) >= 3:
 if len(sys.argv) >= 2:
        nRounds = int(sys.argv[1])
 if len(sys.argv) >= 3:
@@ -226,7 +228,7 @@ for roundNumber in range(totalRounds, totalRounds + nRounds):
                                if verbose:
                                        sys.stdout.write("Agents: \""+red["name"]+"\" and \""+blue["name"]+"\" playing game (ID: " + gameID + ") ... ")
                                logFile = logDirectory + "round"+str(roundNumber) + "/"+red["name"]+".vs."+blue["name"]+"."+str(gameID)
                                if verbose:
                                        sys.stdout.write("Agents: \""+red["name"]+"\" and \""+blue["name"]+"\" playing game (ID: " + gameID + ") ... ")
                                logFile = logDirectory + "round"+str(roundNumber) + "/"+red["name"]+".vs."+blue["name"]+"."+str(gameID)
-                               outline = os.popen(managerPath + " -o " + logFile + " " + red["path"] + " " + blue["path"], "r").read()
+                               outline = os.popen(managerPath + " -o " + logFile + " -T " + str(timeoutValue) + " " + red["path"] + " " + blue["path"], "r").read()
                                results = outline.split(' ')
                        
                                if len(results) != 6:
                                results = outline.split(' ')
                        
                                if len(results) != 6:
index 7a9c02c..bd9f0e1 100644 (file)
@@ -5,7 +5,7 @@ WARNING
        This program is still a work in progress. Consider it a Beta version.
 
 SYNOPSIS
        This program is still a work in progress. Consider it a Beta version.
 
 SYNOPSIS
-       stratego {[-gpirb] [-o output_file ] [-t stall_time] [-m max_turns] {red_player blue_player | -f input_file} | {-h | --help} }
+       stratego {[-gpirb] [-o output_file ] [-t stall_time] [-T timeout_time] [-m max_turns] {red_player blue_player | -f input_file} | {-h | --help} }
 
 DESCRIPTION
        stratego manages a game of Stratego. It stores the state of the board, and uses a simple protocol to interface with AI programs.
 
 DESCRIPTION
        stratego manages a game of Stratego. It stores the state of the board, and uses a simple protocol to interface with AI programs.
@@ -69,6 +69,15 @@ OPTIONS
                
                It is tentatively planned to allow the user to enter various commands to alter the game or proceed to specified turns.
                However this is slightly complicated. So it might never be done.
                
                It is tentatively planned to allow the user to enter various commands to alter the game or proceed to specified turns.
                However this is slightly complicated. So it might never be done.
+
+       -T
+               By default, stratego allows AI programs 2 seconds to respond before declaring their move ILLEGAL due to a timeout.
+               If the -T switch is present, AI programs will be allowed timeout_time to respond before their move is declared ILLEGAL.
+
+               If timeout_time is negative or "inf", stratego will never declare moves illegal due to timeouts.
+       
+               Human players are never subject to timeouts.
+               
        -m
                By default, the game is declared a Draw after 5000 turns have ellapsed.
                Use this option to change the maximum number of turns.
        -m
                By default, the game is declared a Draw after 5000 turns have ellapsed.
                Use this option to change the maximum number of turns.
@@ -116,11 +125,12 @@ GAME RULES
 
                Each player's pieces are hidden from the other player. When two pieces encounter each other, the ranks will be revealed.
 
 
                Each player's pieces are hidden from the other player. When two pieces encounter each other, the ranks will be revealed.
 
-               The objective is to destroy all Enemy Pieces (#) or capture the Enemy Flag (also #).
+               The objective is to either destroy all enemy pieces except the Bombs and Flag, or to capture the Flag.
 
                Since 20/12 Bombs reflect the traditional rules; they are only destroyed by Miners.
                In previous versions contact of an attacker other than a Miner with a Bomb destroyed the Bomb as well as the attacking piece.
                
 
                Since 20/12 Bombs reflect the traditional rules; they are only destroyed by Miners.
                In previous versions contact of an attacker other than a Miner with a Bomb destroyed the Bomb as well as the attacking piece.
                
+               
 
 PROTOCOL
        In order to interface with stratego, an AI program must satisfy the following protocol. 
 
 PROTOCOL
        In order to interface with stratego, an AI program must satisfy the following protocol. 
@@ -181,8 +191,10 @@ PROTOCOL
                
        
        4. TIMEOUTS
                
        
        4. TIMEOUTS
-               If a program fails to respond to a query within 2 (two) seconds, the game will end and that AI will be sent the ILLEGAL result.
+               If a program fails to respond to a query, the game will end and that AI will be sent the ILLEGAL result.
                Human players are not subject to the timeout restriction.
                Human players are not subject to the timeout restriction.
+
+               Please see the information on the -T switch.
                
                        
 
                
                        
 

UCC git Repository :: git.ucc.asn.au