--- /dev/null
+#include "game.h"
+
+using namespace std;
+
+
+
+Game* Game::theGame = NULL;
+
+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)
+{
+ static bool gameCreated = false;
+ if (gameCreated)
+ {
+ if (log != NULL)
+ fprintf(log, "ERROR - Game has already been created!\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);
+
+ if (strcmp(redPath, "human") == 0)
+ red = new Human_Controller(Piece::RED, graphicsEnabled);
+ else
+ red = new AI_Controller(Piece::RED, redPath);
+
+
+ if (strcmp(bluePath, "human") == 0)
+ blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
+ else
+ blue = new AI_Controller(Piece::BLUE, redPath);
+
+
+}
+
+Game::~Game()
+{
+ fprintf(stderr, "Killing AI\n");
+ delete red;
+ delete blue;
+
+ if (log != NULL && log != stdout && log != stderr)
+ fclose(log);
+}
+
+bool Game::Setup(const char * redName, const char * blueName)
+{
+
+ for (int y = 4; y < 6; ++y)
+ {
+ for (int x = 2; x < 4; ++x)
+ {
+ theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
+ }
+ for (int x = 6; x < 8; ++x)
+ {
+ theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
+ }
+ }
+
+
+ MovementResult redSetup = red->Setup(blueName);
+ MovementResult blueSetup = blue->Setup(redName);
+
+ if (redSetup != MovementResult::OK)
+ {
+ if (blueSetup != MovementResult::OK)
+ {
+ if (log != NULL)
+ fprintf(log, "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");
+ red->Message("ILLEGAL");
+ blue->Message("DEFAULT");
+ }
+ return false;
+ }
+ else if (blueSetup != MovementResult::OK)
+ {
+ if (log != NULL)
+ fprintf(log, "Player BLUE gave an invalid setup!\n");
+ red->Message("DEFAULT");
+ blue->Message("ILLEGAL");
+ return false;
+ }
+ return true;
+
+}
+
+void Game::Wait(double wait)
+{
+ if (wait <= 0)
+ return;
+
+ TimerThread timer(wait*1000000); //Wait in seconds
+ timer.Start();
+
+ if (!graphicsEnabled)
+ {
+ while (!timer.Finished());
+ timer.Stop();
+ return;
+ }
+
+
+ while (!timer.Finished())
+ {
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_QUIT:
+ timer.Stop();
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+ }
+ timer.Stop();
+
+}
+
+void Game::HandleBrokenPipe(int sig)
+{
+ if (theGame->turn == Piece::RED)
+ {
+ theGame->logMessage("Game ends on RED's turn - REASON: ");
+ theGame->blue->Message("DEFAULT");
+ }
+ else if (theGame->turn == Piece::BLUE)
+ {
+
+ theGame->logMessage("Game ends on BLUE's turn - REASON: ");
+ theGame->red->Message("DEFAULT");
+ }
+ else
+ {
+ theGame->logMessage("Game ends on ERROR's turn - REASON: ");
+
+ }
+
+ theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
+
+
+
+ if (Game::theGame->graphicsEnabled && theGame->log == stdout)
+ {
+ theGame->logMessage("CLOSE WINDOW TO EXIT\n");
+ Game::theGame->theBoard.Draw(Piece::BOTH);
+ while (true)
+ {
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (theGame->log == stdout)
+ {
+ theGame->logMessage( "PRESS ENTER TO EXIT\n");
+ theGame->theBoard.Print(theGame->log);
+ while (fgetc(stdin) != '\n');
+ }
+ }
+
+
+ exit(EXIT_SUCCESS);
+}
+
+void Game::PrintEndMessage(const MovementResult & result)
+{
+ if (turn == Piece::RED)
+ {
+ logMessage("Game ends on RED's turn - REASON: ");
+ }
+ else if (turn == Piece::BLUE)
+ {
+ logMessage("Game ends on BLUE's turn - REASON: ");
+ }
+ else
+ {
+ logMessage("Game ends on ERROR's turn - REASON: ");
+
+ }
+ switch (result.type)
+ {
+ case MovementResult::OK:
+ logMessage("Status returned OK, unsure why game halted...\n");
+ break;
+ case MovementResult::DIES:
+ logMessage("Status returned DIES, unsure why game halted...\n");
+ break;
+ case MovementResult::KILLS:
+ logMessage("Status returned KILLS, unsure why game halted...\n");
+ break;
+ case MovementResult::BOTH_DIE:
+ logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
+ break;
+ case MovementResult::NO_BOARD:
+ logMessage("Board does not exit?!\n");
+ break;
+ case MovementResult::INVALID_POSITION:
+ logMessage("Coords outside board\n");
+ break;
+ case MovementResult::NO_SELECTION:
+ logMessage("Move does not select a piece\n");
+ break;
+ case MovementResult::NOT_YOUR_UNIT:
+ logMessage("Selected piece belongs to other player\n");
+ break;
+ case MovementResult::IMMOBILE_UNIT:
+ logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
+ break;
+ case MovementResult::INVALID_DIRECTION:
+ logMessage("Selected unit cannot move that way\n");
+ break;
+ case MovementResult::POSITION_FULL:
+ logMessage("Attempted move into square occupied by allied piece\n");
+ break;
+ case MovementResult::VICTORY:
+ logMessage("Captured the flag\n");
+ break;
+ case MovementResult::BAD_RESPONSE:
+ logMessage("Unintelligable response\n");
+ break;
+ case MovementResult::NO_MOVE:
+ logMessage("Did not make a move (may have exited)\n");
+ break;
+ case MovementResult::COLOUR_ERROR:
+ logMessage("Internal controller error - COLOUR_ERROR\n");
+ break;
+ case MovementResult::ERROR:
+ logMessage("Internal controller error - Unspecified ERROR\n");
+ break;
+
+ }
+
+ if (graphicsEnabled && log == stdout)
+ {
+ logMessage("CLOSE WINDOW TO EXIT\n");
+ theBoard.Draw(Piece::BOTH);
+ while (true)
+ {
+ SDL_Event event;
+ while (SDL_PollEvent(&event))
+ {
+ switch (event.type)
+ {
+ case SDL_QUIT:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (log == stdout)
+ {
+ logMessage("PRESS ENTER TO EXIT\n");
+ while (fgetc(stdin) != '\n');
+ }
+ }
+
+}
+
+
+
+MovementResult Game::Play()
+{
+
+ MovementResult result = MovementResult::OK;
+ turnCount = 1;
+ string buffer;
+
+
+
+ red->Message("START");
+ logMessage("START");
+ while (Board::LegalResult(result))
+ {
+
+
+ turn = Piece::RED;
+ logMessage( "%d RED: ", turnCount);
+ result = red->MakeMove(buffer);
+ red->Message(buffer);
+ blue->Message(buffer);
+ logMessage( "%s\n", buffer.c_str());
+ if (!Board::LegalResult(result))
+ break;
+ if (graphicsEnabled)
+ theBoard.Draw(reveal);
+ Wait(stallTime);
+
+ turn = Piece::BLUE;
+ logMessage( "%d BLU: ", turnCount);
+ result = blue->MakeMove(buffer);
+ blue->Message(buffer);
+ red->Message(buffer);
+ logMessage( "%s\n", buffer.c_str());
+
+ if (!Board::LegalResult(result))
+ break;
+
+
+
+ if (graphicsEnabled)
+ theBoard.Draw(reveal);
+ Wait(stallTime);
+
+ ++turnCount;
+ }
+
+
+ return result;
+
+
+
+}
+
+/**
+ * Logs a message to the game's log file if it exists
+ * @param format the format string
+ * @param additional parameters - printed using va_args
+ * @returns the result of vfprintf or a negative number if the log file does not exist
+ */
+int Game::logMessage(const char * format, ...)
+{
+ if (log == NULL)
+ return -666;
+ va_list ap;
+ va_start(ap, format);
+
+ int result = vfprintf(log, format, ap);
+ va_end(ap);
+
+ return result;
+}