[PATCH] Handle case where an AI sends an invalid message and then crashes
[progcomp2012.git] / judge / manager / game.cpp
1 #include "game.h"
2 #include <stdarg.h>
3 #include <string>
4
5 using namespace std;
6
7
8
9 Game* Game::theGame = NULL;
10 bool Game::gameCreated = false;
11
12 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)
13 {
14         gameCreated = false;
15         if (gameCreated)
16         {
17                 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
18                 exit(EXIT_FAILURE);
19         }
20         gameCreated = true;
21         Game::theGame = this;
22         signal(SIGPIPE, Game::HandleBrokenPipe);
23
24
25         #ifdef BUILD_GRAPHICS
26         if (graphicsEnabled && (!Graphics::Initialised()))
27         {
28                         string s = "Stratego: ";
29                         s += string(redPath);
30                         s += " ";
31                         s += string(bluePath);
32                         Graphics::Initialise(s.c_str(), theBoard.Width()*GRID_SIZE, theBoard.Height()*GRID_SIZE);
33         }
34         #endif //BUILD_GRAPHICS
35
36
37
38         MakeControllers(redPath, bluePath);
39
40         if (red == NULL || blue == NULL)
41         {
42                 fprintf(stderr, "Game::Game - Error creating controller: ");
43                 if (red == NULL)
44                 {
45                         if (blue == NULL)
46                                 fprintf(stderr, " BOTH! (red: \"%s\", blue: \"%s\"\n", redPath, bluePath);
47                         else
48                                 fprintf(stderr, " RED! (red: \"%s\")\n", redPath);
49                 }
50                 else
51                         fprintf(stderr, "BLUE! (blue: \"%s\")\n", bluePath);
52                 exit(EXIT_FAILURE);
53         }
54 //      logMessage("Game initialised.\n");
55 }
56
57 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)
58 {
59         gameCreated = false;
60         if (gameCreated)
61         {
62                 fprintf(stderr, "Game::Game - Error - Tried to create more than one Game!\n");
63                 exit(EXIT_FAILURE);
64         }
65         gameCreated = true;
66         Game::theGame = this;
67         signal(SIGPIPE, Game::HandleBrokenPipe);
68
69         #ifdef BUILD_GRAPHICS
70         if (graphicsEnabled && (!Graphics::Initialised()))
71         {
72                         string s = "Stratego: (file) ";
73                         s += string(fromFile);
74                         Graphics::Initialise(s.c_str(), theBoard.Width()*GRID_SIZE, theBoard.Height()*GRID_SIZE);
75         }
76         #endif //BUILD_GRAPHICS
77
78         input = fopen(fromFile, "r");
79
80         red = new FileController(Piece::RED, input);
81         blue = new FileController(Piece::BLUE, input);
82
83
84 }
85
86 Game::~Game()
87 {
88         
89         delete red;
90         delete blue;
91
92         if (log != NULL && log != stdout && log != stderr)
93                 fclose(log);
94
95         if (input != NULL && input != stdin)
96                 fclose(input);
97 }
98
99 /**
100  * Attempts to setup the board and controllers
101  * @param redName the name of the red AI
102  * @param blueName the name of the blue AI
103  * @returns A colour, indicating if there were any errors
104         Piece::NONE indicates no errors
105         Piece::BOTH indicates errors with both AI
106         Piece::RED / Piece::BLUE indicates an error with only one of the two AI
107  */
108 Piece::Colour Game::Setup(const char * redName, const char * blueName)
109 {
110
111         if (!red->Valid())
112         {
113                 logMessage("Controller for Player RED is invalid!\n");
114                 if (!red->HumanController())
115                         logMessage("Check that executable \"%s\" exists and has executable permissions set.\n", redName);
116         }
117         if (!blue->Valid())
118         {
119                 logMessage("Controller for Player BLUE is invalid!\n");
120                 if (!blue->HumanController())
121                         logMessage("Check that executable \"%s\" exists and has executable permissions set.\n", blueName);
122         }
123         if (!red->Valid())
124         {
125                 if (!blue->Valid())
126                         return Piece::BOTH;
127                 return Piece::RED;
128         }
129         else if (!blue->Valid())
130         {
131                 return Piece::BLUE;
132         }
133
134         for (int y = 4; y < 6; ++y)
135         {
136                 for (int x = 2; x < 4; ++x)
137                 {
138                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
139                 }
140                 for (int x = 6; x < 8; ++x)
141                 {
142                         theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
143                 }
144         }
145
146
147         MovementResult redSetup = red->Setup(blueName);
148         MovementResult blueSetup = blue->Setup(redName);
149
150
151         Piece::Colour result = Piece::NONE;
152         if (redSetup != MovementResult::OK)
153         {       
154                 if (blueSetup != MovementResult::OK)
155                 {
156                         logMessage("BOTH players give invalid setup!\n");
157                         result = Piece::BOTH;
158                 }
159                 else
160                 {
161                         //logMessage("Player RED gave an invalid setup!\n");
162                         result = Piece::RED;
163                 }
164                 
165         }
166         else if (blueSetup != MovementResult::OK)
167         {
168                 //logMessage("Player BLUE gave an invalid setup!\n");
169                 result = Piece::BLUE;
170         }
171
172
173         logMessage("%s RED SETUP\n", red->name.c_str());
174         if (redSetup == MovementResult::OK)
175         {
176                 for (int y=0; y < 4; ++y)
177                 {
178                         for (int x=0; x < theBoard.Width(); ++x)
179                         {
180                                 if (theBoard.GetPiece(x, y) != NULL)
181                                         logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, y)->type)]);
182                                 else
183                                         logMessage(".");
184                         }
185                         logMessage("\n");
186                 }       
187         }
188         else
189         {
190                 logMessage("INVALID!\n");
191         }
192
193         logMessage("%s BLUE SETUP\n", blue->name.c_str());
194         if (blueSetup == MovementResult::OK)
195         {
196                 for (int y=0; y < 4; ++y)
197                 {
198                         for (int x=0; x < theBoard.Width(); ++x)
199                         {
200                                 if (theBoard.GetPiece(x, theBoard.Height()-4+y) != NULL)
201                                         logMessage("%c", Piece::tokens[(int)(theBoard.GetPiece(x, theBoard.Height()-4+y)->type)]);
202                                 else
203                                         logMessage(".");
204                         }
205                         logMessage("\n");
206                 }       
207         }
208         else
209         {
210                 logMessage("INVALID!\n");
211         }
212
213         
214         return result;
215
216 }
217
218 void Game::Wait(double wait)
219 {
220         if (wait <= 0)
221                 return;
222
223
224
225
226         #ifdef BUILD_GRAPHICS
227
228
229         if (!graphicsEnabled)
230         {
231                 usleep(1000000*wait); //Wait in seconds
232                 return;
233         }
234
235         TimerThread timer(wait*1000000); //Wait in seconds
236         timer.Start();
237         while (!timer.Finished())
238         {
239         
240                 SDL_Event  event;
241                 while (SDL_PollEvent(&event))
242                 {
243                         switch (event.type)
244                         {
245                                 case SDL_QUIT:
246                                         timer.Stop();
247                                         exit(EXIT_SUCCESS);
248                                         break;
249                         }
250                 }
251         }
252         timer.Stop();
253
254         #else
255         usleep(wait*1000000); //Wait in seconds
256         #endif //BUILD_GRAPHICS
257         
258 }
259
260 void Game::HandleBrokenPipe(int sig)
261 {
262         if (theGame == NULL)
263         {
264                 fprintf(stderr, "ERROR - Recieved SIGPIPE during game exit!\n");
265                 exit(EXIT_FAILURE);
266         }
267         
268         theGame->logMessage("SIGPIPE - Broken pipe (AI program no longer running)\n");
269
270         MovementResult result = MovementResult::BAD_RESPONSE; 
271
272         if (theGame->turn == Piece::RED)
273         {
274                 if (theGame->red->Valid())
275                 {
276                         theGame->logMessage("   Strange; RED still appears valid.\n");
277                         if (theGame->blue->Valid())
278                         {
279                                 theGame->logMessage("   BLUE also appears valid. Exiting with ERROR.\n");
280                                 result = MovementResult::ERROR;
281                         }
282                         else
283                         {
284                                 theGame->logMessage("BLUE is invalid. Wait for BLUE's turn to exit.\n");
285                                 return;
286                         }
287                 }
288         }
289         if (theGame->turn == Piece::BLUE)
290         {
291                 if (theGame->blue->Valid())
292                 {
293                         theGame->logMessage("   Strange; BLUE still appears valid.\n");
294                         if (theGame->red->Valid())
295                         {
296                                 theGame->logMessage("   RED also appears valid. Exiting with ERROR.\n");
297                                 result = MovementResult::ERROR;
298                         }
299                         else
300                         {
301                                 theGame->logMessage("RED is invalid. Wait for RED's turn to exit.\n");
302                                 return;
303                         }
304                 }
305         }
306
307
308         Game::theGame->PrintEndMessage(result);
309
310         string buffer = "";
311         PrintResults(result, buffer);
312
313         //Message the AI's the quit message
314         Game::theGame->red->Message("QUIT " + buffer);
315         Game::theGame->blue->Message("QUIT " + buffer);
316
317         //Log the message
318         if (Game::theGame->GetLogFile() != stdout)
319                 Game::theGame->logMessage("%s\n", buffer.c_str());
320
321         fprintf(stdout, "%s\n", buffer.c_str());
322         exit(EXIT_SUCCESS);
323 }
324
325 void Game::PrintEndMessage(const MovementResult & result)
326 {
327         if (turnCount == 0)
328         {
329                 logMessage("Game ends in the SETUP phase - REASON: ");
330         }
331         else
332         {
333                 if (turn == Piece::RED)
334                 {
335                         logMessage("Game ends on RED's turn - REASON: ");       
336                 }
337                 else if (turn == Piece::BLUE)
338                 {
339                         logMessage("Game ends on BLUE's turn - REASON: ");
340                 }
341                 else
342                 {
343                         logMessage("Game ends on ERROR's turn - REASON: ");
344                         
345                 }
346         }
347         switch (result.type)
348         {
349                 case MovementResult::OK:
350                         logMessage("Status returned OK, unsure why game halted...\n");
351                         break;
352                 case MovementResult::DIES:
353                         logMessage("Status returned DIES, unsure why game halted...\n");
354                         break;
355                 case MovementResult::KILLS:
356                         logMessage("Status returned KILLS, unsure why game halted...\n");
357                         break;
358                 case MovementResult::BOTH_DIE:
359                         logMessage("Status returned BOTH_DIE, unsure why game halted...\n");
360                         break;
361                 case MovementResult::NO_BOARD:
362                         logMessage("Board does not exit?!\n");
363                         break;
364                 case MovementResult::INVALID_POSITION:
365                         logMessage("Coords outside board\n");
366                         break;
367                 case MovementResult::NO_SELECTION:
368                         logMessage("Move does not select a piece\n");
369                         break;
370                 case MovementResult::NOT_YOUR_UNIT:
371                         logMessage("Selected piece belongs to other player\n");
372                         break;
373                 case MovementResult::IMMOBILE_UNIT:
374                         logMessage("Selected piece is not mobile (FLAG or BOMB)\n");
375                         break;
376                 case MovementResult::INVALID_DIRECTION:
377                         logMessage("Selected unit cannot move that way\n");
378                         break;
379                 case MovementResult::POSITION_FULL:
380                         logMessage("Attempted move into square occupied by neutral or allied piece\n");
381                         break;
382                 case MovementResult::VICTORY_FLAG:
383                         logMessage("Captured the flag\n");
384                         break;
385                 case MovementResult::VICTORY_ATTRITION:
386                         logMessage("Destroyed all mobile enemy pieces\n");
387                         break;
388                 case MovementResult::BAD_RESPONSE:
389                         logMessage("Unintelligable response\n");
390                         break;
391                 case MovementResult::NO_MOVE:
392                         logMessage("Response timeout after %2f seconds.\n", timeoutTime);
393                         break;
394                 case MovementResult::COLOUR_ERROR:
395                         logMessage("Internal controller error - COLOUR_ERROR\n");
396                         break;
397                 case MovementResult::ERROR:
398                         logMessage("Internal controller error - Unspecified ERROR\n");
399                         break;
400                 case MovementResult::DRAW_DEFAULT:
401                         logMessage("Game declared a draw after %d turns\n", turnCount);
402                         break;
403                 case MovementResult::DRAW:
404                         logMessage("Game declared a draw because neither player has mobile pieces\n");
405                         break;
406                 case MovementResult::SURRENDER:
407                         logMessage("This player has surrendered!\n");
408                         break;
409                 case MovementResult::BAD_SETUP:
410                         switch (turn)
411                         {
412                                 case Piece::RED:
413                                         logMessage("An illegal setup was made by RED\n");
414                                         break;
415                                 case Piece::BLUE:
416                                         logMessage("An illegal setup was made by BLUE\n");
417                                         break;
418                                 case Piece::BOTH:
419                                         logMessage("An illegal setup was made by BOTH players\n");
420                                         break;
421                                 case Piece::NONE:
422                                         logMessage("Unknown internal error.\n");
423                                         break;
424                         }
425                         break;
426
427
428         }
429
430         if (printBoard)
431         {
432                 system("clear");
433                 fprintf(stdout, "%d Final State\n", turnCount);
434                 theBoard.PrintPretty(stdout, Piece::BOTH);
435                 fprintf(stdout, "\n");
436         }
437
438         #ifdef BUILD_GRAPHICS
439         if (graphicsEnabled && log == stdout)
440         {
441                 logMessage("CLOSE WINDOW TO EXIT\n");
442                 theBoard.Draw(Piece::BOTH);
443                 while (true)
444                 {
445                         SDL_Event  event;
446                         while (SDL_PollEvent(&event))
447                         {
448                                 switch (event.type)
449                                 {
450                                         case SDL_QUIT:
451                                                 exit(EXIT_SUCCESS);
452                                                 break;
453                                 }
454                         }                       
455                 }
456         }
457         else
458         #endif //BUILD_GRAPHICS
459         {
460                 if (log == stdout)
461                 {
462                         logMessage("PRESS ENTER TO EXIT\n");
463                         while (fgetc(stdin) != '\n');
464                         exit(EXIT_SUCCESS); //Might want to actually exit, you foolish fool
465                 }
466         }
467
468 }
469 /** Checks for victory by attrition (destroying all mobile pieces)
470  *
471  *  @returns OK for no victory, 
472  *      DRAW if both players have no pieces, or 
473  *      VICTORY_ATTRITION  if the current player has won by attrition
474  */
475 MovementResult Game::CheckVictoryAttrition()
476 {
477         if (theBoard.MobilePieces(Piece::OppositeColour(turn)) == 0)
478         {
479                 if (theBoard.MobilePieces(turn) == 0)
480                         return MovementResult::DRAW;
481                 else
482                         return MovementResult::VICTORY_ATTRITION;
483         }
484         return MovementResult::OK;
485
486 }
487 MovementResult Game::Play()
488 {
489
490         MovementResult result = MovementResult::OK;
491         turnCount = 1;
492         string buffer;
493
494         Piece::Colour toReveal = reveal;
495         
496         
497         
498
499 //      logMessage("Messaging red with \"START\"\n");
500         red->Message("START");
501         
502         int moveCount = 0;
503
504         while (!Board::HaltResult(result) && (turnCount < maxTurns || maxTurns < 0))
505         {
506                 if (red->HumanController() && blue->HumanController())
507                         toReveal = Piece::RED;
508                 if (printBoard)
509                 {
510                         system("clear");
511                         if (turnCount == 0)
512                                 fprintf(stdout, "START:\n");
513                         else
514                                 fprintf(stdout, "%d BLUE:\n", turnCount);
515                         theBoard.PrintPretty(stdout, toReveal);
516                         fprintf(stdout, "\n\n");
517                 }
518
519                 #ifdef BUILD_GRAPHICS
520                 if (graphicsEnabled)
521                 {
522                         theBoard.Draw(toReveal);
523                         if (imageOutput != "")
524                         {
525                                 string imageFile = "" + imageOutput + "/"+ itostr(moveCount) + ".bmp";
526                                 Graphics::ScreenShot(imageFile.c_str());
527                         }
528
529                 }
530                 #endif //BUILD_GRAPHICS
531                 
532                 turn = Piece::RED;
533                 blue->Pause();
534                 red->Continue();
535                 if (!Board::HaltResult(result))
536                 {
537                         result = CheckVictoryAttrition();
538                 }
539                 if (Board::HaltResult(result))
540                         break;
541
542                 logMessage( "%d RED: ", turnCount);
543                 result = red->MakeMove(buffer);
544                 logMessage( "%s\n", buffer.c_str());
545
546                 if (!Board::HaltResult(result))
547                 {
548                         result = CheckVictoryAttrition();
549                 }
550                 if (Board::HaltResult(result))
551                         break;
552
553                 red->Message(buffer);
554                 blue->Message(buffer);
555
556
557
558
559                 if (stallTime >= 0)
560                         Wait(stallTime);
561                 else
562                         ReadUserCommand();
563
564                 if (blue->HumanController() && red->HumanController())
565                         toReveal = Piece::BLUE;
566                 if (printBoard)
567                 {
568                         system("clear");
569                         fprintf(stdout, "%d RED:\n", turnCount);
570                         theBoard.PrintPretty(stdout, toReveal);
571                         fprintf(stdout, "\n\n");
572                 }
573
574                 ++moveCount;
575                 
576                 #ifdef BUILD_GRAPHICS
577                 if (graphicsEnabled)
578                 {
579                         theBoard.Draw(toReveal);
580                         if (imageOutput != "")
581                         {
582                                 string imageFile = "" + imageOutput + "/" + itostr(moveCount) + ".bmp";
583                                 Graphics::ScreenShot(imageFile.c_str());
584                         }
585                 }
586                 #endif //BUILD_GRAPHICS
587
588                 
589                 
590                 turn = Piece::BLUE;
591                 red->Pause();
592                 blue->Continue();
593                 if (!Board::HaltResult(result))
594                 {
595                         result = CheckVictoryAttrition();
596                 }
597                 if (Board::HaltResult(result))
598                         break;
599
600                 logMessage( "%d BLU: ", turnCount);
601                 result = blue->MakeMove(buffer);
602                 logMessage( "%s\n", buffer.c_str());
603
604                 if (!Board::HaltResult(result))
605                 {
606                         result = CheckVictoryAttrition();
607                 }
608                 if (Board::HaltResult(result))
609                         break;
610
611                 red->Message(buffer);
612                 blue->Message(buffer);
613
614
615                 if (theBoard.MobilePieces(Piece::RED) == 0)
616                         result = MovementResult::DRAW;
617
618                 if (theBoard.MobilePieces(Piece::RED) == 0)
619                 {
620                         if (theBoard.MobilePieces(Piece::BLUE) == 0)
621                                 result = MovementResult::DRAW;
622                         else
623                                 result = MovementResult::VICTORY_ATTRITION;
624                         break;                  
625                 }
626
627                 if (stallTime >= 0)
628                         Wait(stallTime);
629                 else
630                         ReadUserCommand();
631         
632                 ++moveCount;
633
634                 ++turnCount;
635         }
636
637         if ((maxTurns >= 0 && turnCount >= maxTurns) && result == MovementResult::OK)
638         {
639                 result = MovementResult::DRAW_DEFAULT;
640         }
641
642         
643         return result;
644
645                 
646
647 }
648
649 /**
650  * Logs a message to the game's log file if it exists
651  * @param format the format string
652  * @param additional parameters - printed using va_args
653  * @returns the result of vfprintf or a negative number if the log file does not exist
654  */
655 int Game::logMessage(const char * format, ...)
656 {
657         if (log == NULL)
658                 return -666;
659                 va_list ap;
660         va_start(ap, format);
661
662         int result = vfprintf(log, format, ap);
663         va_end(ap);
664
665         return result;
666 }
667
668 /**
669  * Waits for a user command
670  * Currently ignores the command.
671  */
672 void Game::ReadUserCommand()
673 {
674         fprintf(stdout, "Waiting for user to press enter... (type QUIT to exit)\n");
675         string command("");
676         for (char c = fgetc(stdin); c != '\n' && (int)(c) != EOF; c = fgetc(stdin))
677         {
678                 command += c;
679         }
680
681         if (command == "QUIT")
682         {
683                 fprintf(stdout, "Ordered to quit... exiting...\n");
684                 exit(EXIT_SUCCESS);
685         }
686 }
687
688 MovementResult FileController::QuerySetup(const char * opponentName, std::string setup[])
689 {
690
691         char c = fgetc(file);
692         name = "";
693         while (c != ' ')
694         {
695                 name += c;
696                 c = fgetc(file);
697         }
698
699         while (fgetc(file) != '\n');
700
701         for (int y = 0; y < 4; ++y)
702         {
703                 setup[y] = "";
704                 for (int x = 0; x < Game::theGame->theBoard.Width(); ++x)
705                 {
706                         setup[y] += fgetc(file);
707                 }
708
709                 if (fgetc(file) != '\n')
710                 {
711                         return MovementResult::BAD_RESPONSE;
712                 }
713         }
714         return MovementResult::OK;
715
716         
717 }
718
719 MovementResult FileController::QueryMove(std::string & buffer)
720 {
721         //This bit is kind of hacky and terrible, and yes I am mixing C with C++
722         //Yes I should have used fstream for the whole thing and it would be much easier.
723         //Oh well.
724
725         char buf[BUFSIZ];
726
727         fgets(buf, sizeof(buf), file);
728         char * s = (char*)(buf);
729         while (*s != ':' && *s != '\0')
730                 ++s;
731         
732         //Move forward to the start of the move information
733         for (int i=0; i < 2; ++i)
734         {
735                 if (*s != '\0' && *s != '\n')
736                         ++s;
737         }
738         
739         //Unfortunately we can't just copy the whole line
740         buffer = string(s);
741         //We have to remove the movement result tokens
742         
743
744         vector<string> tokens;
745         Game::Tokenise(tokens, buffer, ' ');
746         buffer.clear();
747
748         if (tokens.size() < 1)
749                 return MovementResult::BAD_RESPONSE;
750         buffer += tokens[0];
751
752         
753         if (tokens[0] == "NO_MOVE") //tokens[0] is either the x coordinate, or "NO_MOVE"
754                 return MovementResult::OK;
755         if (tokens.size() < 2)
756                 return MovementResult::BAD_RESPONSE;
757         buffer += " ";
758         buffer += tokens[1]; //The y coordinate
759         buffer += " ";
760         buffer += tokens[2]; //The direction
761         
762         //Check for a possible multiplier. If tokens[3] is an integer it will be the multiplier, otherwise it won't be.
763         if (tokens.size() > 3 && atoi(tokens[3].c_str()) != 0)
764         {
765                 buffer += " ";
766                 buffer += tokens[3];
767         }
768         else
769         {
770                 //(tokens[3] should include a new line)
771                 //buffer += "\n";
772         }
773
774         
775
776         
777         
778         
779         return MovementResult::OK;
780 }
781
782 /**
783  * Tokenise a string
784  */
785 int Game::Tokenise(std::vector<string> & buffer, std::string & str, char split)
786 {
787         string token = "";
788         for (unsigned int x = 0; x < str.size(); ++x)
789         {
790                 if (str[x] == split && token.size() > 0)
791                 {
792                         buffer.push_back(token);
793                         token = "";
794                 }
795                 if (str[x] != split)
796                         token += str[x];
797         }
798         if (token.size() > 0)
799                 buffer.push_back(token);
800         return buffer.size();
801 }
802
803 /**
804  * Creates Controller baseds off strings. Takes into account controllers other than AI_Controller.
805  * @param redPath - Either the path to an AI_Controller compatable executable, or one of %human or %network or %network:[IP_ADDRESS]
806  * @param bluePath - Ditto
807  * Sets this->red to a controller using redPath, and this->blue to a controller using bluePath
808  * TODO: Make nicer (this function should be ~half the length)
809  */
810 void Game::MakeControllers(const char * redPath, const char * bluePath)
811 {
812         Network * redNetwork = NULL;
813         Network * blueNetwork = NULL;
814         //To allow for running two network controllers (I don't know why you would, but beside the point...) use two ports
815         static const int port1 = 4560;
816         static const int port2 = 4561;
817
818         if (redPath[0] == '@')
819         {
820                 if (strcmp(redPath, "@human") == 0)
821                         red = new Human_Controller(Piece::RED, graphicsEnabled);
822                 else
823                 {
824                         const char * network = strstr(redPath, "@network");
825                         if (network == NULL)
826                         {
827                                 red = NULL;
828                                 return;
829                         }
830                         network = strstr(network, ":");
831                 
832                         if (network == NULL)
833                         {
834                                 logMessage("Creating server for red AI... ");
835                                 redNetwork = new Server(port1);
836                                 logMessage("Successful!\n");
837
838                         }
839                         else
840                         {
841                                 network = (const char*)(network+1);
842                                 logMessage("Creating client for red AI... ");
843                                 redNetwork = new Client(network, port2);
844                                 logMessage("Connected to address %s\n", network);
845                         }
846
847                         logMessage("    (Red's responses will be received over the connection)\n");
848                         red = new NetworkReceiver(Piece::RED, redNetwork);
849                 }               
850         }
851         else
852                 red = new AI_Controller(Piece::RED, redPath, timeoutTime);
853
854         if (bluePath[0] == '@')
855         {
856                 if (strcmp(bluePath, "@human") == 0)
857                         blue = new Human_Controller(Piece::BLUE, graphicsEnabled);
858                 else
859                 {
860                         const char * network = strstr(bluePath, "@network");
861                         if (network == NULL)
862                         {
863                                 blue = NULL;
864                                 return;
865                         }
866                         network = strstr(network, ":");
867                 
868                         if (network == NULL)
869                         {
870                                 logMessage("Creating server for blue AI... ");
871                                 blueNetwork = new Server(port2);
872                                 logMessage("Successful!\n");
873
874                         }
875                         else
876                         {
877                                 network = (const char*)(network+1);
878                                 logMessage("Creating client for blue AI... ");
879                                 blueNetwork = new Client(network, port1);
880                                 logMessage("Connected to address %s\n", network);
881                         }
882                         logMessage("    (Blue's responses will be received over the connection)\n");
883                         blue = new NetworkReceiver(Piece::BLUE, blueNetwork);
884                 }               
885         }
886         else
887                 blue = new AI_Controller(Piece::BLUE, bluePath, timeoutTime);
888
889         if (redNetwork != NULL)
890         {
891                 
892                 blue = new NetworkSender(Piece::BLUE,blue, redNetwork);
893                 logMessage("    (Blue's responses will be copied over the connection)\n");
894         }
895         if (blueNetwork != NULL)
896         {
897                 
898                 red = new NetworkSender(Piece::RED, red, blueNetwork);
899                 logMessage("    (Red's responses will be copied over the connection)\n");
900         }
901
902         red->FixName(); blue->FixName();
903         
904 }
905
906 string itostr(int i)
907 {
908         stringstream s;
909         s << i;
910         return s.str();
911 }
912
913
914 void Game::PrintResults(const MovementResult & result, string & buffer)
915 {
916         stringstream s("");
917         switch (Game::theGame->Turn())
918         {
919                 case Piece::RED:
920                         s << Game::theGame->red->name << " RED ";
921                         break;
922                 case Piece::BLUE:
923                         s << Game::theGame->blue->name << " BLUE ";
924                         break;
925                 case Piece::BOTH:
926                         s << "neither BOTH ";
927                         break;
928                 case Piece::NONE:
929                         s << "neither NONE ";
930                         break;
931         }
932
933         if (!Board::LegalResult(result) && result != MovementResult::BAD_SETUP)
934                 s << "ILLEGAL ";
935         else if (!Board::HaltResult(result))
936                 s << "INTERNAL_ERROR ";
937         else
938         {
939                 switch (result.type)
940                 {
941                         case MovementResult::VICTORY_FLAG:
942                         case MovementResult::VICTORY_ATTRITION: //It does not matter how you win, it just matters that you won!
943                                 s <<  "VICTORY ";
944                                 break;
945                         case MovementResult::SURRENDER:
946                                 s << "SURRENDER ";
947                                 break;
948                         case MovementResult::DRAW:
949                                 s << "DRAW ";
950                                 break;
951                         case MovementResult::DRAW_DEFAULT:
952                                 s << "DRAW_DEFAULT ";
953                                 break;
954                         case MovementResult::BAD_SETUP:
955                                 s << "BAD_SETUP ";
956                                 break;  
957                         default:
958                                 s << "INTERNAL_ERROR ";
959                                 break;  
960                 }
961         }
962         
963         s << Game::theGame->TurnCount() << " " << Game::theGame->theBoard.TotalPieceValue(Piece::RED) << " " << Game::theGame->theBoard.TotalPieceValue(Piece::BLUE);
964
965         buffer = s.str();
966         
967
968 }
969

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