From: Sam Moore Date: Sat, 3 Dec 2011 12:55:43 +0000 (+0800) Subject: More adding of pointless crap to manager X-Git-Url: https://git.ucc.asn.au/?p=progcomp2012.git;a=commitdiff_plain;h=b563784f7e8b559fc100e174331c99fc6a1beda8 More adding of pointless crap to manager -f option to allow replaying of games output to files with -o -m option to enforce max number of turns (default 5000) before a DRAW is called -p to print a colourful representation of the board to stdout Yes. I now have both graphics AND pretty coloured terminal escape codes. Why did I do this?????????????? --- diff --git a/manager/ai_controller.h b/manager/ai_controller.h index 005043e..7d62591 100644 --- a/manager/ai_controller.h +++ b/manager/ai_controller.h @@ -11,7 +11,7 @@ class AI_Controller : public Controller, private Program { public: - AI_Controller(const Piece::Colour & newColour, const char * executablePath, const double newTimeout = 2.0) : Controller(newColour), Program(executablePath), timeout(newTimeout) {} + AI_Controller(const Piece::Colour & newColour, const char * executablePath, const double newTimeout = 2.0) : Controller(newColour, executablePath), Program(executablePath), timeout(newTimeout) {} virtual ~AI_Controller() {} @@ -21,6 +21,8 @@ class AI_Controller : public Controller, private Program virtual void Message(const char * message) {Program::SendMessage(message);} + virtual bool Valid() const {return Program::Running();} + private: const double timeout; //Timeout in seconds for messages from the AI Program diff --git a/manager/controller.cpp b/manager/controller.cpp index 1b70fb6..b7ab105 100644 --- a/manager/controller.cpp +++ b/manager/controller.cpp @@ -51,7 +51,7 @@ MovementResult Controller::Setup(const char * opponentName) usedUnits[(int)(type)]++; if (usedUnits[type] > Piece::maxUnits[(int)type]) { - fprintf(stderr, "Too many units of type %c\n", Piece::tokens[(int)(type)]); + //fprintf(stderr, "Too many units of type %c\n", Piece::tokens[(int)(type)]); return MovementResult::BAD_RESPONSE; } Game::theGame->theBoard.AddPiece(x, yStart+y, type, colour); @@ -107,7 +107,7 @@ MovementResult Controller::MakeMove(string & buffer) } else { - fprintf(stderr, "BAD_RESPONSE \"%s\"\n", buffer.c_str()); + //fprintf(stderr, "BAD_RESPONSE \"%s\"\n", buffer.c_str()); return MovementResult::BAD_RESPONSE; //Player gave bogus direction - it will lose by default. } diff --git a/manager/controller.h b/manager/controller.h index c7fe3d6..1a8ce02 100644 --- a/manager/controller.h +++ b/manager/controller.h @@ -12,7 +12,7 @@ class Controller { public: - Controller(const Piece::Colour & newColour) : colour(newColour) {} + Controller(const Piece::Colour & newColour, const char * newName = "no-name") : colour(newColour), name(newName) {} virtual ~Controller() {} MovementResult Setup(const char * opponentName); @@ -26,9 +26,12 @@ class Controller virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]) = 0; virtual MovementResult QueryMove(std::string & buffer) = 0; + virtual bool Valid() const {return true;} const Piece::Colour colour; + std::string name; + }; diff --git a/manager/game.cpp b/manager/game.cpp index 005983b..49c2c90 100644 --- a/manager/game.cpp +++ b/manager/game.cpp @@ -5,14 +5,14 @@ using namespace std; 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) : red(NULL), blue(NULL), turn(Piece::RED), theBoard(10,10), graphicsEnabled(enableGraphics), stallTime(newStallTime), allowIllegalMoves(allowIllegal), log(newLog), reveal(newReveal), turnCount(0) +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) { - static bool gameCreated = false; + gameCreated = false; if (gameCreated) { - if (log != NULL) - fprintf(log, "ERROR - Game has already been created!\n"); + fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n"); exit(EXIT_FAILURE); } gameCreated = true; @@ -32,24 +32,62 @@ Game::Game(const char * redPath, const char * bluePath, const bool enableGraphic if (strcmp(bluePath, "human") == 0) blue = new Human_Controller(Piece::BLUE, graphicsEnabled); else - blue = new AI_Controller(Piece::BLUE, redPath); + blue = new AI_Controller(Piece::BLUE, bluePath); + + +} + +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) +{ + gameCreated = false; + if (gameCreated) + { + fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n"); + exit(EXIT_FAILURE); + } + gameCreated = true; + Game::theGame = this; + signal(SIGPIPE, Game::HandleBrokenPipe); + + + if (graphicsEnabled && (!Graphics::Initialised())) + Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32); + + input = fopen(fromFile, "r"); + + red = new FileController(Piece::RED, input); + blue = new FileController(Piece::BLUE, input); } Game::~Game() { - fprintf(stderr, "Killing AI\n"); + delete red; delete blue; if (log != NULL && log != stdout && log != stderr) fclose(log); + + if (input != NULL && input != stdin) + fclose(input); } bool Game::Setup(const char * redName, const char * blueName) { + if (!red->Valid()) + { + logMessage("Controller for Player RED is invalid!\n"); + } + if (!blue->Valid()) + { + logMessage("Controller for Player BLUE is invalid!\n"); + } + if (!red->Valid() || !blue->Valid()) + return false; + for (int y = 4; y < 6; ++y) { for (int x = 2; x < 4; ++x) @@ -70,15 +108,13 @@ bool Game::Setup(const char * redName, const char * blueName) { if (blueSetup != MovementResult::OK) { - if (log != NULL) - fprintf(log, "BOTH players give invalid setup!\n"); + logMessage("BOTH players give invalid setup!\n"); red->Message("ILLEGAL"); blue->Message("ILLEGAL"); } else { - if (log != NULL) - fprintf(log, "Player RED gave an invalid setup!\n"); + logMessage("Player RED gave an invalid setup!\n"); red->Message("ILLEGAL"); blue->Message("DEFAULT"); } @@ -86,12 +122,29 @@ bool Game::Setup(const char * redName, const char * blueName) } else if (blueSetup != MovementResult::OK) { - if (log != NULL) - fprintf(log, "Player BLUE gave an invalid setup!\n"); + logMessage("Player BLUE gave an invalid setup!\n"); red->Message("DEFAULT"); blue->Message("ILLEGAL"); return false; } + + logMessage("%s RED SETUP\n", red->name.c_str()); + for (int y=0; y < 4; ++y) + { + for (int x=0; x < theBoard.Width(); ++x) + logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]); + logMessage("\n"); + } + + logMessage("%s BLUE SETUP\n", blue->name.c_str()); + for (int y=0; y < 4; ++y) + { + for (int x=0; x < theBoard.Width(); ++x) + logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4 + y)->type)]); + logMessage("\n"); + } + + return true; } @@ -151,7 +204,8 @@ void Game::HandleBrokenPipe(int sig) theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n"); - + if (Game::theGame->printBoard) + Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH); if (Game::theGame->graphicsEnabled && theGame->log == stdout) { @@ -250,9 +304,19 @@ void Game::PrintEndMessage(const MovementResult & result) case MovementResult::ERROR: logMessage("Internal controller error - Unspecified ERROR\n"); break; + case MovementResult::DRAW: + logMessage("Game declared a draw after %d turns\n", turnCount); + break; } + if (printBoard) + { + system("clear"); + fprintf(stdout, "%d Final State\n", turnCount); + theBoard.PrintPretty(stdout, Piece::BOTH); + fprintf(stdout, "\n"); + } if (graphicsEnabled && log == stdout) { logMessage("CLOSE WINDOW TO EXIT\n"); @@ -294,8 +358,8 @@ MovementResult Game::Play() red->Message("START"); - logMessage("START"); - while (Board::LegalResult(result)) + //logMessage("START\n"); + while (Board::LegalResult(result) && (turnCount < maxTurns || maxTurns < 0)) { @@ -309,6 +373,13 @@ MovementResult Game::Play() break; if (graphicsEnabled) theBoard.Draw(reveal); + if (printBoard) + { + system("clear"); + fprintf(stdout, "%d RED:\n", turnCount); + theBoard.PrintPretty(stdout, reveal); + fprintf(stdout, "\n\n"); + } Wait(stallTime); turn = Piece::BLUE; @@ -325,11 +396,25 @@ MovementResult Game::Play() if (graphicsEnabled) theBoard.Draw(reveal); + if (printBoard) + { + system("clear"); + fprintf(stdout, "%d BLUE:\n", turnCount); + theBoard.PrintPretty(stdout, reveal); + fprintf(stdout, "\n\n"); + } + Wait(stallTime); ++turnCount; } + if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK) + { + result = MovementResult::DRAW; + turn = Piece::BOTH; + } + return result; @@ -355,3 +440,49 @@ int Game::logMessage(const char * format, ...) return result; } + +MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[]) +{ + + char c = fgetc(file); + name = ""; + while (c != ' ') + { + name += c; + c = fgetc(file); + } + + while (fgetc(file) != '\n'); + + for (int y = 0; y < 4; ++y) + { + setup[y] = ""; + for (int x = 0; x < Game::theGame->theBoard.Width(); ++x) + { + setup[y] += fgetc(file); + } + + if (fgetc(file) != '\n') + { + return MovementResult::BAD_RESPONSE; + } + } + return MovementResult::OK; + + +} + +MovementResult FileController::QueryMove(std::string & buffer) +{ + char buf[BUFSIZ]; + + fgets(buf, sizeof(buf), file); + char * s = (char*)(buf); + while (*s != ':' && *s != '\0') + ++s; + + s += 2; + + buffer = string(s); + return MovementResult::OK; +} diff --git a/manager/game.h b/manager/game.h index 9a02044..f6d7b6b 100644 --- a/manager/game.h +++ b/manager/game.h @@ -13,7 +13,8 @@ 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); + 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); virtual ~Game(); @@ -32,10 +33,12 @@ class Game int TurnCount() const {return turnCount;} static Game * theGame; - private: + public: int logMessage(const char * format, ...); + FILE * GetLogFile() const {return log;} Controller * red; Controller * blue; + private: Piece::Colour turn; public: @@ -48,10 +51,36 @@ class Game private: FILE * log; + Piece::Colour reveal; int turnCount; + + static bool gameCreated; + + FILE * input; + + int maxTurns; + const bool printBoard; }; +class FileController : public Controller +{ + public: + FileController(const Piece::Colour & newColour, FILE * newFile) : Controller(newColour, "file"), file(newFile) {} + virtual ~FileController() {} + + virtual void Message(const char * string) {} //Don't send messages + virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]); + virtual MovementResult QueryMove(std::string & buffer); + virtual bool Valid() const {return file != NULL;} + + private: + FILE * file; + + +}; + + #endif //MAIN_H diff --git a/manager/human_controller.h b/manager/human_controller.h index c0df811..6d5292e 100644 --- a/manager/human_controller.h +++ b/manager/human_controller.h @@ -9,7 +9,7 @@ class Human_Controller : public Controller { public: - Human_Controller(const Piece::Colour & newColour, const bool enableGraphics) : Controller(newColour), graphicsEnabled(enableGraphics) {} + Human_Controller(const Piece::Colour & newColour, const bool enableGraphics) : Controller(newColour, "human"), graphicsEnabled(enableGraphics) {} virtual ~Human_Controller() {} virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]); diff --git a/manager/main.cpp b/manager/main.cpp index 6adc34d..01a7fab 100644 --- a/manager/main.cpp +++ b/manager/main.cpp @@ -10,11 +10,41 @@ using namespace std; +void CreateGame(int argc, char ** argv); +void DestroyGame(); +void PrintResults(const MovementResult & result); + int main(int argc, char ** argv) { + + + + if (argc == 1) + { + fprintf(stderr, "Usage: stratego [options] red blue\n"); + fprintf(stderr, " stratego --help\n"); + exit(EXIT_SUCCESS); + + } + CreateGame(argc, argv); + if (Game::theGame == NULL) + { + fprintf(stderr, "ERROR: Couldn't create a game!\n"); + exit(EXIT_FAILURE); + } + + MovementResult result = Game::theGame->Play(); + Game::theGame->PrintEndMessage(result); + PrintResults(result); + + exit(EXIT_SUCCESS); + return 0; +} +void CreateGame(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; + Piece::Colour reveal = Piece::BOTH; char * inputFile = NULL; int maxTurns = 5000; bool printBoard = false; for (int ii=1; ii < argc; ++ii) { if (argv[ii][0] == '-') @@ -31,10 +61,13 @@ int main(int argc, char ** argv) ++ii; break; case 'g': - graphics = true; + graphics = !graphics; + break; + case 'p': + printBoard = !printBoard; break; case 'i': - allowIllegal = true; + allowIllegal = !allowIllegal; break; case 'o': @@ -69,6 +102,34 @@ int main(int argc, char ** argv) else reveal = Piece::NONE; break; + case 'm': + if (argc - ii <= 1) + { + fprintf(stderr, "Expected max_turns value after -m switch!\n"); + exit(EXIT_FAILURE); + } + if (strcmp(argv[ii+1], "inf")) + maxTurns = -1; + else + maxTurns = atoi(argv[ii+1]); + ++ii; + break; + case 'f': + if (argc - ii <= 1) + { + fprintf(stderr, "Expected filename after -f switch!\n"); + exit(EXIT_FAILURE); + } + if (log != NULL) + { + fprintf(stderr, "Expected at most ONE -f switch!\n"); + exit(EXIT_FAILURE); + } + red = (char*)("file"); + blue = (char*)("file"); + inputFile = argv[ii+1]; + ++ii; + break; case 'h': system("clear"); system("less manual.txt"); @@ -102,27 +163,28 @@ int main(int argc, char ** argv) } } } - if (argc == 1) + + if (inputFile == NULL) { - fprintf(stderr, "Usage: stratego [options] red blue\n"); - fprintf(stderr, " stratego --help\n"); - exit(EXIT_SUCCESS); - + Game::theGame = new Game(red,blue, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard); } - - Game game(red, blue, graphics, timeout, allowIllegal, log, reveal); - - - if (!game.Setup(red, blue)) + else + { + Game::theGame = new Game(inputFile, graphics, timeout, allowIllegal,log, reveal,maxTurns, printBoard); + } + if (!Game::theGame->Setup(red, blue)) { - fprintf(stdout, "NONE %d\n",game.TurnCount()); + fprintf(stdout, "NONE %d\n",Game::theGame->TurnCount()); exit(EXIT_SUCCESS); } + + atexit(DestroyGame); - MovementResult result = game.Play(); - game.PrintEndMessage(result); +} - Piece::Colour winner = game.Turn(); +void PrintResults(const MovementResult & result) +{ + Piece::Colour winner = Game::theGame->Turn(); if (Board::LegalResult(result)) { if (winner == Piece::BOTH) @@ -140,28 +202,27 @@ int main(int argc, char ** argv) switch (winner) { case Piece::RED: - fprintf(stdout, "%s RED %d\n", red,game.TurnCount()); + fprintf(stdout, "%s RED %d\n", Game::theGame->red->name.c_str(),Game::theGame->TurnCount()); + Game::theGame->logMessage("%s RED %d\n", Game::theGame->red->name.c_str(),Game::theGame->TurnCount()); break; case Piece::BLUE: - fprintf(stdout, "%s BLUE %d\n", blue,game.TurnCount()); + fprintf(stdout, "%s BLUE %d\n", Game::theGame->blue->name.c_str(),Game::theGame->TurnCount()); + Game::theGame->logMessage("%s BLUE %d\n", Game::theGame->blue->name.c_str(),Game::theGame->TurnCount()); break; case Piece::BOTH: - fprintf(stdout, "DRAW %d\n",game.TurnCount()); + fprintf(stdout, "DRAW %d\n",Game::theGame->TurnCount()); + Game::theGame->logMessage("DRAW %d\n",Game::theGame->TurnCount()); break; case Piece::NONE: - fprintf(stdout, "NONE %d\n",game.TurnCount()); + fprintf(stdout, "NONE %d\n",Game::theGame->TurnCount()); + Game::theGame->logMessage("NONE %d\n",Game::theGame->TurnCount()); break; } - - - - - - - exit(EXIT_SUCCESS); - - return 0; } - +void DestroyGame() +{ + delete Game::theGame; + Game::theGame = NULL; +} diff --git a/manager/manual.txt b/manager/manual.txt index 5eb1e8a..55a8f05 100644 --- a/manager/manual.txt +++ b/manager/manual.txt @@ -5,14 +5,14 @@ WARNING This program is still a work in progress. Consider it a Beta version. SYNOPSIS - stratego {[-girb] [-o= output_file ] [-t= stall_time] red_player blue_player | {-h | --help}} + stratego {[-gpirb] [-o output_file ] [-t stall_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. By itself, stratego does not "play" the game. An external AI program must be used. stratego is intended to be used for the testing of various AI strategies, written in any programming language. It will be used for the UCC Programming Competition 2012. - Unless -h, or --help is given, both red_player and blue_player must be supplied. + Unless the -h (--help) or -f switch is given, both red_player and blue_player must be supplied. red_player Should be either a path to an executable file which will control the Red player, or "human". @@ -27,6 +27,10 @@ DESCRIPTION OPTIONS -g By default, graphics are disabled. If the -g switch is present, stratego will draw the game as it is played using OpenGL + -p + By default, even if graphics are disabled, the board state is not printed. If -p is present, the board will be printed to stdout. + If the system supports colour, the characters will be in colour. + If -p and -g are both present you will see both behaviours (overkill)! -i By default, stratego will exit if a move which is deemed "illegal" is made. If the -i switch is present, illegal moves will be ignored. That is, the move will not be made (effectively the player making the illegal move loses a turn). @@ -42,8 +46,22 @@ OPTIONS -t By default, stratego executes moves as fast as they are recieved. If the -t switch is present, a delay of stall_time will be introduced between each move. + + -m + By default, the game is declared a Draw after 5000 turns have ellapsed. + Use this option to change the maximum number of turns. + To play for an infinite number of turns, supply "inf" as max_number. + + -f + By default, stratego requires red_player and blue_player to enact a game. + If this option is supplied, a file previously produced by using the -o switch is read, and the game reenacted. + All switches function as normal with -f. + NOTE: It is recommended that -g is used with -f. + -h, --help - If the -h switch is present, this page will be printed and stratego will exit. + If the -h switch is used, this page will be printed and stratego will exit. + + GAME RULES Each player sets up 40 pieces on the Board. The pieces consist of the following: diff --git a/manager/movementresult.h b/manager/movementresult.h index 4056a71..695a1e2 100644 --- a/manager/movementresult.h +++ b/manager/movementresult.h @@ -13,7 +13,7 @@ class Piece; 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, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR} Type; + typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, BAD_RESPONSE, NO_MOVE, COLOUR_ERROR, ERROR, DRAW} Type; MovementResult(const Type & result = OK, const Piece::Type & newAttackerRank = Piece::NOTHING, const Piece::Type & newDefenderRank = Piece::NOTHING) : type(result), attackerRank(newAttackerRank), defenderRank(newDefenderRank) {} diff --git a/manager/program.cpp b/manager/program.cpp index 8b4e4af..acf501e 100644 --- a/manager/program.cpp +++ b/manager/program.cpp @@ -72,7 +72,7 @@ Program::~Program() if (kill(pid, 0) == 0) //Check if the process created is still running... { fputc(EOF, output); //If it was, tell it to stop with EOF - sleep(1); //Give it 1 second to respond... + usleep(500000); //Give it 1/2 a second to respond... if (kill(pid, 0) == 0) //Check if its still running { kill(pid, 9); //Slay the infidel mercilessly! diff --git a/manager/stratego.cpp b/manager/stratego.cpp index 37df4d2..d84819f 100644 --- a/manager/stratego.cpp +++ b/manager/stratego.cpp @@ -92,7 +92,7 @@ Board::~Board() /** * Print textual representation of the board to a stream * @param stream - the stream to print information to - * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' or '*' for RED or BLUE respectively. + * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' */ void Board::Print(FILE * stream, const Piece::Colour & reveal) { @@ -107,26 +107,89 @@ void Board::Print(FILE * stream, const Piece::Colour & reveal) } else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH)) { + fprintf(stream, "%c", Piece::tokens[piece->type]); + + } else { switch (piece->colour) { case Piece::RED: + case Piece::BLUE: fprintf(stream, "#"); + break; + case Piece::NONE: + fprintf(stream, "+"); + break; + case Piece::BOTH: + fprintf(stream, "$"); + break; + } + } + } + fprintf(stream, "\n"); + } + +} + +/** + * Print textual representation of the board to a stream + * @param stream - the stream to print information to + * @param reveal - Pieces matching this colour will have their identify revealed, other pieces will be shown as '#' + */ +void Board::PrintPretty(FILE * stream, const Piece::Colour & reveal) +{ + for (int y=0; y < height; ++y) + { + for (int x=0; x < width; ++x) + { + Piece * piece = board[x][y]; + if (piece == NULL) + { + fprintf(stream, "."); + } + else if (piece->colour != Piece::NONE && (piece->colour == reveal || reveal == Piece::BOTH)) + { + switch (piece->colour) + { + case Piece::RED: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,40); + break; + case Piece::BLUE: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,40); + break; + default: + break; + } + fprintf(stream, "%c", Piece::tokens[piece->type]); + + } + else + { + switch (piece->colour) + { + case Piece::RED: + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,31,41); + break; case Piece::BLUE: - fprintf(stream, "*"); + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,34,44); break; case Piece::NONE: - fprintf(stream, "+"); + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,37,47); break; case Piece::BOTH: - fprintf(stream, "$"); //Should never see these! + //Should never see this + fprintf(stream, "%c[%d;%d;%dm",0x1B,1,33,43); break; - } + + } + fprintf(stream, "#"); + } + fprintf(stream, "%c[%d;%d;%dm",0x1B,0,7,0); } fprintf(stream, "\n"); } diff --git a/manager/stratego.h b/manager/stratego.h index 6f0f8fe..39e8873 100644 --- a/manager/stratego.h +++ b/manager/stratego.h @@ -101,6 +101,7 @@ class Board virtual ~Board(); //Destructor void Print(FILE * stream, const Piece::Colour & reveal=Piece::BOTH); //Print board + void PrintPretty(FILE * stream, const Piece::Colour & reveal=Piece::BOTH); //Print board using colour void Draw(const Piece::Colour & reveal=Piece::BOTH); //Draw board @@ -117,7 +118,7 @@ class Board static bool LegalResult(const MovementResult & result) { - return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE); + return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE || result == MovementResult::VICTORY || result == MovementResult::DRAW); } MovementResult MovePiece(int x, int y, const Direction & direction, int multiplier=1,const Piece::Colour & colour=Piece::NONE); //Move piece from position in direction diff --git a/manager/test.out b/manager/test.out new file mode 100644 index 0000000..cf21bfb --- /dev/null +++ b/manager/test.out @@ -0,0 +1,342 @@ +forfax RED SETUP +FB8sB479B8 +BB31555583 +6724898974 +967B669999 +dummy BLUE SETUP +967B669999 +6724898974 +BB31555583 +FB8sB479B8 +1 RED: 9 3 DOWN OK +1 BLU: 1 6 UP OK +2 RED: 9 4 DOWN OK +2 BLU: 8 6 UP OK +3 RED: 9 5 DOWN DIES 9 9 +3 BLU: 2 6 LEFT OK +4 RED: 8 3 DOWN OK +4 BLU: 0 6 UP OK +5 RED: 8 2 DOWN OK +5 BLU: 0 7 UP OK +6 RED: 9 2 LEFT OK +6 BLU: 1 5 UP OK +7 RED: 8 4 DOWN KILLS 9 9 +7 BLU: 4 6 UP OK +8 RED: 4 3 DOWN OK +8 BLU: 7 6 RIGHT OK +9 RED: 5 3 LEFT OK +9 BLU: 0 6 DOWN OK +10 RED: 5 2 DOWN OK +10 BLU: 1 4 UP DIES 6 6 +11 RED: 8 5 DOWN DIES 9 9 +11 BLU: 6 6 RIGHT OK +12 RED: 4 4 DOWN DIES 6 6 +12 BLU: 9 6 UP OK +13 RED: 9 1 DOWN OK +13 BLU: 1 6 LEFT OK +14 RED: 8 1 RIGHT OK +14 BLU: 6 7 UP OK +15 RED: 8 3 RIGHT OK +15 BLU: 1 7 UP OK +16 RED: 8 2 DOWN OK +16 BLU: 0 5 RIGHT OK +17 RED: 9 3 DOWN OK +17 BLU: 1 5 UP OK +18 RED: 9 2 DOWN OK +18 BLU: 6 8 UP OK +19 RED: 9 4 DOWN KILLS 7 9 +19 BLU: 0 6 UP OK +20 RED: 5 1 DOWN OK +20 BLU: 9 7 UP OK +21 RED: 4 3 DOWN OK +21 BLU: 6 9 UP OK +22 RED: 9 5 DOWN DIES 7 4 +22 BLU: 9 8 UP OK +23 RED: 1 3 DOWN KILLS 6 9 +23 BLU: 6 8 DOWN OK +24 RED: 0 3 RIGHT OK +24 BLU: 6 7 DOWN OK +25 RED: 4 4 DOWN DIES 6 6 +25 BLU: 9 9 UP OK +26 RED: 6 1 LEFT OK +26 BLU: 5 6 UP OK +27 RED: 8 3 DOWN OK +27 BLU: 8 6 UP OK +28 RED: 9 1 DOWN OK +28 BLU: 0 5 RIGHT OK +29 RED: 8 4 DOWN KILLS 4 9 +29 BLU: 1 5 UP DIES 7 6 +30 RED: 9 3 DOWN OK +30 BLU: 4 5 UP OK +31 RED: 7 1 LEFT OK +31 BLU: 5 5 UP OK +32 RED: 5 3 DOWN DIES 9 6 +32 BLU: 4 7 UP OK +33 RED: 5 2 DOWN OK +33 BLU: 5 4 UP DIES 6 5 +34 RED: 8 5 DOWN OK +34 BLU: 7 6 RIGHT DIES 9 4 +35 RED: 5 3 LEFT OK +35 BLU: 8 7 UP DIES 7 4 +36 RED: 9 4 DOWN OK +36 BLU: 6 6 DOWN OK +37 RED: 4 3 DOWN KILLS 5 6 +37 BLU: 8 8 UP OK +38 RED: 9 5 DOWN KILLS 3 4 +38 BLU: 7 8 RIGHT OK +39 RED: 8 6 LEFT OK +39 BLU: 7 9 UP OK +40 RED: 9 6 DOWN KILLS 3 3 +40 BLU: 7 7 UP DIES 9 4 +41 RED: 6 3 LEFT OK +41 BLU: 9 8 UP DIES 8 3 +42 RED: 9 7 LEFT KILLS 3 8 +42 BLU: 6 9 RIGHT OK +43 RED: 7 6 DOWN OK +43 BLU: 5 7 UP OK +44 RED: 8 7 DOWN KILLS 3 5 +44 BLU: 3 7 RIGHT OK +45 RED: 7 7 LEFT KILLS 4 8 +45 BLU: 4 6 UP OK +46 RED: 4 4 DOWN KILLS 5 8 +46 BLU: 6 8 UP DIES 5 4 +47 RED: 5 3 DOWN OK +47 BLU: 3 8 UP OK +48 RED: 8 8 LEFT KILLS 3 9 +48 BLU: 3 9 UP OK +49 RED: 6 7 DOWN OK +49 BLU: 0 7 RIGHT OK +50 RED: 6 8 LEFT KILLS 4 5 +50 BLU: 3 8 DOWN OK +51 RED: 7 8 DOWN KILLS 3 7 +51 BLU: 1 6 LEFT OK +52 RED: 5 8 LEFT KILLS 4 5 +52 BLU: 2 8 RIGHT OK +53 RED: 5 4 LEFT OK +53 BLU: 3 8 LEFT OK +54 RED: 7 9 RIGHT BOTHDIE 3 B +54 BLU: 1 7 LEFT OK +55 RED: 4 8 DOWN BOTHDIE 4 B +55 BLU: 2 8 RIGHT OK +56 RED: 4 2 DOWN OK +56 BLU: 2 9 UP OK +57 RED: 7 3 LEFT OK +57 BLU: 2 8 DOWN OK +58 RED: 6 2 LEFT OK +58 BLU: 2 9 UP OK +59 RED: 1 4 DOWN OK +59 BLU: 2 8 DOWN OK +60 RED: 7 2 LEFT OK +60 BLU: 2 7 UP OK +61 RED: 1 3 DOWN OK +61 BLU: 2 9 UP OK +62 RED: 4 5 RIGHT OK +62 BLU: 2 8 UP OK +63 RED: 4 4 DOWN OK +63 BLU: 3 9 LEFT OK +64 RED: 2 3 LEFT OK +64 BLU: 3 8 DOWN OK +65 RED: 2 2 DOWN OK +65 BLU: 3 7 DOWN OK +66 RED: 1 5 DOWN OK +66 BLU: 2 6 LEFT KILLS 2 6 +67 RED: 4 3 DOWN OK +67 BLU: 3 8 LEFT OK +68 RED: 6 3 LEFT OK +68 BLU: 3 9 RIGHT OK +69 RED: 4 5 DOWN OK +69 BLU: 2 9 RIGHT OK +70 RED: 4 6 LEFT BOTHDIE 9 B +70 BLU: 4 9 UP OK +71 RED: 1 4 DOWN OK +71 BLU: 2 8 DOWN OK +72 RED: 6 2 DOWN OK +72 BLU: 2 9 UP OK +73 RED: 5 3 DOWN OK +73 BLU: 3 9 LEFT OK +74 RED: 5 2 DOWN OK +74 BLU: 0 6 UP OK +75 RED: 1 2 RIGHT OK +75 BLU: 0 7 RIGHT OK +76 RED: 4 4 DOWN OK +76 BLU: 5 9 LEFT OK +77 RED: 7 0 DOWN OK +77 BLU: 1 7 LEFT OK +78 RED: 1 3 DOWN OK +78 BLU: 2 8 RIGHT OK +79 RED: 5 5 DOWN KILLS 5 9 +79 BLU: 4 8 RIGHT OK +80 RED: 5 4 DOWN OK +80 BLU: 2 9 RIGHT OK +81 RED: 4 5 DOWN OK +81 BLU: 3 9 LEFT OK +82 RED: 0 2 RIGHT OK +82 BLU: 0 5 RIGHT KILLS 7 9 +83 RED: 2 3 LEFT OK +83 BLU: 2 9 RIGHT OK +84 RED: 3 2 RIGHT OK +84 BLU: 3 9 LEFT OK +85 RED: 4 6 DOWN DIES 8 4 +85 BLU: 1 5 LEFT OK +86 RED: 5 6 RIGHT OK +86 BLU: 0 5 RIGHT OK +87 RED: 3 1 DOWN OK +87 BLU: 0 7 RIGHT OK +88 RED: 4 1 LEFT OK +88 BLU: 3 8 UP OK +89 RED: 5 5 LEFT OK +89 BLU: 1 7 LEFT OK +90 RED: 6 6 DOWN OK +90 BLU: 2 7 UP OK +91 RED: 5 3 DOWN OK +91 BLU: 2 6 RIGHT OK +92 RED: 6 3 LEFT OK +92 BLU: 1 6 DOWN OK +93 RED: 4 5 DOWN OK +93 BLU: 2 9 RIGHT OK +94 RED: 6 7 DOWN OK +94 BLU: 3 6 LEFT OK +95 RED: 6 8 LEFT DIES 5 3 +95 BLU: 4 9 RIGHT OK +96 RED: 9 0 DOWN OK +96 BLU: 5 8 LEFT OK +97 RED: 4 6 LEFT OK +97 BLU: 4 8 DOWN OK +98 RED: 1 4 DOWN KILLS 7 7 +98 BLU: 3 9 LEFT OK +99 RED: 2 2 DOWN OK +99 BLU: 0 7 UP OK +100 RED: 3 6 DOWN DIES 9 1 +100 BLU: 4 7 RIGHT OK +101 RED: 2 1 DOWN OK +101 BLU: 2 9 RIGHT OK +102 RED: 2 0 DOWN OK +102 BLU: 3 9 LEFT OK +103 RED: 5 4 LEFT OK +103 BLU: 2 9 RIGHT OK +104 RED: 1 5 DOWN OK +104 BLU: 1 7 LEFT OK +105 RED: 5 3 LEFT OK +105 BLU: 3 9 UP OK +106 RED: 1 6 RIGHT KILLS 7 8 +106 BLU: 0 7 RIGHT OK +107 RED: 1 3 DOWN OK +107 BLU: 3 7 LEFT OK +108 RED: 1 2 DOWN OK +108 BLU: 1 7 LEFT OK +109 RED: 2 2 LEFT OK +109 BLU: 4 9 LEFT OK +110 RED: 2 1 DOWN OK +110 BLU: 3 9 LEFT OK +111 RED: 1 4 DOWN OK +111 BLU: 2 9 RIGHT OK +112 RED: 1 5 DOWN OK +112 BLU: 3 9 LEFT OK +113 RED: 1 3 DOWN OK +113 BLU: 2 9 UP OK +114 RED: 1 4 DOWN OK +114 BLU: 2 8 DOWN OK +115 RED: 2 3 LEFT OK +115 BLU: 5 9 LEFT OK +116 RED: 1 3 DOWN OK +116 BLU: 0 7 RIGHT OK +117 RED: 2 2 DOWN OK +117 BLU: 2 7 RIGHT OK +118 RED: 2 3 LEFT OK +118 BLU: 3 8 DOWN OK +119 RED: 1 6 DOWN DIES 2 2 +119 BLU: 4 9 RIGHT OK +120 RED: 2 6 LEFT OK +120 BLU: 2 9 UP OK +121 RED: 3 2 LEFT OK +121 BLU: 5 9 LEFT OK +122 RED: 2 2 DOWN OK +122 BLU: 1 7 LEFT OK +123 RED: 3 1 LEFT OK +123 BLU: 0 6 RIGHT KILLS 6 7 +124 RED: 1 5 DOWN DIES 6 6 +124 BLU: 4 9 RIGHT OK +125 RED: 2 1 DOWN OK +125 BLU: 3 9 LEFT OK +126 RED: 2 2 RIGHT OK +126 BLU: 2 8 RIGHT OK +127 RED: 3 2 UP OK +127 BLU: 5 9 LEFT OK +128 RED: 4 2 RIGHT OK +128 BLU: 0 7 RIGHT OK +129 RED: 3 1 LEFT OK +129 BLU: 1 7 LEFT OK +130 RED: 2 1 DOWN OK +130 BLU: 0 7 RIGHT OK +131 RED: 2 2 RIGHT OK +131 BLU: 1 7 LEFT OK +132 RED: 3 2 RIGHT OK +132 BLU: 2 9 RIGHT OK +133 RED: 5 1 LEFT OK +133 BLU: 3 9 LEFT OK +134 RED: 4 1 LEFT OK +134 BLU: 0 7 RIGHT OK +135 RED: 3 1 LEFT OK +135 BLU: 1 7 LEFT OK +136 RED: 2 1 DOWN OK +136 BLU: 2 9 RIGHT OK +137 RED: 2 2 RIGHT OK +137 BLU: 3 9 LEFT OK +138 RED: 4 2 UP OK +138 BLU: 2 9 RIGHT OK +139 RED: 3 2 RIGHT OK +139 BLU: 3 9 LEFT OK +140 RED: 4 1 LEFT OK +140 BLU: 2 9 RIGHT OK +141 RED: 3 1 LEFT OK +141 BLU: 0 7 RIGHT OK +142 RED: 2 1 DOWN OK +142 BLU: 3 9 LEFT OK +143 RED: 4 2 UP OK +143 BLU: 3 8 DOWN OK +144 RED: 2 2 RIGHT OK +144 BLU: 2 9 UP OK +145 RED: 4 1 LEFT OK +145 BLU: 4 9 RIGHT OK +146 RED: 3 1 LEFT OK +146 BLU: 5 9 LEFT OK +147 RED: 2 1 DOWN OK +147 BLU: 3 9 LEFT OK +148 RED: 3 2 RIGHT OK +148 BLU: 1 6 LEFT OK +149 RED: 2 2 RIGHT OK +149 BLU: 1 7 LEFT OK +150 RED: 3 2 UP OK +150 BLU: 2 8 RIGHT OK +151 RED: 3 1 LEFT OK +151 BLU: 2 9 RIGHT OK +152 RED: 2 1 DOWN OK +152 BLU: 3 9 LEFT OK +153 RED: 2 2 RIGHT OK +153 BLU: 2 9 RIGHT OK +154 RED: 4 4 DOWN OK +154 BLU: 3 9 LEFT OK +155 RED: 3 2 UP OK +155 BLU: 2 9 RIGHT OK +156 RED: 3 1 LEFT OK +156 BLU: 0 7 RIGHT OK +157 RED: 2 1 DOWN OK +157 BLU: 3 9 LEFT OK +158 RED: 2 2 RIGHT OK +158 BLU: 2 9 RIGHT OK +159 RED: 4 5 DOWN OK +159 BLU: 3 9 LEFT OK +160 RED: 4 6 LEFT OK +160 BLU: 4 9 LEFT OK +161 RED: 3 2 UP OK +161 BLU: 2 9 UP OK +162 RED: 3 6 LEFT OK +162 BLU: 3 8 RIGHT OK +163 RED: 3 1 LEFT OK +163 BLU: 3 9 LEFT OK +164 RED: 2 1 DOWN OK +164 BLU: 2 9 RIGHT OK +165 RED: 2 2 RIGHT OK +165 BLU: 1 9 UP ILLEGAL +Game ends on BLUE's turn - REASON: Selected piece is not mobile (FLAG or BOMB) +forfax RED 165 diff --git a/samples/forfax/forfax.cpp b/samples/forfax/forfax.cpp index eb44960..a7e233b 100644 --- a/samples/forfax/forfax.cpp +++ b/samples/forfax/forfax.cpp @@ -605,7 +605,7 @@ Forfax::Status Forfax::MakeMove() //Print chosen move to stdout cout << choice.piece->x << " " << choice.piece->y << " " << direction << "\n"; - cerr << "\nForfax move " << choice.piece->x << " " << choice.piece->y << " " << direction << " [score = " << choice.score << "]\n"; + //cerr << "\nForfax move " << choice.piece->x << " " << choice.piece->y << " " << direction << " [score = " << choice.score << "]\n"; diff --git a/samples/forfax/main.cpp b/samples/forfax/main.cpp index f3678e8..5fea5e7 100644 --- a/samples/forfax/main.cpp +++ b/samples/forfax/main.cpp @@ -42,6 +42,7 @@ int main(int argc, char ** argv) move = forfax.MakeMove(); } + /* switch (move) { case Forfax::OK: @@ -76,11 +77,11 @@ int main(int argc, char ** argv) cerr << argv[0] << " Error - An error occurred with the board!\n"; break; } + */ + //cerr << "Final board state:\n"; + //forfax.PrintBoard(cerr); - cerr << "Final board state:\n"; - forfax.PrintBoard(cerr); - - cerr << "Forfax is now exiting!\n"; + //cerr << "Forfax is now exiting!\n"; exit(EXIT_SUCCESS);