ArenaRealTime.cc

Go to the documentation of this file.
00001 /*
00002 RealTimeBattle, a robot programming game for Unix
00003 Copyright (C) 1998-2000  Erik Ouchterlony and Ragnar Ouchterlony
00004 
00005 This program is free software; you can redistribute it and/or modify
00006 it under the terms of the GNU General Public License as published by
00007 the Free Software Foundation; either version 2 of the License, or
00008 (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software Foundation,
00017 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 
00021 #ifdef HAVE_CONFIG_H
00022 #include <config.h>
00023 #endif
00024 
00025 #include <math.h>
00026 #include <signal.h>
00027 #include <unistd.h>
00028 #include <stdlib.h>
00029 #include <iostream>
00030 #include <iomanip>
00031 #include <stdarg.h>
00032 #include <sys/stat.h>
00033 #include <stdio.h>
00034 
00035 using namespace std;
00036 
00037 //#include "Gui.h"
00038 #include "ArenaRealTime.h"
00039 #include "ArenaController.h"
00040 #include "ArenaWindow.h"
00041 //#include "MovingObject.h"
00042 //#include "Shape.h"
00043 #include "IntlDefs.h"
00044 #include "Extras.h"
00045 #include "Various.h"
00046 #include "String.h"
00047 #include "Shot.h"
00048 #include "Options.h"
00049 #include "Wall.h"
00050 #include "Robot.h"
00051 #ifndef NO_GRAPHICS
00052 # include "ScoreWindow.h"
00053 # include "ControlWindow.h"
00054 # include "MessageWindow.h"
00055 #endif
00056 
00057 #ifndef NO_GRAPHICS
00058 extern class ControlWindow* controlwindow_p;
00059 #endif
00060 
00061 ArenaRealTime::ArenaRealTime()
00062 {
00063   set_game_mode( (ArenaBase::game_mode_t)the_arena_controller.game_mode );
00064   set_filenames( the_arena_controller.log_filename,
00065                  the_arena_controller.statistics_filename,
00066                  the_arena_controller.tournament_filename,
00067                  the_arena_controller.message_filename,
00068                  the_arena_controller.option_filename );
00069 
00070   robots_in_sequence = NULL;
00071 }
00072 
00073 ArenaRealTime::~ArenaRealTime()
00074 {
00075   for(int i=0; i < sequences_in_tournament; i++)
00076     delete [] robots_in_sequence[i];
00077 
00078   if( robots_in_sequence != NULL )
00079     delete robots_in_sequence;
00080 
00081   if( use_log_file && LOG_FILE ) LOG_FILE.close();
00082   if( use_message_file && message_file ) message_file.close();
00083 }
00084 
00085 
00086 void
00087 ArenaRealTime::clear()
00088 {
00089   delete_lists(true, true, true, true);
00090 
00091   for(int i=0; i < sequences_in_tournament; i++)
00092     delete [] robots_in_sequence[i];
00093 
00094   sequence_nr = 0;
00095   sequences_in_tournament = 0;
00096   
00097   set_state( NOT_STARTED );
00098 }
00099 
00100 void
00101 ArenaRealTime::set_filenames( String& log_fname,
00102                               const String& statistics_fname, 
00103                               const String& tournament_fname,
00104                               String& message_fname,
00105                               const String& option_fname )
00106 {
00107   bool log_stdout = false;
00108 
00109   if( log_fname == "" )
00110     {
00111       use_log_file = false;
00112     }
00113   else if( log_fname == "-" || log_fname == "STDOUT" )  // use stdout as log_file
00114     {
00115       cout << "Attach -- Muss gefixt werden in ArenaREaltime.cc 113" << endl;
00116       //LOG_FILE.attach(STDOUT_FILENO);
00117       use_log_file = true;
00118       log_stdout = true;
00119     }
00120   else
00121     {
00122        //LOG_FILE.open(log_fname.chars(), ios::out, S_IRUSR | S_IWUSR);
00123                 LOG_FILE.open(log_fname.chars(), ios::out);
00124                 
00125       use_log_file = true;
00126       if( !LOG_FILE )
00127         {
00128           Error( false, "Couldn't open log file. Contuing without log file",
00129                  "ArenaRealTime::set_filenames" );
00130           use_log_file = false;
00131         }
00132     }
00133   if( message_fname == "" )
00134     {
00135       use_message_file = false;
00136     }
00137   else if( message_fname == "-" || message_fname == "STDOUT" )
00138     {
00139       if( !log_stdout )
00140         {
00141           use_message_file = true;
00142           //message_file.attach( STDOUT_FILENO );
00143         }
00144       else
00145         {
00146           use_message_file = false;
00147         }
00148     }
00149   else
00150     {
00151       use_message_file = true;
00152       //message_file.open( message_fname.chars(), ios::out, S_IRUSR | S_IWUSR );
00153       if( !message_file )
00154         {
00155           Error( false, "Couldn't open message file. Message file disabled",
00156                  "ArenaRealTime::set_filenames" );
00157           use_message_file = false;
00158         }
00159       
00160     }
00161 
00162   statistics_file_name = statistics_fname;
00163 
00164   tournament_file_name = tournament_fname;
00165 
00166   option_file_name = option_fname;
00167 }
00168 
00169 void
00170 ArenaRealTime::parse_arena_file(String& filename)
00171 {
00172   Vector2D vec1, vec2, vec0;
00173 
00174   ifstream file(filename.chars());
00175   if( !file ) Error(true, "Couldn't open arena file" + filename, "ArenaBase::parse_arena_file");
00176 
00177   int succession = 1;
00178   double scale = the_opts.get_d(OPTION_ARENA_SCALE);
00179   double angle_factor = 1.0;
00180   do
00181     {
00182       parse_arena_line(file, scale, succession, angle_factor);
00183 
00184     } while( !file.eof() );
00185 
00186   file.close();
00187 
00188   
00189   if( use_log_file )      // copy the arena file to the log file
00190     {
00191       char buffer[500];
00192       
00193       ifstream file(filename.chars());
00194       if( !file ) Error(true, "Couldn't open arena file for log file" + filename, "ArenaBase::parse_arena_file");
00195   
00196       do
00197         {
00198           file >> ws;
00199           file.get(buffer, 500, '\n');
00200           if( buffer[0] != '\0' ) print_to_logfile('A', buffer);
00201         } 
00202       while( buffer[0] != '\0' );
00203       
00204     }
00205 
00206 }
00207 
00208 void
00209 ArenaRealTime::print_to_logfile(const char first_letter ... )
00210 {
00211   if( !use_log_file ) return;
00212 
00213   va_list args;
00214   va_start(args, first_letter);
00215 
00216   // log 'R' only each OPTION_LOG_EVERY_NTH_UPDATE_INTERVAL
00217   if( update_count_for_logging != 0 && first_letter == 'R' )
00218     {
00219       va_end(args);
00220       return;
00221     }
00222 
00223   LOG_FILE << first_letter;
00224 
00225   int prec = 2;
00226   LOG_FILE << setiosflags(ios::fixed) << setprecision(prec);
00227 
00228   switch(first_letter)
00229     {
00230     case 'R': // Robot position info
00231       LOG_FILE << va_arg(args, int   ) << " ";     // robot id;
00232       LOG_FILE << va_arg(args, double) << " ";  // x
00233       LOG_FILE << va_arg(args, double) << " ";  // y
00234       LOG_FILE << va_arg(args, double) << " ";  // robot angle
00235       LOG_FILE << va_arg(args, double) << " ";  // cannon angle
00236       LOG_FILE << va_arg(args, double) << " ";  // radar angle
00237       LOG_FILE << va_arg(args, double);         // energy
00238       break;
00239 
00240     case 'T': // Time
00241       LOG_FILE << setprecision(prec+1) << va_arg(args, double);  // time elapsed
00242       break;
00243 
00244     case 'P': // Print a robot message
00245       LOG_FILE << va_arg(args, int   ) << " ";  // robot id
00246       LOG_FILE << va_arg(args, char* );         // message to print
00247       break;
00248 
00249     case 'C': // Cookie
00250       LOG_FILE << va_arg(args, int   ) << " ";  // cookie id
00251       LOG_FILE << va_arg(args, double) << " ";  // x
00252       LOG_FILE << va_arg(args, double);         // y
00253       break;
00254 
00255     case 'M': // Mine
00256       LOG_FILE << va_arg(args, int   ) << " ";  // mine id
00257       LOG_FILE << va_arg(args, double) << " ";  // x
00258       LOG_FILE << va_arg(args, double);         // y
00259       break;
00260 
00261     case 'S': // Shot
00262       LOG_FILE << va_arg(args, int   ) << " ";  // shot id
00263       LOG_FILE << va_arg(args, double) << " ";  // x
00264       LOG_FILE << va_arg(args, double) << " ";  // y
00265       LOG_FILE << setprecision(prec+1) << va_arg(args, double) << " ";  // dx/dt
00266       LOG_FILE << setprecision(prec+1) << va_arg(args, double);         // dy/dt
00267       break;
00268       
00269     case 'D': // Die
00270       {
00271         int obj_type = va_arg(args, int  );
00272         LOG_FILE << (char)obj_type    << " ";  // object type to kill
00273         LOG_FILE << va_arg(args, int) << " ";  // object id
00274         if( obj_type == 'R' )
00275           {
00276             LOG_FILE << setprecision(1) 
00277                      <<  va_arg(args, double) << " "; // robot points received
00278             LOG_FILE << va_arg(args, int);            // position this game
00279           }
00280       }
00281       break;
00282 
00283     case 'G': // Game begins
00284       LOG_FILE << va_arg(args, int  ) << " ";  // sequence number
00285       LOG_FILE << va_arg(args, int  ) << " ";  // game number
00286       //      LOG_FILE << va_arg(args, char*);         // arena filename
00287       break;
00288 
00289     case 'H': // Header
00290       LOG_FILE << va_arg(args, int  ) << " ";  // number of games per sequence
00291       LOG_FILE << va_arg(args, int  ) << " ";  // number of robots per sequence
00292       LOG_FILE << va_arg(args, int  ) << " ";  // number of sequences
00293       LOG_FILE << va_arg(args, int  ) << " ";  // number of robots
00294       //      LOG_FILE << va_arg(args, char*);         // name of optionfile
00295       break;
00296 
00297     case 'L': // List of robot properties
00298       {
00299         LOG_FILE << va_arg(args, int  ) << " ";  // robot id
00300         LOG_FILE << hex2str(va_arg(args, long )) << " ";  // robot colour
00301        
00302         String name = va_arg(args, char*);   // robot name
00303         if( name == "" ) name = "Anonymous";
00304         LOG_FILE << name;
00305       }
00306       break;
00307 
00308     case 'A': // Arena file line
00309       LOG_FILE << va_arg(args, char*);  // line of arena file
00310       break;
00311 
00312     case 'O':
00313       {
00314         char option_type = (char)va_arg(args, int);
00315         LOG_FILE << va_arg(args, char*);                        // Option label
00316         switch( option_type )
00317           {
00318           case 'D':
00319             LOG_FILE << String( va_arg(args, double) ).chars(); // Option value
00320             break;
00321           case 'L':
00322             LOG_FILE << String( va_arg(args, long) ).chars();   // Option value
00323             break;
00324           case 'H':
00325             LOG_FILE << hex2str( va_arg(args, long) ).chars();   // Option value
00326             break;
00327           case 'S':
00328             LOG_FILE << String( va_arg(args, char*) ).chars();   // Option value
00329             break;
00330           }
00331       }
00332       break;
00333 
00334     default:
00335       Error(true, "Unrecognized first letter in logfile", "ArenaRealTime::print_to_logfile");
00336       break;
00337     }
00338 
00339   LOG_FILE << endl;
00340   va_end(args);
00341 }
00342 
00343 Vector2D
00344 ArenaRealTime::get_random_position()
00345 {
00346   return Vector2D( boundary[0][0] + (boundary[1][0] - boundary[0][0])*
00347                    (double)rand()/(double)RAND_MAX, 
00348                    boundary[0][1] + (boundary[1][1] - boundary[0][1])*
00349                    (double)rand()/(double)RAND_MAX );
00350 }
00351 
00352 void
00353 ArenaRealTime::broadcast(const message_to_robot_type msg_type ...)
00354 {
00355   va_list args;
00356   va_start(args, msg_type);
00357   String str = (String)message_to_robot[msg_type].msg + ' ';
00358   for(int i=0; i<message_to_robot[msg_type].number_of_args; i++)
00359     {
00360       switch(message_to_robot[msg_type].arg_type[i])
00361         {
00362         case NONE: 
00363           Error(true, "Couldn't send message, no arg_type", "ArenaRealTime::broadcast");
00364           break;
00365         case INT:
00366           str += (String)va_arg(args, int) + ' ';
00367           break;
00368         case DOUBLE:
00369           str += String(va_arg(args, double), 6) + ' ';
00370           break;
00371         case STRING:
00372           str += (String)va_arg(args, char*) + ' ';
00373           break;   
00374         case HEX:
00375           str += hex2str(va_arg(args, int)) + ' ';
00376           break;
00377         default:
00378           Error(true, "Couldn't send message, unknown arg_type", "ArenaRealTime::broadcast");
00379         }
00380     }
00381   str += '\n';
00382 
00383  ListIterator<Shape> li;
00384  for( object_lists[ROBOT].first(li); li.ok(); li++ )
00385     *(((Robot*)li())->get_outstreamp()) << str;
00386 }
00387 
00388 void
00389 ArenaRealTime::quit_ordered()
00390 {
00391   set_state( EXITING );
00392 }
00393 
00394 bool
00395 ArenaRealTime::timeout_function()
00396 {
00397 #ifndef NO_GRAPHICS
00398       int old_total = (int)total_time;
00399 #endif 
00400 
00401   if( state != PAUSED )
00402     {
00403       update_timer ();
00404     }
00405 
00406   switch(state)
00407     {
00408     case NOT_STARTED:
00409       if( the_arena_controller.auto_start_and_end )
00410         parse_tournament_file( tournament_file_name,
00411                                (StartTournamentFunction)
00412                                ArenaRealTime::start_tournament_from_tournament_file,
00413                                this );
00414       break;
00415 
00416     case FINISHED:
00417       if( the_arena_controller.auto_start_and_end )
00418         {
00419           if( statistics_file_name != "" )
00420             save_statistics_to_file( statistics_file_name );
00421 
00422           Quit();
00423         }
00424       break;
00425       
00426     case STARTING_ROBOTS:
00427       {
00428         read_robot_messages();
00429 
00430         if( total_time > next_check_time ) start_sequence_follow_up();
00431       }
00432       break;
00433       
00434     case SHUTTING_DOWN_ROBOTS:
00435       {     
00436         ListIterator<Robot> li;
00437         for( all_robots_in_sequence.first(li); li.ok(); li++ )
00438           li()->get_messages();
00439         
00440         if( total_time > next_check_time ) end_sequence_follow_up();
00441       }
00442       break;
00443       
00444     case GAME_IN_PROGRESS:
00445       {
00446         update();
00447 #ifndef NO_GRAPHICS
00448         if((int)total_time > old_total && !no_graphics)
00449           the_gui.get_scorewindow_p()->set_window_title();
00450 #endif
00451         if( robots_left <= 1 || total_time > the_opts.get_d(OPTION_TIMEOUT) ) 
00452           {
00453             end_game();
00454           }
00455         else
00456           {
00457             if( game_mode == COMPETITION_MODE && total_time > next_check_time ) check_robots();
00458             
00459             // Place mines and cookies
00460             if( ((double)rand()) / (double)RAND_MAX <= timestep*the_opts.get_d(OPTION_COOKIE_FREQUENCY) )
00461               add_cookie();
00462             
00463             if( ((double)rand()) / (double)RAND_MAX <= timestep*the_opts.get_d(OPTION_MINE_FREQUENCY) )
00464               add_mine();
00465 
00466               if( halt_next )
00467                 {
00468                   set_state( PAUSED );
00469                   halt_next = false;
00470                 }
00471           }
00472       }
00473       break;
00474 
00475     case PAUSED:
00476       break;
00477 
00478     case PAUSING_BETWEEN_GAMES:
00479       if( !pause_after_next_game ) start_game();
00480       break;
00481 
00482     case EXITING:
00483       return false;
00484       
00485     case BEFORE_GAME_START:
00486     case NO_STATE:
00487       Error(true, "Arena shouldn't be in this state here!!", "ArenaRealTime::timeout_function");
00488     }
00489 
00490   return true;
00491 }
00492 
00493 void
00494 ArenaRealTime::update()
00495 {
00496   print_to_logfile('T', total_time);
00497 
00498 #ifndef NO_GRAPHICS
00499   if( state == GAME_IN_PROGRESS && !no_graphics)
00500     the_gui.get_messagewindow_p()->freeze_clist();
00501 #endif
00502 
00503   read_robot_messages();
00504   move_shots(timestep);
00505   update_robots();
00506 
00507 #ifndef NO_GRAPHICS
00508   if( state == GAME_IN_PROGRESS && !no_graphics)
00509     {
00510       the_gui.get_arenawindow_p()->draw_moving_objects( true );
00511       the_gui.get_messagewindow_p()->thaw_clist();
00512     }
00513 #endif
00514 
00515   update_count_for_logging++;
00516   if( update_count_for_logging == the_opts.get_l(OPTION_LOG_EVERY_NTH_UPDATE_INTERVAL) )
00517     update_count_for_logging = 0;
00518 }
00519 
00520 void
00521 ArenaRealTime::add_cookie()
00522 {
00523   double en = the_opts.get_d(OPTION_COOKIE_MIN_ENERGY) + 
00524     (the_opts.get_d(OPTION_COOKIE_MAX_ENERGY) - the_opts.get_d(OPTION_COOKIE_MIN_ENERGY)) * 
00525     (double)rand() / (double)RAND_MAX;
00526   bool found_space = false;
00527   double r = the_opts.get_d(OPTION_COOKIE_RADIUS);
00528   Vector2D pos;
00529 
00530   for( int i=0; i<100 && !found_space; i++ )
00531     {
00532       pos = get_random_position();
00533       found_space = space_available(pos, r*2.0);
00534     }
00535   
00536   if( !found_space ) return;
00537 
00538   Cookie* cookiep = new Cookie(pos, en);
00539   object_lists[COOKIE].insert_last( cookiep );
00540 
00541   print_to_logfile('C', cookiep->get_id(), pos[0], pos[1]);
00542 }
00543 
00544 void
00545 ArenaRealTime::add_mine()
00546 {
00547   double en = the_opts.get_d(OPTION_MINE_MIN_ENERGY) + 
00548     (the_opts.get_d(OPTION_MINE_MAX_ENERGY) - the_opts.get_d(OPTION_MINE_MIN_ENERGY)) * 
00549     (double)rand() / (double)RAND_MAX;
00550   bool found_space = false;
00551   double r = the_opts.get_d(OPTION_MINE_RADIUS);
00552   Vector2D pos;
00553 
00554   for( int i=0; i<100 && !found_space; i++)
00555     {
00556       pos = get_random_position();
00557       found_space = space_available(pos, r*2.0);
00558     }
00559   
00560   if( !found_space )  return;
00561 
00562   Mine* minep = new Mine(pos, en);
00563   object_lists[MINE].insert_last( minep );
00564 
00565   print_to_logfile('M', minep->get_id(), pos[0], pos[1]);
00566 }
00567 
00568 void
00569 ArenaRealTime::check_robots()
00570 {
00571   ListIterator<Robot> li;
00572   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00573     {
00574       if( li()->is_process_running() )
00575         {
00576           li()->check_process();
00577         }      
00578     } 
00579 
00580   next_check_time = total_time + the_opts.get_d(OPTION_CHECK_INTERVAL);
00581 }
00582 
00583 void
00584 ArenaRealTime::read_robot_messages()
00585 {
00586   ListIterator<Robot> li;
00587   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00588     {
00589       if( li()->is_alive() || state != GAME_IN_PROGRESS )  
00590         li()->get_messages();
00591     }
00592 }
00593 
00594 void
00595 ArenaRealTime::update_robots()
00596 {
00597   Robot* robotp;
00598 
00599   robots_killed_this_round = 0;
00600 
00601   ListIterator<Shape> li;
00602   for( object_lists[ROBOT].first(li); li.ok(); li++ )
00603     {
00604       robotp = (Robot*)li();
00605       if( robotp->is_alive() )
00606         {
00607           robotp->update_radar_and_cannon(timestep);  
00608           robotp->change_velocity(timestep);
00609           robotp->move(timestep);        
00610         }
00611       if( robotp->is_alive() ) 
00612         robotp->get_messages();
00613     }
00614 
00615   // Check if robots have died and send energy level
00616 
00617   for( object_lists[ROBOT].first(li); li.ok(); li++ )
00618     {
00619       robotp = (Robot*)li();
00620       if( !robotp->is_alive() ) 
00621         {
00622           object_lists[ROBOT].remove(li);
00623           robots_killed_this_round++;
00624         }
00625       else
00626         {
00627           double lvls = (double)the_opts.get_l(OPTION_ROBOT_ENERGY_LEVELS);
00628           robotp->send_message( ENERGY, rint( robotp->get_energy() / lvls ) * lvls );
00629         }
00630     }
00631 
00632   robots_left -= robots_killed_this_round;
00633 
00634   if( robots_killed_this_round > 0 )
00635     {
00636       for( object_lists[ROBOT].first(li); li.ok(); li++ )
00637         {
00638           robotp = (Robot*)li();
00639           //          robotp->add_points(robots_killed_this_round);
00640 #ifndef NO_GRAPHICS
00641           if( robots_left < 15 && !no_graphics ) 
00642             robotp->display_score();
00643 #endif
00644         }
00645 
00646       ListIterator<Robot> li2;
00647       for( all_robots_in_sequence.first(li2); li2.ok(); li2++ )
00648         if( li2()->is_dead_but_stats_not_set() )
00649           li2()->set_stats(robots_killed_this_round);
00650       
00651       broadcast(ROBOTS_LEFT, robots_left);
00652     }
00653 
00654   
00655   for( object_lists[ROBOT].first(li); li.ok(); li++ )
00656     ((Robot*)li())->send_signal();
00657 }
00658 
00659 
00660 // coulor_dist is supposed to be a subjective distance between two colours, normalized
00661 // to be between 0.0 (same colour) and 1.0 (furthest away).
00662 double
00663 ArenaRealTime::colour_dist(const long col1, const long int col2)
00664 {
00665   double red1   = (col1 & 0x0000ff);
00666   double green1 = (col1 & 0x00ff00) >> 8;
00667   double blue1  = (col1 & 0xff0000) >> 16;
00668 
00669   double red2   = (col2 & 0x0000ff);
00670   double green2 = (col2 & 0x00ff00) >> 8;
00671   double blue2  = (col2 & 0xff0000) >> 16;
00672 
00673   return  ( fabs(red1  -red2  ) * log(1.0 + sqrt(red1  +red2  )) + 
00674             fabs(green1-green2) * log(1.0 + sqrt(green1+green2)) +
00675             fabs(blue1 -blue2 ) * log(1.0 + sqrt(blue1 +blue2 )) ) / 2417.8;
00676 
00677 
00678 //    return( ((double)abs((col1 & 0xff)*0x101 - col2.blue))*
00679 //            log(1.0 + sqrt((col1 & 0xff)*0x101 + col2.blue))/log(2.0) +
00680 //            ((double)abs(((col1 & 0xff00) >> 8)*0x101 - col2.green))*
00681 //            log(1.0 + sqrt(((col1 & 0xff00) >> 8)*0x101 + col2.green))/log(2.0) +
00682 //            ((double)abs(((col1 & 0xff0000) >> 16)*0x101 - col2.red))*
00683 //            log(1.0 + sqrt(((col1 & 0xff0000) >> 16)*0x101 + col2.red))/log(2.0));
00684 }
00685 
00686 bool
00687 ArenaRealTime::is_colour_allowed(const long colour, const double min_dist, const Robot* robotp)
00688 {
00689   double d;
00690   ListIterator<Robot> li;
00691 
00692   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00693     {
00694       if(li() != robotp)
00695         {
00696           d = colour_dist( colour, li()->get_rgb_colour() );
00697           if( d < min_dist ) return false;          
00698         }
00699     }
00700   
00701   d = colour_dist( colour, the_opts.get_l( OPTION_BACKGROUND_COLOUR ) );
00702   if( d < min_dist ) return false;
00703 
00704   return true;
00705 }
00706 
00707 long int
00708 ArenaRealTime::find_free_colour(const long int home_colour, 
00709                                  const long int away_colour, 
00710                                  const Robot* robotp, const bool random_colours)
00711 {  
00712   long int tmp_colour;
00713 
00714   for(double min_dist = 0.1; min_dist > 0.01 ; min_dist *= 0.8)
00715     {
00716       if( !random_colours )
00717         {
00718           if( is_colour_allowed(home_colour, min_dist, robotp) ) return home_colour;
00719           if( is_colour_allowed(away_colour, min_dist, robotp) ) return away_colour;
00720         }
00721       for(int i=0; i<25; i++)
00722         {
00723           tmp_colour = rand() & 0xffffff;
00724           if( is_colour_allowed(tmp_colour, min_dist*2, robotp) ) return tmp_colour;
00725         }                  
00726     }
00727    Error(true, "Impossible to find colour", "ArenaRealTime::find_free_colour");
00728 
00729    return 0;
00730 }
00731 
00732 int
00733 ArenaRealTime::set_debug_level( const int new_level)
00734 {
00735   ArenaBase::set_debug_level(new_level);
00736 
00737   if( GAME_IN_PROGRESS )
00738     {
00739       broadcast(GAME_OPTION, DEBUG_LEVEL, (double)debug_level);
00740     }
00741 
00742   return debug_level;
00743 }
00744 
00745 void
00746 ArenaRealTime::start_game()
00747 {
00748   // put the arena together
00749 
00750   if( pause_after_next_game )
00751     {
00752       set_state( PAUSING_BETWEEN_GAMES );
00753       return;
00754     }  
00755   
00756   current_arena_nr = current_arena_nr % number_of_arenas + 1;
00757   
00758   String* filename = arena_filenames.get_nth(current_arena_nr);
00759 
00760   print_to_logfile('G', sequence_nr, game_nr + 1);
00761 
00762   parse_arena_file(*filename);
00763 
00764   int charpos;
00765   if( (charpos = filename->find('/',0,true)) != -1 )
00766     current_arena_filename = get_segment(*filename, charpos+1, -1);
00767   else
00768     Error(true, "Incomplete arena file path" + *filename, "ArenaRealTime::start_game");
00769 
00770   char msg[128];
00771   snprintf( msg, 127, _("Game %d of sequence %d begins on arena"),
00772             game_nr+1, sequence_nr );
00773   print_message( "RealTimeBattle", String(msg) + " " + current_arena_filename );
00774 
00775   // reset some variables
00776 
00777   shot_count = 0;
00778   cookie_count = 0;
00779   mine_count = 0;
00780 
00781 
00782   // Place robots on the arena
00783 
00784   Robot* robotp;
00785   bool found_space;
00786   double angle;
00787   Vector2D pos;
00788 
00789   robots_left = 0;
00790   
00791   set_state( BEFORE_GAME_START );
00792 
00793   ListIterator<Robot> li;
00794   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00795     {
00796       robotp = li();
00797       robotp->get_messages();
00798 
00799       found_space = false;
00800       for( int i=0; i<100 && !found_space; i++)
00801         {
00802           pos = get_random_position();
00803           found_space = space_available(pos, the_opts.get_d(OPTION_ROBOT_RADIUS)*1.2);
00804         }
00805 
00806       if( !found_space ) Error(true, "Couldn't find space for all robots", "ArenaRealTime::start_game");
00807       angle = ((double)rand())*2.0*M_PI/RAND_MAX;
00808       robotp->set_values_before_game(pos, angle);
00809       object_lists[ROBOT].insert_last(robotp);
00810       robots_left++;
00811       robotp->live();
00812     }
00813 
00814   //  print_to_logfile('G', sequence_nr, games_per_sequence - games_remaining_in_sequence + 1);
00815 
00816   broadcast(GAME_STARTS);
00817   broadcast(ROBOTS_LEFT, robots_left);
00818   the_opts.broadcast_opts();
00819 
00820 
00821   update_count_for_logging = 0;
00822   print_to_logfile('T', 0.0);
00823 
00824   ListIterator<Shape> li2;
00825   for( object_lists[ROBOT].first(li2); li2.ok(); li2++ )
00826     {
00827       robotp = (Robot*)li2();
00828       robotp->send_signal();
00829       robotp->move(0.0);  // To log current position
00830     }
00831 
00832   set_state( GAME_IN_PROGRESS );
00833   game_nr++;
00834 
00835 #ifndef NO_GRAPHICS
00836   if( !no_graphics )
00837     {
00838       the_gui.get_arenawindow_p()->clear_area();
00839       the_gui.get_arenawindow_p()->drawing_area_scale_changed();
00840       the_gui.get_scorewindow_p()->update_robots();
00841 
00842       reset_timer();  // Time should be zero in score window
00843       the_gui.get_scorewindow_p()->set_window_title();
00844       the_gui.get_arenawindow_p()->set_window_title();
00845     }
00846 #endif
00847 
00848   reset_timer();  // Game starts !
00849   next_check_time = total_time + the_opts.get_d(OPTION_CHECK_INTERVAL);
00850 }
00851 
00852 void
00853 ArenaRealTime::end_game()
00854 {
00855   Robot* robotp;
00856   ListIterator<Robot> li;
00857 
00858   int robots_died_by_timeout = robots_left;
00859   robots_left = 0;
00860 
00861   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00862     {
00863       robotp = li();
00864       if( robotp->is_alive() || robotp->is_dead_but_stats_not_set() )
00865         {
00866           robotp->die();
00867           robotp->set_stats(robots_died_by_timeout, true);
00868         }
00869     }
00870 
00871   broadcast(GAME_FINISHES);
00872 
00873   delete_lists(false, false, false, false);
00874   
00875   if(game_nr == games_per_sequence) 
00876     end_sequence();
00877   else
00878     start_game();
00879 }
00880 
00881 
00882 void
00883 ArenaRealTime::start_sequence()
00884 {
00885   game_nr = 0;
00886   current_arena_nr = 0;
00887 
00888   // Make list of robots in this sequence
00889 
00890   for(int i=0; i<robots_per_game; i++)
00891     {
00892       all_robots_in_sequence.
00893         insert_last( all_robots_in_tournament.
00894                      get_nth(robots_in_sequence[sequence_nr][i]));
00895     }
00896 
00897   // execute robot processes
00898 
00899 
00900   Robot* robotp;
00901   ListIterator<Robot> li;
00902   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00903     {
00904       robotp = li();
00905       if( robotp->is_networked() )
00906         {
00907           *robotp->get_outstreamp() << "@R" << endl;
00908           robotp->set_values_at_process_start_up();
00909         }      
00910       else
00911         robotp->start_process();
00912     }
00913   
00914   // wait a second before checking
00915 
00916   set_state( STARTING_ROBOTS );
00917   sequence_nr++;
00918   reset_timer();
00919   next_check_time = total_time + the_opts.get_d(OPTION_ROBOT_STARTUP_TIME);
00920 }
00921 
00922 void
00923 ArenaRealTime::start_sequence_follow_up()
00924 {
00925   // check if the process have started correctly
00926   Robot* robotp = NULL;
00927 
00928   ListIterator<Robot> li;
00929   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00930     {
00931       robotp = li();
00932       if( !(robotp->is_networked()) &&
00933           !(robotp->is_process_running()) ) 
00934         {
00935           all_robots_in_sequence.remove(li);
00936           robots_left--;
00937         }
00938       else
00939         {      
00940           if( !robotp->set_and_get_has_competed() )
00941             print_to_logfile('L', robotp->get_id(), robotp->get_rgb_colour(), 
00942                              robotp->get_robot_name().chars());
00943           
00944           if( !robotp->is_name_given() )
00945             {
00946               robotp->send_message(WARNING, NAME_NOT_GIVEN, "");
00947               char msg[128];
00948               snprintf( msg, 127, _("Robot with filename %s has not given any name"),
00949                         robotp->get_robot_filename().chars() );
00950               print_message( "RealTimeBattle", String(msg) );
00951             }
00952 
00953           if( !robotp->is_colour_given() )
00954             {
00955               robotp->send_message(WARNING, COLOUR_NOT_GIVEN, "");
00956               robotp->set_colour( find_free_colour( 0, 0, robotp, true ) );
00957               robotp->set_colour_given( true );
00958             }
00959         }
00960 
00961     }
00962   start_game();
00963 }
00964 
00965 void
00966 ArenaRealTime::end_sequence()
00967 {
00968   // kill all robot processes
00969 
00970   ListIterator<Robot> li;
00971   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00972     {
00973       li()->end_process();
00974     }
00975 
00976   // wait a second before checking
00977 
00978   set_state( SHUTTING_DOWN_ROBOTS);
00979   next_check_time = total_time + 1.0;
00980 }
00981 
00982 void
00983 ArenaRealTime::end_sequence_follow_up()
00984 {
00985   // check if the process have stopped, otherwise kill
00986   
00987   Robot* robotp;
00988 
00989   ListIterator<Robot> li;
00990   for( all_robots_in_sequence.first(li); li.ok(); li++ )
00991     {
00992       robotp = li();
00993       if( robotp->is_process_running() ) robotp->kill_process_forcefully();
00994       robotp->delete_pipes();
00995       all_robots_in_sequence.remove(li);
00996     }
00997 
00998   if( sequence_nr == sequences_in_tournament ) 
00999     end_tournament();
01000   else
01001     start_sequence();
01002 }
01003 
01004 void
01005 ArenaRealTime::start_tournament_from_tournament_file
01006 ( const List<start_tournament_info_t>& robotfilename_list, 
01007   const List<start_tournament_info_t>& arenafilename_list, 
01008   const int robots_p_game, const int games_p_sequence, 
01009   const int n_o_sequences, ArenaRealTime* ar_p )
01010 {
01011   ar_p->start_tournament( robotfilename_list, arenafilename_list, robots_p_game,
01012                           games_p_sequence, n_o_sequences );
01013 }
01014 
01015 void
01016 ArenaRealTime::
01017 start_tournament(const List<start_tournament_info_t>& robotfilename_list, 
01018                  const List<start_tournament_info_t>& arenafilename_list, 
01019                  const int robots_p_game, 
01020                  const int games_p_sequence, 
01021                  const int n_o_sequences)
01022 {
01023   clear();
01024 
01025   // Open windows if they were closed, else clear them 
01026 
01027 #ifndef NO_GRAPHICS
01028   if( !no_graphics )
01029     {
01030       if( the_gui.is_messagewindow_up() )
01031         MessageWindow::clear_clist( NULL, the_gui.get_messagewindow_p() );
01032       else //if( !use_message_file )
01033         the_gui.open_messagewindow();
01034 
01035       if( !the_gui.is_scorewindow_up() ) the_gui.open_scorewindow();
01036       if( !the_gui.is_arenawindow_up() ) the_gui.open_arenawindow();
01037     }
01038 #endif
01039 
01040   // Create robot classes and put them into the list all_robots_in_tournament
01041 
01042   number_of_robots = 0;
01043   robot_count = 0;
01044   Robot* robotp;
01045   start_tournament_info_t* infop = NULL;
01046   String* stringp;
01047 
01048   ListIterator<start_tournament_info_t> li;
01049   for( robotfilename_list.first(li); li.ok(); li++ )
01050     {
01051       infop = li();
01052       robotp = new Robot(infop->filename);
01053       all_robots_in_tournament.insert_last( robotp );
01054       number_of_robots++;
01055     }
01056 
01057   // Create list of arena filenames
01058   number_of_arenas = 0;
01059   
01060   for( arenafilename_list.first(li); li.ok(); li++ )
01061     {
01062       stringp = new String(li()->filename);
01063       arena_filenames.insert_last( stringp );
01064       number_of_arenas++;
01065     }
01066 
01067   robots_per_game = robots_p_game;
01068   games_per_sequence = games_p_sequence;
01069   sequences_in_tournament = n_o_sequences;
01070 
01071   // make list of robots to compete in the sequences
01072   int games_per_round = binomial(number_of_robots, robots_per_game);
01073   int complete_rounds = n_o_sequences / games_per_round;
01074   int rem_games = n_o_sequences % games_per_round;
01075 
01076   robots_in_sequence = new (int*)[n_o_sequences];
01077   for(int i=0; i<n_o_sequences; i++) robots_in_sequence[i] = new int[robots_per_game];
01078   
01079   int current_sequence[robots_per_game];
01080   int current_nr = 0;
01081   //  for(int i=0; i<robots_per_game; i++) current_sequence[i] = i+1;
01082   
01083   // set complete rounds first
01084 
01085   for(int round_nr=0; round_nr < complete_rounds; round_nr++)
01086     {
01087       int k, i, j;
01088 
01089       for(i=0; i<robots_per_game; i++) current_sequence[i] = i+1;
01090       current_sequence[robots_per_game-1]--;   // To be increased first time
01091 
01092       
01093       for(i=0; i< games_per_round; i++)
01094         {
01095           
01096           k = robots_per_game - 1;
01097           while( current_sequence[k] == number_of_robots + 1 - robots_per_game + k )
01098             k--;
01099 
01100           if( k < 0 ) Error(true, "Problem generating list of participants, k < 0", 
01101                             "ArenaRealTime::start_tournament");
01102 
01103           current_sequence[k]++;
01104           for(j=k+1; j<robots_per_game; j++) current_sequence[j] = current_sequence[j-1]+1;
01105 
01106           for(j=0; j<robots_per_game; j++) 
01107             robots_in_sequence[current_nr][j] = current_sequence[j];
01108 
01109           current_nr++;
01110         }
01111       reorder_pointer_array((void**)robots_in_sequence, games_per_round);
01112     }
01113 
01114   // the remaining game will be randomly chosen
01115 
01116   int robot_matches_played[number_of_robots];
01117   for(int i=0; i<number_of_robots; i++) robot_matches_played[i] = 0;
01118 
01119   bool robot_playing_this_match[number_of_robots];
01120   int min_matches_played = 0;
01121   int number_of_robots_on_min_matches = number_of_robots;
01122   int nr;
01123 
01124   for(int i=0; i< rem_games; i++)
01125     {
01126       for(int i2=0; i2<number_of_robots; i2++) robot_playing_this_match[i2] = false;
01127 
01128       for(int j=0; j<robots_per_game; j++)
01129         {
01130           do 
01131             nr = (int)floor(number_of_robots*((double)rand() / (double)RAND_MAX));
01132           while( robot_playing_this_match[nr] || robot_matches_played[nr] != min_matches_played );
01133 
01134           robot_playing_this_match[nr] = true;
01135           robot_matches_played[nr]++;
01136           number_of_robots_on_min_matches--;
01137           if( number_of_robots_on_min_matches == 0 ) 
01138             {
01139               min_matches_played++;
01140               number_of_robots_on_min_matches = number_of_robots;
01141             }
01142 
01143           robots_in_sequence[current_nr][j] = nr + 1;   // robot count will start from 1
01144         }      
01145       current_nr++;
01146     }
01147 
01148   // set random seed
01149 
01150 
01151   srand(timer.get_random_seed());
01152 
01153   // start first sequence
01154 
01155   print_to_logfile('H', games_per_sequence, robots_per_game, 
01156                    sequences_in_tournament, number_of_robots);
01157 
01158   the_opts.log_all_options();
01159 
01160   sequence_nr = 0;
01161   start_sequence();
01162 }
01163 
01164 void
01165 ArenaRealTime::end_tournament()
01166 {
01167   set_state( FINISHED );
01168 
01169 #ifndef NO_GRAPHICS
01170   if( !no_graphics )
01171     {
01172       //      if( !use_message_file )
01173       //        the_gui.close_messagewindow();
01174       //      the_gui.close_scorewindow();
01175       the_gui.close_arenawindow();
01176     }
01177 #endif
01178 }

Generated on Fri Oct 15 15:47:35 2004 for Real Time Battle by  doxygen 1.3.9.1