More adding of pointless crap to manager
[progcomp2012.git] / manager / game.cpp
1 #include "game.h"
2
3 using namespace std;
4
5
6
7 Game* Game::theGame = NULL;
8 bool Game::gameCreated = false;
9
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)
11 {
12         gameCreated = false;
13         if (gameCreated)
14         {
15                 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\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, bluePath);
36
37
38 }
39
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)
41 {
42         gameCreated = false;
43         if (gameCreated)
44         {
45                 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
46                 exit(EXIT_FAILURE);
47         }
48         gameCreated = true;
49         Game::theGame = this;
50         signal(SIGPIPE, Game::HandleBrokenPipe);
51
52
53         if (graphicsEnabled && (!Graphics::Initialised()))
54                         Graphics::Initialise("Stratego", theBoard.Width()*32, theBoard.Height()*32);
55
56         input = fopen(fromFile, "r");
57
58         red = new FileController(Piece::RED, input);
59         blue = new FileController(Piece::BLUE, input);
60
61
62 }
63
64 Game::~Game()
65 {
66         
67         delete red;
68         delete blue;
69
70         if (log != NULL && log != stdout && log != stderr)
71                 fclose(log);
72
73         if (input != NULL && input != stdin)
74                 fclose(input);
75 }
76
77 bool Game::Setup(const char * redName, const char * blueName)
78 {
79
80         if (!red->Valid())
81         {
82                 logMessage("Controller for Player RED is invalid!\n");
83         }
84         if (!blue->Valid())
85         {
86                 logMessage("Controller for Player BLUE is invalid!\n");
87         }
88         if (!red->Valid() || !blue->Valid())
89                 return false;
90
91         for (int y = 4; y < 6; ++y)
92         {
93                 for (int x = 2; x < 4; ++x)
94                 {
95                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
96                 }
97                 for (int x = 6; x < 8; ++x)
98                 {
99                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
100                 }
101         }
102
103
104         MovementResult redSetup = red->Setup(blueName);
105         MovementResult blueSetup = blue->Setup(redName);
106
107         if (redSetup != MovementResult::OK)
108         {       
109                 if (blueSetup != MovementResult::OK)
110                 {
111                         logMessage("BOTH players give invalid setup!\n");
112                         red->Message("ILLEGAL");
113                         blue->Message("ILLEGAL");
114                 }
115                 else
116                 {
117                         logMessage("Player RED gave an invalid setup!\n");
118                         red->Message("ILLEGAL");
119                         blue->Message("DEFAULT");
120                 }
121                 return false;
122         }
123         else if (blueSetup != MovementResult::OK)
124         {
125                 logMessage("Player BLUE gave an invalid setup!\n");
126                 red->Message("DEFAULT");
127                 blue->Message("ILLEGAL");       
128                 return false;
129         }
130
131         logMessage("%s RED SETUP\n", red->name.c_str());
132         for (int y=0; y < 4; ++y)
133         {
134                 for (int x=0; x < theBoard.Width(); ++x)
135                         logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
136                 logMessage("\n");
137         }       
138
139         logMessage("%s BLUE SETUP\n", blue->name.c_str());
140         for (int y=0; y < 4; ++y)
141         {
142                 for (int x=0; x < theBoard.Width(); ++x)
143                         logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4 + y)->type)]);
144                 logMessage("\n");
145         }       
146
147         
148         return true;
149
150 }
151
152 void Game::Wait(double wait)
153 {
154         if (wait <= 0)
155                 return;
156
157         TimerThread timer(wait*1000000); //Wait in seconds
158         timer.Start();
159
160         if (!graphicsEnabled)
161         {
162                 while (!timer.Finished());
163                 timer.Stop();
164                 return;
165         }
166
167
168         while (!timer.Finished())
169         {
170                 SDL_Event  event;
171                 while (SDL_PollEvent(&event))
172                 {
173                         switch (event.type)
174                         {
175                                 case SDL_QUIT:
176                                         timer.Stop();
177                                         exit(EXIT_SUCCESS);
178                                         break;
179                         }
180                 }
181         }
182         timer.Stop();
183         
184 }
185
186 void Game::HandleBrokenPipe(int sig)
187 {
188         if (theGame->turn == Piece::RED)
189         {
190                 theGame->logMessage("Game ends on RED's turn - REASON: ");
191                 theGame->blue->Message("DEFAULT");      
192         }
193         else if (theGame->turn == Piece::BLUE)
194         {
195         
196                 theGame->logMessage("Game ends on BLUE's turn - REASON: ");
197                 theGame->red->Message("DEFAULT");
198         }
199         else
200         {
201                 theGame->logMessage("Game ends on ERROR's turn - REASON: ");
202                         
203         }
204         
205         theGame->logMessage("SIGPIPE - Broken pipe (AI program may have segfaulted)\n");
206
207         if (Game::theGame->printBoard)
208                 Game::theGame->theBoard.PrintPretty(stdout, Piece::BOTH);
209
210         if (Game::theGame->graphicsEnabled && theGame->log == stdout)
211         {
212                 theGame->logMessage("CLOSE WINDOW TO EXIT\n");
213                 Game::theGame->theBoard.Draw(Piece::BOTH);
214                 while (true)
215                 {
216                         SDL_Event  event;
217                         while (SDL_PollEvent(&event))
218                         {
219                                 switch (event.type)
220                                 {
221                                         case SDL_QUIT:
222                                                 exit(EXIT_SUCCESS);
223                                                 break;
224                                 }
225                         }                       
226                 }
227         }
228         else
229         {
230                 if (theGame->log == stdout)
231                 {
232                         theGame->logMessage( "PRESS ENTER TO EXIT\n");
233                         theGame->theBoard.Print(theGame->log);
234                         while (fgetc(stdin) != '\n');
235                 }
236         }
237         
238
239         exit(EXIT_SUCCESS);
240 }
241
242 void Game::PrintEndMessage(const MovementResult & result)
243 {
244         if (turn == Piece::RED)
245         {
246                 logMessage("Game ends on RED's turn - REASON: ");       
247         }
248         else if (turn == Piece::BLUE)
249         {
250                 logMessage("Game ends on BLUE's turn - REASON: ");
251         }
252         else
253         {
254                 logMessage("Game ends on ERROR's turn - REASON: ");
255                         
256         }
257         switch (result.type)
258         {
259                 case MovementResult::OK:
260                         logMessage("Status returned OK, unsure why game halted...\n");
261                         break;
262                 case MovementResult::DIES:
263                         logMessage("Status returned DIES, unsure why game halted...\n");
264                         break;
265                 case MovementResult::KILLS:
266                         logMessage("Status returned KILLS, unsure why game halted...\n");
267                         break;
268                 case MovementResult::BOTH_DIE:
269                         logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
270                         break;
271                 case MovementResult::NO_BOARD:
272                         logMessage("Board does not exit?!\n");
273                         break;
274                 case MovementResult::INVALID_POSITION:
275                         logMessage("Coords outside board\n");
276                         break;
277                 case MovementResult::NO_SELECTION:
278                         logMessage("Move does not select a piece\n");
279                         break;
280                 case MovementResult::NOT_YOUR_UNIT:
281                         logMessage("Selected piece belongs to other player\n");
282                         break;
283                 case MovementResult::IMMOBILE_UNIT:
284                         logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
285                         break;
286                 case MovementResult::INVALID_DIRECTION:
287                         logMessage("Selected unit cannot move that way\n");
288                         break;
289                 case MovementResult::POSITION_FULL:
290                         logMessage("Attempted move into square occupied by allied piece\n");
291                         break;
292                 case MovementResult::VICTORY:
293                         logMessage("Captured the flag\n");
294                         break;
295                 case MovementResult::BAD_RESPONSE:
296                         logMessage("Unintelligable response\n");
297                         break;
298                 case MovementResult::NO_MOVE:
299                         logMessage("Did not make a move (may have exited)\n");
300                         break;
301                 case MovementResult::COLOUR_ERROR:
302                         logMessage("Internal controller error - COLOUR_ERROR\n");
303                         break;
304                 case MovementResult::ERROR:
305                         logMessage("Internal controller error - Unspecified ERROR\n");
306                         break;
307                 case MovementResult::DRAW:
308                         logMessage("Game declared a draw after %d turns\n", turnCount);
309                         break;
310
311         }
312
313         if (printBoard)
314         {
315                 system("clear");
316                 fprintf(stdout, "%d Final State\n", turnCount);
317                 theBoard.PrintPretty(stdout, Piece::BOTH);
318                 fprintf(stdout, "\n");
319         }
320         if (graphicsEnabled && log == stdout)
321         {
322                 logMessage("CLOSE WINDOW TO EXIT\n");
323                 theBoard.Draw(Piece::BOTH);
324                 while (true)
325                 {
326                         SDL_Event  event;
327                         while (SDL_PollEvent(&event))
328                         {
329                                 switch (event.type)
330                                 {
331                                         case SDL_QUIT:
332                                                 exit(EXIT_SUCCESS);
333                                                 break;
334                                 }
335                         }                       
336                 }
337         }
338         else
339         {
340                 if (log == stdout)
341                 {
342                         logMessage("PRESS ENTER TO EXIT\n");
343                         while (fgetc(stdin) != '\n');
344                 }
345         }
346
347 }
348
349
350
351 MovementResult Game::Play()
352 {
353         
354         MovementResult result = MovementResult::OK;
355         turnCount = 1;
356         string buffer;
357         
358
359
360         red->Message("START");
361         //logMessage("START\n");
362         while (Board::LegalResult(result) && (turnCount < maxTurns || maxTurns < 0))
363         {
364
365                 
366                 turn = Piece::RED;
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))
373                         break;
374                 if (graphicsEnabled)
375                         theBoard.Draw(reveal);
376                 if (printBoard)
377                 {
378                         system("clear");
379                         fprintf(stdout, "%d RED:\n", turnCount);
380                         theBoard.PrintPretty(stdout, reveal);
381                         fprintf(stdout, "\n\n");
382                 }
383                 Wait(stallTime);
384                 
385                 turn = Piece::BLUE;
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());
391
392                 if (!Board::LegalResult(result))
393                         break;
394
395                 
396
397                 if (graphicsEnabled)
398                         theBoard.Draw(reveal);
399                 if (printBoard)
400                 {
401                         system("clear");
402                         fprintf(stdout, "%d BLUE:\n", turnCount);
403                         theBoard.PrintPretty(stdout, reveal);
404                         fprintf(stdout, "\n\n");
405                 }
406
407                 Wait(stallTime);
408                 
409                 ++turnCount;
410         }
411
412         if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
413         {
414                 result = MovementResult::DRAW;
415                 turn = Piece::BOTH;
416         }
417
418         
419         return result;
420
421                 
422
423 }
424
425 /**
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
430  */
431 int Game::logMessage(const char * format, ...)
432 {
433         if (log == NULL)
434                 return -666;
435                 va_list ap;
436         va_start(ap, format);
437
438         int result = vfprintf(log, format, ap);
439         va_end(ap);
440
441         return result;
442 }
443
444 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
445 {
446
447         char c = fgetc(file);
448         name = "";
449         while (c != ' ')
450         {
451                 name += c;
452                 c = fgetc(file);
453         }
454
455         while (fgetc(file) != '\n');
456
457         for (int y = 0; y < 4; ++y)
458         {
459                 setup[y] = "";
460                 for (int x = 0; x < Game::theGame->theBoard.Width(); ++x)
461                 {
462                         setup[y] += fgetc(file);
463                 }
464
465                 if (fgetc(file) != '\n')
466                 {
467                         return MovementResult::BAD_RESPONSE;
468                 }
469         }
470         return MovementResult::OK;
471
472         
473 }
474
475 MovementResult FileController::QueryMove(std::string & buffer)
476 {
477         char buf[BUFSIZ];
478
479         fgets(buf, sizeof(buf), file);
480         char * s = (char*)(buf);
481         while (*s != ':' && *s != '\0')
482                 ++s;
483
484         s += 2;
485         
486         buffer = string(s);
487         return MovementResult::OK;
488 }

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