7 Game* Game::theGame = NULL;
8 bool Game::gameCreated = false;
10 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)
15 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
20 signal(SIGPIPE, Game::HandleBrokenPipe);
23 if (graphicsEnabled && (!Graphics::Initialised()))
24 Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32);
26 if (strcmp(redPath, "human") == 0)
27 red = new Human_Controller(Piece::RED, graphicsEnabled);
29 red = new AI_Controller(Piece::RED, redPath);
32 if (strcmp(bluePath, "human") == 0)
33 blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
35 blue = new AI_Controller(Piece::BLUE, bluePath);
40 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)
45 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
50 signal(SIGPIPE, Game::HandleBrokenPipe);
53 if (graphicsEnabled && (!Graphics::Initialised()))
54 Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32);
56 input = fopen(fromFile, "r");
58 red = new FileController(Piece::RED, input);
59 blue = new FileController(Piece::BLUE, input);
70 if (log != NULL && log != stdout && log != stderr)
73 if (input != NULL && input != stdin)
77 bool Game::Setup(const char * redName, const char * blueName)
82 logMessage("Controller for Player RED is invalid!\n");
86 logMessage("Controller for Player BLUE is invalid!\n");
88 if (!red->Valid() || !blue->Valid())
91 for (int y = 4; y < 6; ++y)
93 for (int x = 2; x < 4; ++x)
95 theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
97 for (int x = 6; x < 8; ++x)
99 theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
104 MovementResult redSetup = red->Setup(blueName);
105 MovementResult blueSetup = blue->Setup(redName);
107 if (redSetup != MovementResult::OK)
109 if (blueSetup != MovementResult::OK)
111 logMessage("BOTH players give invalid setup!\n");
112 red->Message("ILLEGAL");
113 blue->Message("ILLEGAL");
117 logMessage("Player RED gave an invalid setup!\n");
118 red->Message("ILLEGAL");
119 blue->Message("DEFAULT");
123 else if (blueSetup != MovementResult::OK)
125 logMessage("Player BLUE gave an invalid setup!\n");
126 red->Message("DEFAULT");
127 blue->Message("ILLEGAL");
131 logMessage("%s RED SETUP\n", red->name.c_str());
132 for (int y=0; y < 4; ++y)
134 for (int x=0; x < theBoard.Width(); ++x)
135 logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
139 logMessage("%s BLUE SETUP\n", blue->name.c_str());
140 for (int y=0; y < 4; ++y)
142 for (int x=0; x < theBoard.Width(); ++x)
143 logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4 + y)->type)]);
152 void Game::Wait(double wait)
157 TimerThread timer(wait*1000000); //Wait in seconds
160 if (!graphicsEnabled)
162 while (!timer.Finished());
168 while (!timer.Finished())
171 while (SDL_PollEvent(&event))
186 void Game::HandleBrokenPipe(int sig)
188 if (theGame->turn == Piece::RED)
190 theGame->logMessage("Game ends on RED's turn - REASON: ");
191 theGame->blue->Message("DEFAULT");
193 else if (theGame->turn == Piece::BLUE)
196 theGame->logMessage("Game ends on BLUE's turn - REASON: ");
197 theGame->red->Message("DEFAULT");
201 theGame->logMessage("Game ends on ERROR's turn - REASON: ");
205 theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
207 if (Game::theGame->printBoard)
208 Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH);
210 if (Game::theGame->graphicsEnabled && theGame->log == stdout)
212 theGame->logMessage("CLOSE WINDOW TO EXIT\n");
213 Game::theGame->theBoard.Draw(Piece::BOTH);
217 while (SDL_PollEvent(&event))
230 if (theGame->log == stdout)
232 theGame->logMessage( "PRESS ENTER TO EXIT\n");
233 theGame->theBoard.Print(theGame->log);
234 while (fgetc(stdin) != '\n');
242 void Game::PrintEndMessage(const MovementResult & result)
244 if (turn == Piece::RED)
246 logMessage("Game ends on RED's turn - REASON: ");
248 else if (turn == Piece::BLUE)
250 logMessage("Game ends on BLUE's turn - REASON: ");
254 logMessage("Game ends on ERROR's turn - REASON: ");
259 case MovementResult::OK:
260 logMessage("Status returned OK, unsure why game halted...\n");
262 case MovementResult::DIES:
263 logMessage("Status returned DIES, unsure why game halted...\n");
265 case MovementResult::KILLS:
266 logMessage("Status returned KILLS, unsure why game halted...\n");
268 case MovementResult::BOTH_DIE:
269 logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
271 case MovementResult::NO_BOARD:
272 logMessage("Board does not exit?!\n");
274 case MovementResult::INVALID_POSITION:
275 logMessage("Coords outside board\n");
277 case MovementResult::NO_SELECTION:
278 logMessage("Move does not select a piece\n");
280 case MovementResult::NOT_YOUR_UNIT:
281 logMessage("Selected piece belongs to other player\n");
283 case MovementResult::IMMOBILE_UNIT:
284 logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
286 case MovementResult::INVALID_DIRECTION:
287 logMessage("Selected unit cannot move that way\n");
289 case MovementResult::POSITION_FULL:
290 logMessage("Attempted move into square occupied by allied piece\n");
292 case MovementResult::VICTORY:
293 logMessage("Captured the flag\n");
295 case MovementResult::BAD_RESPONSE:
296 logMessage("Unintelligable response\n");
298 case MovementResult::NO_MOVE:
299 logMessage("Did not make a move (may have exited)\n");
301 case MovementResult::COLOUR_ERROR:
302 logMessage("Internal controller error - COLOUR_ERROR\n");
304 case MovementResult::ERROR:
305 logMessage("Internal controller error - Unspecified ERROR\n");
307 case MovementResult::DRAW:
308 logMessage("Game declared a draw after %d turns\n", turnCount);
316 fprintf(stdout, "%d Final State\n", turnCount);
317 theBoard.PrintPretty(stdout, Piece::BOTH);
318 fprintf(stdout, "\n");
320 if (graphicsEnabled && log == stdout)
322 logMessage("CLOSE WINDOW TO EXIT\n");
323 theBoard.Draw(Piece::BOTH);
327 while (SDL_PollEvent(&event))
342 logMessage("PRESS ENTER TO EXIT\n");
343 while (fgetc(stdin) != '\n');
351 MovementResult Game::Play()
354 MovementResult result = MovementResult::OK;
360 red->Message("START");
361 //logMessage("START\n");
362 while (Board::LegalResult(result) && (turnCount < maxTurns || maxTurns < 0))
367 logMessage( "%d RED: ", turnCount);
368 result = red->MakeMove(buffer);
369 red->Message(buffer);
370 blue->Message(buffer);
371 logMessage( "%s\n", buffer.c_str());
372 if (!Board::LegalResult(result))
375 theBoard.Draw(reveal);
379 fprintf(stdout, "%d RED:\n", turnCount);
380 theBoard.PrintPretty(stdout, reveal);
381 fprintf(stdout, "\n\n");
386 logMessage( "%d BLU: ", turnCount);
387 result = blue->MakeMove(buffer);
388 blue->Message(buffer);
389 red->Message(buffer);
390 logMessage( "%s\n", buffer.c_str());
392 if (!Board::LegalResult(result))
398 theBoard.Draw(reveal);
402 fprintf(stdout, "%d BLUE:\n", turnCount);
403 theBoard.PrintPretty(stdout, reveal);
404 fprintf(stdout, "\n\n");
412 if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
414 result = MovementResult::DRAW;
426 * Logs a message to the game's log file if it exists
427 * @param format the format string
428 * @param additional parameters - printed using va_args
429 * @returns the result of vfprintf or a negative number if the log file does not exist
431 int Game::logMessage(const char * format, ...)
436 va_start(ap, format);
438 int result = vfprintf(log, format, ap);
444 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
447 char c = fgetc(file);
455 while (fgetc(file) != '\n');
457 for (int y = 0; y < 4; ++y)
460 for (int x = 0; x < Game::theGame->theBoard.Width(); ++x)
462 setup[y] += fgetc(file);
465 if (fgetc(file) != '\n')
467 return MovementResult::BAD_RESPONSE;
470 return MovementResult::OK;
475 MovementResult FileController::QueryMove(std::string & buffer)
479 fgets(buf, sizeof(buf), file);
480 char * s = (char*)(buf);
481 while (*s != ':' && *s != '\0')
487 return MovementResult::OK;