Commit b563784f authored by Sam Moore's avatar Sam Moore
Browse files

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??????????????
parent 4a3c0478
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
class AI_Controller : public Controller, private Program class AI_Controller : public Controller, private Program
{ {
public: 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() {} virtual ~AI_Controller() {}
...@@ -21,6 +21,8 @@ class AI_Controller : public Controller, private Program ...@@ -21,6 +21,8 @@ class AI_Controller : public Controller, private Program
virtual void Message(const char * message) {Program::SendMessage(message);} virtual void Message(const char * message) {Program::SendMessage(message);}
virtual bool Valid() const {return Program::Running();}
private: private:
const double timeout; //Timeout in seconds for messages from the AI Program const double timeout; //Timeout in seconds for messages from the AI Program
......
...@@ -51,7 +51,7 @@ MovementResult Controller::Setup(const char * opponentName) ...@@ -51,7 +51,7 @@ MovementResult Controller::Setup(const char * opponentName)
usedUnits[(int)(type)]++; usedUnits[(int)(type)]++;
if (usedUnits[type] > Piece::maxUnits[(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; return MovementResult::BAD_RESPONSE;
} }
Game::theGame->theBoard.AddPiece(x, yStart+y, type, colour); Game::theGame->theBoard.AddPiece(x, yStart+y, type, colour);
...@@ -107,7 +107,7 @@ MovementResult Controller::MakeMove(string & buffer) ...@@ -107,7 +107,7 @@ MovementResult Controller::MakeMove(string & buffer)
} }
else 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. return MovementResult::BAD_RESPONSE; //Player gave bogus direction - it will lose by default.
} }
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
class Controller class Controller
{ {
public: public:
Controller(const Piece::Colour & newColour) : colour(newColour) {} Controller(const Piece::Colour & newColour, const char * newName = "no-name") : colour(newColour), name(newName) {}
virtual ~Controller() {} virtual ~Controller() {}
MovementResult Setup(const char * opponentName); MovementResult Setup(const char * opponentName);
...@@ -26,9 +26,12 @@ class Controller ...@@ -26,9 +26,12 @@ class Controller
virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]) = 0; virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]) = 0;
virtual MovementResult QueryMove(std::string & buffer) = 0; virtual MovementResult QueryMove(std::string & buffer) = 0;
virtual bool Valid() const {return true;}
const Piece::Colour colour; const Piece::Colour colour;
std::string name;
}; };
......
...@@ -5,14 +5,14 @@ using namespace std; ...@@ -5,14 +5,14 @@ using namespace std;
Game* Game::theGame = NULL; 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 (gameCreated)
{ {
if (log != NULL) fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
fprintf(log, "ERROR - Game has already been created!\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
gameCreated = true; gameCreated = true;
...@@ -32,24 +32,62 @@ Game::Game(const char * redPath, const char * bluePath, const bool enableGraphic ...@@ -32,24 +32,62 @@ Game::Game(const char * redPath, const char * bluePath, const bool enableGraphic
if (strcmp(bluePath, "human") == 0) if (strcmp(bluePath, "human") == 0)
blue = new Human_Controller(Piece::BLUE, graphicsEnabled); blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
else 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() Game::~Game()
{ {
fprintf(stderr, "Killing AI\n");
delete red; delete red;
delete blue; delete blue;
if (log != NULL && log != stdout && log != stderr) if (log != NULL && log != stdout && log != stderr)
fclose(log); fclose(log);
if (input != NULL && input != stdin)
fclose(input);
} }
bool Game::Setup(const char * redName, const char * blueName) 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 y = 4; y < 6; ++y)
{ {
for (int x = 2; x < 4; ++x) for (int x = 2; x < 4; ++x)
...@@ -70,15 +108,13 @@ bool Game::Setup(const char * redName, const char * blueName) ...@@ -70,15 +108,13 @@ bool Game::Setup(const char * redName, const char * blueName)
{ {
if (blueSetup != MovementResult::OK) if (blueSetup != MovementResult::OK)
{ {
if (log != NULL) logMessage("BOTH players give invalid setup!\n");
fprintf(log, "BOTH players give invalid setup!\n");
red->Message("ILLEGAL"); red->Message("ILLEGAL");
blue->Message("ILLEGAL"); blue->Message("ILLEGAL");
} }
else else
{ {
if (log != NULL) logMessage("Player RED gave an invalid setup!\n");
fprintf(log, "Player RED gave an invalid setup!\n");
red->Message("ILLEGAL"); red->Message("ILLEGAL");
blue->Message("DEFAULT"); blue->Message("DEFAULT");
} }
...@@ -86,12 +122,29 @@ bool Game::Setup(const char * redName, const char * blueName) ...@@ -86,12 +122,29 @@ bool Game::Setup(const char * redName, const char * blueName)
} }
else if (blueSetup != MovementResult::OK) else if (blueSetup != MovementResult::OK)
{ {
if (log != NULL) logMessage("Player BLUE gave an invalid setup!\n");
fprintf(log, "Player BLUE gave an invalid setup!\n");
red->Message("DEFAULT"); red->Message("DEFAULT");
blue->Message("ILLEGAL"); blue->Message("ILLEGAL");
return false; 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; return true;
} }
...@@ -151,7 +204,8 @@ void Game::HandleBrokenPipe(int sig) ...@@ -151,7 +204,8 @@ void Game::HandleBrokenPipe(int sig)
theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n"); 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) if (Game::theGame->graphicsEnabled && theGame->log == stdout)
{ {
...@@ -250,9 +304,19 @@ void Game::PrintEndMessage(const MovementResult & result) ...@@ -250,9 +304,19 @@ void Game::PrintEndMessage(const MovementResult & result)
case MovementResult::ERROR: case MovementResult::ERROR:
logMessage("Internal controller error - Unspecified ERROR\n"); logMessage("Internal controller error - Unspecified ERROR\n");
break; 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) if (graphicsEnabled && log == stdout)
{ {
logMessage("CLOSE WINDOW TO EXIT\n"); logMessage("CLOSE WINDOW TO EXIT\n");
...@@ -294,8 +358,8 @@ MovementResult Game::Play() ...@@ -294,8 +358,8 @@ MovementResult Game::Play()
red->Message("START"); red->Message("START");
logMessage("START"); //logMessage("START\n");
while (Board::LegalResult(result)) while (Board::LegalResult(result) && (turnCount < maxTurns || maxTurns < 0))
{ {
...@@ -309,6 +373,13 @@ MovementResult Game::Play() ...@@ -309,6 +373,13 @@ MovementResult Game::Play()
break; break;
if (graphicsEnabled) if (graphicsEnabled)
theBoard.Draw(reveal); theBoard.Draw(reveal);
if (printBoard)
{
system("clear");
fprintf(stdout, "%d RED:\n", turnCount);
theBoard.PrintPretty(stdout, reveal);
fprintf(stdout, "\n\n");
}
Wait(stallTime); Wait(stallTime);
turn = Piece::BLUE; turn = Piece::BLUE;
...@@ -325,11 +396,25 @@ MovementResult Game::Play() ...@@ -325,11 +396,25 @@ MovementResult Game::Play()
if (graphicsEnabled) if (graphicsEnabled)
theBoard.Draw(reveal); theBoard.Draw(reveal);
if (printBoard)
{
system("clear");
fprintf(stdout, "%d BLUE:\n", turnCount);
theBoard.PrintPretty(stdout, reveal);
fprintf(stdout, "\n\n");
}
Wait(stallTime); Wait(stallTime);
++turnCount; ++turnCount;
} }
if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
{
result = MovementResult::DRAW;
turn = Piece::BOTH;
}
return result; return result;
...@@ -355,3 +440,49 @@ int Game::logMessage(const char * format, ...) ...@@ -355,3 +440,49 @@ int Game::logMessage(const char * format, ...)
return result; 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;
}
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
class Game class Game
{ {
public: 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(); virtual ~Game();
...@@ -32,10 +33,12 @@ class Game ...@@ -32,10 +33,12 @@ class Game
int TurnCount() const {return turnCount;} int TurnCount() const {return turnCount;}
static Game * theGame; static Game * theGame;
private: public:
int logMessage(const char * format, ...); int logMessage(const char * format, ...);
FILE * GetLogFile() const {return log;}
Controller * red; Controller * red;
Controller * blue; Controller * blue;
private:
Piece::Colour turn; Piece::Colour turn;
public: public:
...@@ -48,10 +51,36 @@ class Game ...@@ -48,10 +51,36 @@ class Game
private: private:
FILE * log; FILE * log;
Piece::Colour reveal; Piece::Colour reveal;
int turnCount; 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 #endif //MAIN_H
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
class Human_Controller : public Controller class Human_Controller : public Controller
{ {
public: 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 ~Human_Controller() {}
virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]); virtual MovementResult QuerySetup(const char * opponentName, std::string setup[]);
......
...@@ -10,11 +10,41 @@ ...@@ -10,11 +10,41 @@
using namespace std; using namespace std;
void CreateGame(int argc, char ** argv);
void DestroyGame();
void PrintResults(const MovementResult & result);
int main(int argc, char ** argv) 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; 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) for (int ii=1; ii < argc; ++ii)
{ {
if (argv[ii][0] == '-') if (argv[ii][0] == '-')
...@@ -31,10 +61,13 @@ int main(int argc, char ** argv) ...@@ -31,10 +61,13 @@ int main(int argc, char ** argv)
++ii; ++ii;
break; break;
case 'g': case 'g':
graphics = true; graphics = !graphics;
break;
case 'p':
printBoard = !printBoard;
break; break;
case 'i': case 'i':
allowIllegal = true; allowIllegal = !allowIllegal;
break; break;
case 'o': case 'o':
...@@ -69,6 +102,34 @@ int main(int argc, char ** argv) ...@@ -69,6 +102,34 @@ int main(int argc, char ** argv)
else else
reveal = Piece::NONE; reveal = Piece::NONE;
break; 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);
}
</