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)
78 * Attempts to setup the board and controllers
79 * @param redName the name of the red AI
80 * @param blueName the name of the blue AI
81 * @returns A colour, indicating if there were any errors
82 Piece::NONE indicates no errors
83 Piece::BOTH indicates errors with both AI
84 Piece::RED / Piece::BLUE indicates an error with only one of the two AI
86 Piece::Colour Game::Setup(const char * redName, const char * blueName)
91 logMessage("Controller for Player RED is invalid!\n");
92 if (!red->HumanController())
93 logMessage("Check that program \"%s\" exists and has executable permissions set.\n", redName);
97 logMessage("Controller for Player BLUE is invalid!\n");
98 if (!blue->HumanController())
99 logMessage("Check that program \"%s\" exists and has executable permissions set.\n", blueName);
107 else if (!blue->Valid())
112 for (int y = 4; y < 6; ++y)
114 for (int x = 2; x < 4; ++x)
116 theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
118 for (int x = 6; x < 8; ++x)
120 theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
125 MovementResult redSetup = red->Setup(blueName);
126 MovementResult blueSetup = blue->Setup(redName);
129 Piece::Colour result = Piece::NONE;
130 if (redSetup != MovementResult::OK)
132 if (blueSetup != MovementResult::OK)
134 logMessage("BOTH players give invalid setup!\n");
135 result = Piece::BOTH;
139 //logMessage("Player RED gave an invalid setup!\n");
144 else if (blueSetup != MovementResult::OK)
146 //logMessage("Player BLUE gave an invalid setup!\n");
147 result = Piece::BLUE;
151 logMessage("%s RED SETUP\n", red->name.c_str());
152 if (redSetup == MovementResult::OK)
154 for (int y=0; y < 4; ++y)
156 for (int x=0; x < theBoard.Width(); ++x)
158 if (theBoard.GetPiece(x, y) != NULL)
159 logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
168 logMessage("INVALID!\n");
171 logMessage("%s BLUE SETUP\n", blue->name.c_str());
172 if (blueSetup == MovementResult::OK)
174 for (int y=0; y < 4; ++y)
176 for (int x=0; x < theBoard.Width(); ++x)
178 if (theBoard.GetPiece(x, theBoard.Height()-4+y) != NULL)
179 logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4+y)->type)]);
188 logMessage("INVALID!\n");
196 void Game::Wait(double wait)
201 TimerThread timer(wait*1000000); //Wait in seconds
204 if (!graphicsEnabled)
206 while (!timer.Finished());
212 while (!timer.Finished())
215 while (SDL_PollEvent(&event))
230 void Game::HandleBrokenPipe(int sig)
234 fprintf(stderr, "ERROR - Recieved SIGPIPE during game exit!\n");
237 if (theGame->turn == Piece::RED)
239 theGame->logMessage("Game ends on RED's turn - REASON: ");
240 theGame->blue->Message("DEFAULT");
242 else if (theGame->turn == Piece::BLUE)
245 theGame->logMessage("Game ends on BLUE's turn - REASON: ");
246 theGame->red->Message("DEFAULT");
250 theGame->logMessage("Game ends on ERROR's turn - REASON: ");
254 theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
256 if (Game::theGame->printBoard)
257 Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH);
259 if (Game::theGame->graphicsEnabled && theGame->log == stdout)
261 theGame->logMessage("CLOSE WINDOW TO EXIT\n");
262 Game::theGame->theBoard.Draw(Piece::BOTH);
266 while (SDL_PollEvent(&event))
279 if (theGame->log == stdout)
281 theGame->logMessage( "PRESS ENTER TO EXIT\n");
282 theGame->theBoard.Print(theGame->log);
283 while (fgetc(stdin) != '\n');
291 void Game::PrintEndMessage(const MovementResult & result)
295 logMessage("Game ends in the SETUP phase - REASON: ");
299 if (turn == Piece::RED)
301 logMessage("Game ends on RED's turn - REASON: ");
303 else if (turn == Piece::BLUE)
305 logMessage("Game ends on BLUE's turn - REASON: ");
309 logMessage("Game ends on ERROR's turn - REASON: ");
315 case MovementResult::OK:
316 logMessage("Status returned OK, unsure why game halted...\n");
318 case MovementResult::DIES:
319 logMessage("Status returned DIES, unsure why game halted...\n");
321 case MovementResult::KILLS:
322 logMessage("Status returned KILLS, unsure why game halted...\n");
324 case MovementResult::BOTH_DIE:
325 logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
327 case MovementResult::NO_BOARD:
328 logMessage("Board does not exit?!\n");
330 case MovementResult::INVALID_POSITION:
331 logMessage("Coords outside board\n");
333 case MovementResult::NO_SELECTION:
334 logMessage("Move does not select a piece\n");
336 case MovementResult::NOT_YOUR_UNIT:
337 logMessage("Selected piece belongs to other player\n");
339 case MovementResult::IMMOBILE_UNIT:
340 logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
342 case MovementResult::INVALID_DIRECTION:
343 logMessage("Selected unit cannot move that way\n");
345 case MovementResult::POSITION_FULL:
346 logMessage("Attempted move into square occupied by neutral or allied piece\n");
348 case MovementResult::VICTORY:
349 logMessage("Captured the flag\n");
351 case MovementResult::BAD_RESPONSE:
352 logMessage("Unintelligable response\n");
354 case MovementResult::NO_MOVE:
355 logMessage("Did not make a move (may have exited)\n");
357 case MovementResult::COLOUR_ERROR:
358 logMessage("Internal controller error - COLOUR_ERROR\n");
360 case MovementResult::ERROR:
361 logMessage("Internal controller error - Unspecified ERROR\n");
363 case MovementResult::DRAW_DEFAULT:
364 logMessage("Game declared a draw after %d turns\n", turnCount);
366 case MovementResult::DRAW:
367 logMessage("Game declared a draw because neither player has mobile pieces\n");
369 case MovementResult::SURRENDER:
370 logMessage("This player has surrendered!\n");
372 case MovementResult::BAD_SETUP:
376 logMessage("An illegal setup was made by RED\n");
379 logMessage("An illegal setup was made by BLUE\n");
382 logMessage("An illegal setup was made by BOTH players\n");
385 logMessage("Unknown internal error.\n");
395 fprintf(stdout, "%d Final State\n", turnCount);
396 theBoard.PrintPretty(stdout, Piece::BOTH);
397 fprintf(stdout, "\n");
399 if (graphicsEnabled && log == stdout)
401 logMessage("CLOSE WINDOW TO EXIT\n");
402 theBoard.Draw(Piece::BOTH);
406 while (SDL_PollEvent(&event))
421 logMessage("PRESS ENTER TO EXIT\n");
422 while (fgetc(stdin) != '\n');
430 MovementResult Game::Play()
433 MovementResult result = MovementResult::OK;
437 Piece::Colour toReveal = reveal;
443 red->Message("START");
447 while (!Board::HaltResult(result) && (turnCount < maxTurns || maxTurns < 0))
449 if (red->HumanController() && blue->HumanController())
450 toReveal = Piece::RED;
455 fprintf(stdout, "START:\n");
457 fprintf(stdout, "%d BLUE:\n", turnCount);
458 theBoard.PrintPretty(stdout, toReveal);
459 fprintf(stdout, "\n\n");
463 theBoard.Draw(toReveal);
466 logMessage( "%d RED: ", turnCount);
467 result = red->MakeMove(buffer);
468 red->Message(buffer);
469 blue->Message(buffer);
470 logMessage( "%s\n", buffer.c_str());
471 if (Board::HaltResult(result))
479 if (blue->HumanController() && red->HumanController())
480 toReveal = Piece::BLUE;
484 fprintf(stdout, "%d RED:\n", turnCount);
485 theBoard.PrintPretty(stdout, toReveal);
486 fprintf(stdout, "\n\n");
489 theBoard.Draw(toReveal);
494 logMessage( "%d BLU: ", turnCount);
495 result = blue->MakeMove(buffer);
496 blue->Message(buffer);
497 red->Message(buffer);
498 logMessage( "%s\n", buffer.c_str());
500 if (Board::HaltResult(result))
512 if (theBoard.MobilePieces(Piece::BOTH) == 0)
513 result = MovementResult::DRAW;
518 if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
520 result = MovementResult::DRAW_DEFAULT;
531 * Logs a message to the game's log file if it exists
532 * @param format the format string
533 * @param additional parameters - printed using va_args
534 * @returns the result of vfprintf or a negative number if the log file does not exist
536 int Game::logMessage(const char * format, ...)
541 va_start(ap, format);
543 int result = vfprintf(log, format, ap);
550 * Waits for a user command
551 * Currently ignores the command.
553 void Game::ReadUserCommand()
555 fprintf(stdout, "Waiting for user to press enter...\n");
557 for (char c = fgetc(stdin); c != '\n' && (int)(c) != EOF; c = fgetc(stdin))
563 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
566 char c = fgetc(file);
574 while (fgetc(file) != '\n');
576 for (int y = 0; y < 4; ++y)
579 for (int x = 0; x < Game::theGame->theBoard.Width(); ++x)
581 setup[y] += fgetc(file);
584 if (fgetc(file) != '\n')
586 return MovementResult::BAD_RESPONSE;
589 return MovementResult::OK;
594 MovementResult FileController::QueryMove(std::string & buffer)
598 fgets(buf, sizeof(buf), file);
599 char * s = (char*)(buf);
600 while (*s != ':' && *s != '\0')
606 return MovementResult::OK;