X-Git-Url: https://git.ucc.asn.au/?p=progcomp2012.git;a=blobdiff_plain;f=judge%2Fmanager%2Fgame.cpp;h=f50ce270610755a87fb779dcee7736e9bc2a1ffa;hp=3df968cc9dad319282197be3d522b19788d35cf0;hb=df9b2d14b2e4e5ea2e99614e44151295bcf4956c;hpb=e1153eebe8cfd0c881cef2ff8fca63f130e736b3 diff --git a/judge/manager/game.cpp b/judge/manager/game.cpp index 3df968c..f50ce27 100644 --- a/judge/manager/game.cpp +++ b/judge/manager/game.cpp @@ -1,5 +1,7 @@ #include "game.h" #include +#include + using namespace std; @@ -7,7 +9,7 @@ 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, int newMaxTurns, bool newPrintBoard, double newTimeoutTime) : 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), timeoutTime(newTimeoutTime) +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, double newTimeoutTime, const char * newImageOutput) : 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), timeoutTime(newTimeoutTime), imageOutput(newImageOutput) { gameCreated = false; if (gameCreated) @@ -22,24 +24,37 @@ Game::Game(const char * redPath, const char * bluePath, const bool enableGraphic #ifdef BUILD_GRAPHICS if (graphicsEnabled && (!Graphics::Initialised())) - Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32); + { + string s = "Stratego: "; + s += string(redPath); + s += " "; + s += string(bluePath); + Graphics::Initialise(s.c_str(), theBoard.Width()*GRID_SIZE, theBoard.Height()*GRID_SIZE); + } #endif //BUILD_GRAPHICS - if (strcmp(redPath, "human") == 0) - red = new Human_Controller(Piece::RED, graphicsEnabled); - else - red = new AI_Controller(Piece::RED, redPath, timeoutTime); - - - if (strcmp(bluePath, "human") == 0) - blue = new Human_Controller(Piece::BLUE, graphicsEnabled); - else - blue = new AI_Controller(Piece::BLUE, bluePath, timeoutTime); + MakeControllers(redPath, bluePath); + + if (red == NULL || blue == NULL) + { + fprintf(stderr, "Game::Game - Error creating controller: "); + if (red == NULL) + { + if (blue == NULL) + fprintf(stderr, " BOTH! (red: \"%s\", blue: \"%s\"\n", redPath, bluePath); + else + fprintf(stderr, " RED! (red: \"%s\")\n", redPath); + } + else + fprintf(stderr, "BLUE! (blue: \"%s\")\n", bluePath); + exit(EXIT_FAILURE); + } +// logMessage("Game initialised.\n"); } -Game::Game(const char * fromFile, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard, double newTimeoutTime) : 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), timeoutTime(newTimeoutTime) +Game::Game(const char * fromFile, const bool enableGraphics, double newStallTime, const bool allowIllegal, FILE * newLog, const Piece::Colour & newReveal, int newMaxTurns, bool newPrintBoard, double newTimeoutTime,const char * newImageOutput) : 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), timeoutTime(newTimeoutTime), imageOutput(newImageOutput) { gameCreated = false; if (gameCreated) @@ -53,7 +68,11 @@ Game::Game(const char * fromFile, const bool enableGraphics, double newStallTime #ifdef BUILD_GRAPHICS if (graphicsEnabled && (!Graphics::Initialised())) - Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32); + { + string s = "Stratego: (file) "; + s += string(fromFile); + Graphics::Initialise(s.c_str(), theBoard.Width()*GRID_SIZE, theBoard.Height()*GRID_SIZE); + } #endif //BUILD_GRAPHICS input = fopen(fromFile, "r"); @@ -201,21 +220,23 @@ void Game::Wait(double wait) if (wait <= 0) return; - TimerThread timer(wait*1000000); //Wait in seconds - timer.Start(); + + #ifdef BUILD_GRAPHICS + + if (!graphicsEnabled) { - while (!timer.Finished()); - timer.Stop(); + usleep(1000000*wait); //Wait in seconds return; } - #endif //BUILD_GRAPHICS + TimerThread timer(wait*1000000); //Wait in seconds + timer.Start(); while (!timer.Finished()) { - #ifdef BUILD_GRAPHICS + SDL_Event event; while (SDL_PollEvent(&event)) { @@ -227,9 +248,12 @@ void Game::Wait(double wait) break; } } - #endif //BUILD_GRAPHICS } timer.Stop(); + + #else + usleep(wait*1000000); //Wait in seconds + #endif //BUILD_GRAPHICS } @@ -442,9 +466,24 @@ void Game::PrintEndMessage(const MovementResult & result) } } +/** Checks for victory by attrition (destroying all mobile pieces) + * + * @returns OK for no victory, + * DRAW if both players have no pieces, or + * VICTORY_ATTRITION if the current player has won by attrition + */ +MovementResult Game::CheckVictoryAttrition() +{ + if (theBoard.MobilePieces(Piece::OppositeColour(turn)) == 0) + { + if (theBoard.MobilePieces(turn) == 0) + return MovementResult::DRAW; + else + return MovementResult::VICTORY_ATTRITION; + } + return MovementResult::OK; - - +} MovementResult Game::Play() { @@ -457,10 +496,10 @@ MovementResult Game::Play() - +// logMessage("Messaging red with \"START\"\n"); red->Message("START"); - + int moveCount = 0; while (!Board::HaltResult(result) && (turnCount < maxTurns || maxTurns < 0)) { @@ -479,26 +518,39 @@ MovementResult Game::Play() #ifdef BUILD_GRAPHICS if (graphicsEnabled) + { theBoard.Draw(toReveal); + if (imageOutput != "") + { + string imageFile = "" + imageOutput + "/"+ itostr(moveCount) + ".bmp"; + Graphics::ScreenShot(imageFile.c_str()); + } + + } #endif //BUILD_GRAPHICS turn = Piece::RED; + blue->Pause(); + red->Continue(); + if (!Board::HaltResult(result)) + { + result = CheckVictoryAttrition(); + } + if (Board::HaltResult(result)) + break; + logMessage( "%d RED: ", turnCount); result = red->MakeMove(buffer); red->Message(buffer); blue->Message(buffer); logMessage( "%s\n", buffer.c_str()); - if (Board::HaltResult(result)) - break; - if (theBoard.MobilePieces(Piece::BLUE) == 0) + if (!Board::HaltResult(result)) { - if (theBoard.MobilePieces(Piece::RED) == 0) - result = MovementResult::DRAW; - else - result = MovementResult::VICTORY_ATTRITION; - break; + result = CheckVictoryAttrition(); } + if (Board::HaltResult(result)) + break; if (stallTime >= 0) Wait(stallTime); @@ -514,21 +566,43 @@ MovementResult Game::Play() theBoard.PrintPretty(stdout, toReveal); fprintf(stdout, "\n\n"); } + + ++moveCount; #ifdef BUILD_GRAPHICS if (graphicsEnabled) + { theBoard.Draw(toReveal); + if (imageOutput != "") + { + string imageFile = "" + imageOutput + "/" + itostr(moveCount) + ".bmp"; + Graphics::ScreenShot(imageFile.c_str()); + } + } #endif //BUILD_GRAPHICS turn = Piece::BLUE; + red->Pause(); + blue->Continue(); + if (!Board::HaltResult(result)) + { + result = CheckVictoryAttrition(); + } + if (Board::HaltResult(result)) + break; + logMessage( "%d BLU: ", turnCount); result = blue->MakeMove(buffer); blue->Message(buffer); red->Message(buffer); logMessage( "%s\n", buffer.c_str()); + if (!Board::HaltResult(result)) + { + result = CheckVictoryAttrition(); + } if (Board::HaltResult(result)) break; @@ -549,7 +623,7 @@ MovementResult Game::Play() else ReadUserCommand(); - + ++moveCount; ++turnCount; } @@ -720,4 +794,113 @@ int Game::Tokenise(std::vector & buffer, std::string & str, char split) return buffer.size(); } +/** + * Creates Controller baseds off strings. Takes into account controllers other than AI_Controller. + * @param redPath - Either the path to an AI_Controller compatable executable, or one of %human or %network or %network:[IP_ADDRESS] + * @param bluePath - Ditto + * Sets this->red to a controller using redPath, and this->blue to a controller using bluePath + * TODO: Make nicer (this function should be ~half the length) + */ +void Game::MakeControllers(const char * redPath, const char * bluePath) +{ + Network * redNetwork = NULL; + Network * blueNetwork = NULL; + //To allow for running two network controllers (I don't know why you would, but beside the point...) use two ports + static const int port1 = 4560; + static const int port2 = 4561; + + if (redPath[0] == '@') + { + if (strcmp(redPath, "@human") == 0) + red = new Human_Controller(Piece::RED, graphicsEnabled); + else + { + const char * network = strstr(redPath, "@network"); + if (network == NULL) + { + red = NULL; + return; + } + network = strstr(network, ":"); + + if (network == NULL) + { + logMessage("Creating server for red AI... "); + redNetwork = new Server(port1); + logMessage("Successful!\n"); + + } + else + { + network = (const char*)(network+1); + logMessage("Creating client for red AI... "); + redNetwork = new Client(network, port2); + logMessage("Connected to address %s\n", network); + } + + logMessage(" (Red's responses will be received over the connection)\n"); + red = new NetworkReceiver(Piece::RED, redNetwork); + } + } + else + red = new AI_Controller(Piece::RED, redPath, timeoutTime); + + if (bluePath[0] == '@') + { + if (strcmp(bluePath, "@human") == 0) + blue = new Human_Controller(Piece::BLUE, graphicsEnabled); + else + { + const char * network = strstr(bluePath, "@network"); + if (network == NULL) + { + blue = NULL; + return; + } + network = strstr(network, ":"); + + if (network == NULL) + { + logMessage("Creating server for blue AI... "); + blueNetwork = new Server(port2); + logMessage("Successful!\n"); + + } + else + { + network = (const char*)(network+1); + logMessage("Creating client for blue AI... "); + blueNetwork = new Client(network, port1); + logMessage("Connected to address %s\n", network); + } + logMessage(" (Blue's responses will be received over the connection)\n"); + blue = new NetworkReceiver(Piece::BLUE, blueNetwork); + } + } + else + blue = new AI_Controller(Piece::BLUE, bluePath, timeoutTime); + + if (redNetwork != NULL) + { + + blue = new NetworkSender(Piece::BLUE,blue, redNetwork); + logMessage(" (Blue's responses will be copied over the connection)\n"); + } + if (blueNetwork != NULL) + { + + red = new NetworkSender(Piece::RED, red, blueNetwork); + logMessage(" (Red's responses will be copied over the connection)\n"); + } + + red->FixName(); blue->FixName(); + +} + +string itostr(int i) +{ + stringstream s; + s << i; + return s.str(); +}