Revamped manager program and added manual page
[progcomp2012.git] / manager / game.cpp
1 #include "game.h"
2
3 using namespace std;
4
5
6
7 Game* Game::theGame = NULL;
8
9 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)
10 {
11         static bool gameCreated = false;
12         if (gameCreated)
13         {
14                 if (log != NULL)
15                         fprintf(log, "ERROR - Game has already been created!\n");
16                 exit(EXIT_FAILURE);
17         }
18         gameCreated = true;
19         Game::theGame = this;
20         signal(SIGPIPE, Game::HandleBrokenPipe);
21
22
23         if (graphicsEnabled && (!Graphics::Initialised()))
24                         Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32);
25
26         if (strcmp(redPath, "human") == 0)
27                 red = new Human_Controller(Piece::RED, graphicsEnabled);
28         else
29                 red = new AI_Controller(Piece::RED, redPath);
30         
31         
32         if (strcmp(bluePath, "human") == 0)
33                 blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
34         else
35                 blue = new AI_Controller(Piece::BLUE, redPath);
36
37
38 }
39
40 Game::~Game()
41 {
42         fprintf(stderr, "Killing AI\n");
43         delete red;
44         delete blue;
45
46         if (log != NULL && log != stdout && log != stderr)
47                 fclose(log);
48 }
49
50 bool Game::Setup(const char * redName, const char * blueName)
51 {
52
53         for (int y = 4; y < 6; ++y)
54         {
55                 for (int x = 2; x < 4; ++x)
56                 {
57                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
58                 }
59                 for (int x = 6; x < 8; ++x)
60                 {
61                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
62                 }
63         }
64
65
66         MovementResult redSetup = red->Setup(blueName);
67         MovementResult blueSetup = blue->Setup(redName);
68
69         if (redSetup != MovementResult::OK)
70         {       
71                 if (blueSetup != MovementResult::OK)
72                 {
73                         if (log != NULL)
74                                 fprintf(log, "BOTH players give invalid setup!\n");
75                         red->Message("ILLEGAL");
76                         blue->Message("ILLEGAL");
77                 }
78                 else
79                 {
80                         if (log != NULL)
81                                 fprintf(log, "Player RED gave an invalid setup!\n");
82                         red->Message("ILLEGAL");
83                         blue->Message("DEFAULT");
84                 }
85                 return false;
86         }
87         else if (blueSetup != MovementResult::OK)
88         {
89                 if (log != NULL)
90                         fprintf(log, "Player BLUE gave an invalid setup!\n");
91                 red->Message("DEFAULT");
92                 blue->Message("ILLEGAL");       
93                 return false;
94         }
95         return true;
96
97 }
98
99 void Game::Wait(double wait)
100 {
101         if (wait <= 0)
102                 return;
103
104         TimerThread timer(wait*1000000); //Wait in seconds
105         timer.Start();
106
107         if (!graphicsEnabled)
108         {
109                 while (!timer.Finished());
110                 timer.Stop();
111                 return;
112         }
113
114
115         while (!timer.Finished())
116         {
117                 SDL_Event  event;
118                 while (SDL_PollEvent(&event))
119                 {
120                         switch (event.type)
121                         {
122                                 case SDL_QUIT:
123                                         timer.Stop();
124                                         exit(EXIT_SUCCESS);
125                                         break;
126                         }
127                 }
128         }
129         timer.Stop();
130         
131 }
132
133 void Game::HandleBrokenPipe(int sig)
134 {
135         if (theGame->turn == Piece::RED)
136         {
137                 theGame->logMessage("Game ends on RED's turn - REASON: ");
138                 theGame->blue->Message("DEFAULT");      
139         }
140         else if (theGame->turn == Piece::BLUE)
141         {
142         
143                 theGame->logMessage("Game ends on BLUE's turn - REASON: ");
144                 theGame->red->Message("DEFAULT");
145         }
146         else
147         {
148                 theGame->logMessage("Game ends on ERROR's turn - REASON: ");
149                         
150         }
151         
152         theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
153
154
155
156         if (Game::theGame->graphicsEnabled && theGame->log == stdout)
157         {
158                 theGame->logMessage("CLOSE WINDOW TO EXIT\n");
159                 Game::theGame->theBoard.Draw(Piece::BOTH);
160                 while (true)
161                 {
162                         SDL_Event  event;
163                         while (SDL_PollEvent(&event))
164                         {
165                                 switch (event.type)
166                                 {
167                                         case SDL_QUIT:
168                                                 exit(EXIT_SUCCESS);
169                                                 break;
170                                 }
171                         }                       
172                 }
173         }
174         else
175         {
176                 if (theGame->log == stdout)
177                 {
178                         theGame->logMessage( "PRESS ENTER TO EXIT\n");
179                         theGame->theBoard.Print(theGame->log);
180                         while (fgetc(stdin) != '\n');
181                 }
182         }
183         
184
185         exit(EXIT_SUCCESS);
186 }
187
188 void Game::PrintEndMessage(const MovementResult & result)
189 {
190         if (turn == Piece::RED)
191         {
192                 logMessage("Game ends on RED's turn - REASON: ");       
193         }
194         else if (turn == Piece::BLUE)
195         {
196                 logMessage("Game ends on BLUE's turn - REASON: ");
197         }
198         else
199         {
200                 logMessage("Game ends on ERROR's turn - REASON: ");
201                         
202         }
203         switch (result.type)
204         {
205                 case MovementResult::OK:
206                         logMessage("Status returned OK, unsure why game halted...\n");
207                         break;
208                 case MovementResult::DIES:
209                         logMessage("Status returned DIES, unsure why game halted...\n");
210                         break;
211                 case MovementResult::KILLS:
212                         logMessage("Status returned KILLS, unsure why game halted...\n");
213                         break;
214                 case MovementResult::BOTH_DIE:
215                         logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
216                         break;
217                 case MovementResult::NO_BOARD:
218                         logMessage("Board does not exit?!\n");
219                         break;
220                 case MovementResult::INVALID_POSITION:
221                         logMessage("Coords outside board\n");
222                         break;
223                 case MovementResult::NO_SELECTION:
224                         logMessage("Move does not select a piece\n");
225                         break;
226                 case MovementResult::NOT_YOUR_UNIT:
227                         logMessage("Selected piece belongs to other player\n");
228                         break;
229                 case MovementResult::IMMOBILE_UNIT:
230                         logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
231                         break;
232                 case MovementResult::INVALID_DIRECTION:
233                         logMessage("Selected unit cannot move that way\n");
234                         break;
235                 case MovementResult::POSITION_FULL:
236                         logMessage("Attempted move into square occupied by allied piece\n");
237                         break;
238                 case MovementResult::VICTORY:
239                         logMessage("Captured the flag\n");
240                         break;
241                 case MovementResult::BAD_RESPONSE:
242                         logMessage("Unintelligable response\n");
243                         break;
244                 case MovementResult::NO_MOVE:
245                         logMessage("Did not make a move (may have exited)\n");
246                         break;
247                 case MovementResult::COLOUR_ERROR:
248                         logMessage("Internal controller error - COLOUR_ERROR\n");
249                         break;
250                 case MovementResult::ERROR:
251                         logMessage("Internal controller error - Unspecified ERROR\n");
252                         break;
253
254         }
255
256         if (graphicsEnabled && log == stdout)
257         {
258                 logMessage("CLOSE WINDOW TO EXIT\n");
259                 theBoard.Draw(Piece::BOTH);
260                 while (true)
261                 {
262                         SDL_Event  event;
263                         while (SDL_PollEvent(&event))
264                         {
265                                 switch (event.type)
266                                 {
267                                         case SDL_QUIT:
268                                                 exit(EXIT_SUCCESS);
269                                                 break;
270                                 }
271                         }                       
272                 }
273         }
274         else
275         {
276                 if (log == stdout)
277                 {
278                         logMessage("PRESS ENTER TO EXIT\n");
279                         while (fgetc(stdin) != '\n');
280                 }
281         }
282
283 }
284
285
286
287 MovementResult Game::Play()
288 {
289         
290         MovementResult result = MovementResult::OK;
291         turnCount = 1;
292         string buffer;
293         
294
295
296         red->Message("START");
297         logMessage("START");
298         while (Board::LegalResult(result))
299         {
300
301                 
302                 turn = Piece::RED;
303                 logMessage( "%d RED: ", turnCount);
304                 result = red->MakeMove(buffer);
305                 red->Message(buffer);
306                 blue->Message(buffer);
307                 logMessage( "%s\n", buffer.c_str());
308                 if (!Board::LegalResult(result))
309                         break;
310                 if (graphicsEnabled)
311                         theBoard.Draw(reveal);
312                 Wait(stallTime);
313                 
314                 turn = Piece::BLUE;
315                 logMessage( "%d BLU: ", turnCount);
316                 result = blue->MakeMove(buffer);
317                 blue->Message(buffer);
318                 red->Message(buffer);
319                 logMessage( "%s\n", buffer.c_str());
320
321                 if (!Board::LegalResult(result))
322                         break;
323
324                 
325
326                 if (graphicsEnabled)
327                         theBoard.Draw(reveal);
328                 Wait(stallTime);
329                 
330                 ++turnCount;
331         }
332
333         
334         return result;
335
336                 
337
338 }
339
340 /**
341  * Logs a message to the game's log file if it exists
342  * @param format the format string
343  * @param additional parameters - printed using va_args
344  * @returns the result of vfprintf or a negative number if the log file does not exist
345  */
346 int Game::logMessage(const char * format, ...)
347 {
348         if (log == NULL)
349                 return -666;
350                 va_list ap;
351         va_start(ap, format);
352
353         int result = vfprintf(log, format, ap);
354         va_end(ap);
355
356         return result;
357 }

UCC git Repository :: git.ucc.asn.au