#ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #ifdef TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_LOCALE_H # include #endif #include "IntlDefs.h" #include "rotate_and_fire.h" namespace std { } using namespace std; RotateAndFire::RotateAndFire(const char* name, const char* colour) { robot_name = new char[strlen(name) + 1]; strcpy(robot_name, name); robot_colour = new char[strlen(colour) + 1]; strcpy(robot_colour, colour); quitting = false; robot_rotate = 0.53; acceleration = 0.54; brake_value = 0.0; // Get random seed from the clock // timeval current_time; // gettimeofday(¤t_time, NULL); // srand(current_time.tv_usec); // We want to know when RotateTo and RotateAmount finishes robot_option( SEND_ROTATION_REACHED, 1 ); } RotateAndFire::~RotateAndFire() { delete [] robot_name; delete [] robot_colour; } // Function for sending messages from robot. // They do nothing but write the command and its arguments to cout. void RotateAndFire::robot_option( const int option, const int value ) { cout << "RobotOption " << option << " " << value << endl; } void RotateAndFire::name( const char* name ) { cout << "Name " << name << endl; } void RotateAndFire::colour( const char* home, const char* away ) { cout << "Colour " << home << " " << away << endl; } void RotateAndFire::rotate( const int what, const double vel ) { cout << "Rotate " << what << " " << vel << endl; } void RotateAndFire::rotate_to( const int what, const double vel, const double angle ) { cout << "RotateTo " << what << " " << vel << " " << angle << endl; } void RotateAndFire::rotate_amount( const int what, const double vel, const double angle ) { cout << "RotateAmount " << what << " " << vel << " " << angle << endl; } void RotateAndFire::sweep( const int what, const double vel, const double left, const double right ) { cout << "Sweep " << what << " " << vel << " " << left << " " << right << endl; } void RotateAndFire::accelerate( const double amount ) { cout << "Accelerate " << amount << endl; } void RotateAndFire::brake( const double amount ) { cout << "Brake " << amount << endl; } void RotateAndFire::shoot( const double energy ) { cout << "Shoot " << energy << endl; } void RotateAndFire::print( const char* message ) { cout << "Print " << message << endl; } void RotateAndFire::debug( const char* message ) { cout << "Debug " << message << endl; } void RotateAndFire::debug_line( const double start_angle, const double start_radius, const double end_angle, const double end_radius ) { cout << "DebugLine " << start_angle << " " << start_radius << " " << end_angle << " " << end_radius << endl; } void RotateAndFire::debug_circle( const double center_angle, const double center_radius, const double circle_radius ) { cout << "DebugCircle " << center_angle << " " << center_radius << " " << circle_radius << endl; } // Here are all functions that is called whenever a message of // corresponding type is recieved. // Send name and colour if it is the first sequence. void RotateAndFire::initialize( const int first_seq ) { if( first_seq == 1 ) { name( robot_name ); colour( robot_colour, robot_colour ); } } // The name the robot got in the game. void RotateAndFire::your_name( const char* prev_name ) { } // The colour the robot got in the game. void RotateAndFire::your_colour( const char* colour ) { } // This function is called when a game option is changed and // the robot's copy of this option will change. void RotateAndFire::game_option( const int option, const double value ) { switch( option ) { case ROBOT_MAX_ROTATE: robot_max_rotate = value; break; case ROBOT_CANNON_MAX_ROTATE: robot_cannon_max_rotate = value; break; case ROBOT_RADAR_MAX_ROTATE: robot_radar_max_rotate = value; break; case ROBOT_MAX_ACCELERATION: robot_max_acceleration = value; break; case ROBOT_MIN_ACCELERATION: robot_min_acceleration = value; break; case ROBOT_START_ENERGY: robot_start_energy = value; break; case ROBOT_MAX_ENERGY: robot_max_energy = value; break; case ROBOT_ENERGY_LEVELS: robot_energy_levels = value; break; case SHOT_SPEED: shot_speed = value; break; case SHOT_MIN_ENERGY: shot_min_energy = value; break; case SHOT_MAX_ENERGY: shot_max_energy = value; break; case SHOT_ENERGY_INCREASE_SPEED: shot_energy_increase_speed = value; break; case TIMEOUT: timeout = value; break; case DEBUG_LEVEL: debug_level = value; break; case SEND_ROBOT_COORDINATES: send_robot_coordinates = (int)rint(value); break; } } // Reset the robot when a new game starts. Send initial rotate and // accelerate commands. void RotateAndFire::game_starts() { robot_rotate = 0.53; acceleration = 0.54; brake_value = 0.0; rotate_allowed = true; shots_hit = 0; last_shot_hit_time = -2.0; current_time = 0; radar_and_cannon_rotate = robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate; rotate( 1, robot_rotate ); rotate( 6, radar_and_cannon_rotate ); accelerate( acceleration ); } // Radar info when no object is seen, should never happen. void RotateAndFire::radar_noobject( const double dist, const double angle ) { } // Radar info when robot is seen. // Lock cannon and radar on the seen robot, // and if it is near enough, begin to brake. Shoot at it. void RotateAndFire::radar_robot( const double dist, const double angle ) { if( radar_and_cannon_rotate != - robot_rotate ) { radar_and_cannon_rotate = - robot_rotate; rotate( 6, radar_and_cannon_rotate ); } if( dist < 2 && acceleration != 0.0 ) { acceleration = 0.0; accelerate( acceleration ); brake_value = 1.0; brake( brake_value ); if( debug_level >= 1 ) cout << "Debug "<< _("Brakes locked: Robot found and at distance") << " " << dist << endl; } shoot( 2 ); } // Radar info when a shot is seen. void RotateAndFire::radar_shot( const double dist, const double angle ) { if( radar_and_cannon_rotate != robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate ) { radar_and_cannon_rotate = robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate; rotate( 6, radar_and_cannon_rotate ); } } // Radar info when a wall is seen. // If a wall is near in the robot direction, begin to brake, // else have normal acceleration. void RotateAndFire::radar_wall( const double dist, const double angle ) { if( radar_and_cannon_rotate != robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate ) { radar_and_cannon_rotate = robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate; rotate( 6, radar_and_cannon_rotate ); } double old_acc = acceleration; double mod_angle = fmod( angle, 2 * M_PI ); if( mod_angle < 1 * M_PI / 3 || mod_angle > 5 * M_PI / 3 ) { if( dist < 1.0 ) { acceleration = 0.0; brake_value = 1.0; } else { acceleration = 1.0; brake_value = 0.0; } } if( old_acc != acceleration ) { accelerate( acceleration ); brake( brake_value ); if( debug_level >= 4 ) { cout << "Debug " << _("Acceleration") << ": " << acceleration << endl; cout << "Debug " << _("Brake") << ": " << brake_value << endl; } if( debug_level == 5 ) cout << "Debug " << _("Modular angle, Angle") << ": " << mod_angle << ", " << angle << endl; } } // Radar info when a cookie is seen. void RotateAndFire::radar_cookie( const double dist, const double angle ) { if( radar_and_cannon_rotate != robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate ) { radar_and_cannon_rotate = robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate; rotate( 6, radar_and_cannon_rotate ); } if( debug_level >= 2 ) { cout << "Debug " << _("Cookie found at") << " (" << current_x_coordinate + dist*cos(angle + current_robot_angle) << "," << current_y_coordinate + dist*sin(angle + current_robot_angle) << ")" << endl; cout << "Debug " << _("I am at") << " " << " (" << current_x_coordinate << "," << current_y_coordinate << ") " << _("at angle") << " " << current_robot_angle << endl; } } // Radar info when a mine is seen. void RotateAndFire::radar_mine( const double dist, const double angle ) { if( radar_and_cannon_rotate != robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate ) { radar_and_cannon_rotate = robot_cannon_max_rotate - fabs(robot_rotate) - robot_rotate; rotate( 6, radar_and_cannon_rotate ); } shoot( shot_min_energy ); if( debug_level >= 2 ) { cout << "Debug " << _("Mine found at") << " (" << current_x_coordinate + dist*cos(angle + current_robot_angle) << "," << current_y_coordinate + dist*sin(angle + current_robot_angle) << ")" << endl; cout << "Debug " << _("I am at") << " " << " (" << current_x_coordinate << "," << current_y_coordinate << ") " << _("at angle") << " " << current_robot_angle << endl; } } // Information about the position of the robot. Coordinates are given either absolute, // relative to the starting position, or not at all, depending on the option // SEND_ROBOT_COORDINATES. void RotateAndFire::coordinates( const double x, const double y, const double rotation) { if( send_robot_coordinates == 0 ) return; current_x_coordinate = x; current_y_coordinate = y; current_robot_angle = rotation; } // Get information about time, speed and cannon_angle // Update current time and check how long time has passed since // we were last hit by a shot. void RotateAndFire::info( const double time, const double speed, const double cannon_angle ) { current_time = time; if( current_time - last_shot_hit_time > 2.0 ) shots_hit = 0; } // Information about seen robots void RotateAndFire::robot_info( const double energy, int enemy ) { } // Check if rotation has been reached. // If it is the robot. Begin normal acceleration and rotation void RotateAndFire::rotation_reached( const int what ) { if( what & 1 == 1 ) { rotate_allowed = true; acceleration_change_allowed = true; int direction = rand() / (RAND_MAX/2); if( direction == 0 ) direction = -1; robot_rotate = 0.53 * direction; acceleration = 1.0; accelerate( acceleration ); } } // Our energy level. void RotateAndFire::energy( const double energylevel ) { } // How many robots is left in the game. void RotateAndFire::robots_left( const int number_of_robots ) { number_of_robots_left = number_of_robots; } // We have collided with no object. Should not happen. void RotateAndFire::collision_noobject( const double angle ) { } // We have collided with another robot. void RotateAndFire::collision_robot( const double angle ) { } // We have collided with a shot. // Set last_shot_hit_time and increase shots_hit. // If shots_hit is too high, begin fleeing acceleration and rotation. void RotateAndFire::collision_shot( const double angle ) { shots_hit++; last_shot_hit_time = current_time; if( debug_level == 5 ) cout << "Debug Number of shots hit " << shots_hit << endl; if( shots_hit > 5 ) { int direction = rand() / (RAND_MAX/2); if( direction == 0 ) direction = -1; robot_rotate = robot_max_rotate * direction; rotate_amount( 1, robot_rotate, M_PI / 2 ); rotate_allowed = false; acceleration = robot_max_acceleration; accelerate( acceleration ); acceleration_change_allowed = false; if( debug_level >= 3 ) { cout << "Debug " << _("New rotation") << ": " << robot_rotate << endl; cout << "Debug " << _("New acceleration") << ": " << acceleration << endl; } shots_hit = 0; print( _("Hit too many times! Flee!") ); } } // We have collided with a wall. void RotateAndFire::collision_wall( const double angle ) { } // We have collided with a cookie. void RotateAndFire::collision_cookie( const double angle ) { print( _("Cookie eaten!") ); } // We have collided with a mine. void RotateAndFire::collision_mine( const double angle ) { print( _("Oh no! A mine") ); } // We have received a warning message. // Print the message. void RotateAndFire::warning( const int type, const char* message ) { char full_message[200]; switch( type ) { case UNKNOWN_MESSAGE: strcpy( full_message, _("Unknown message: ") ); break; case PROCESS_TIME_LOW: strcpy( full_message, _("Process time low: ") ); break; case MESSAGE_SENT_IN_ILLEGAL_STATE: strcpy( full_message, _("Message sent in illegal state: ") ); break; case UNKNOWN_OPTION: strcpy( full_message, _("Unknown option: ") ); break; case OBSOLETE_KEYWORD: strcpy( full_message, _("Obsolete Keyword: ") ); break; } strcat( full_message, message ); print( full_message ); } // Unfortunately we have died. void RotateAndFire::dead() { } // The game has finished void RotateAndFire::game_finishes() { } // You have been ordered to exit the robot void RotateAndFire::exit_robot() { print( _("Shutting down and leaving") ); quitting = true; } // This function is called before checking messages. // Every hundred time, change the direction of the rotation. void RotateAndFire::pre_checking_messages() { if(rand() < (RAND_MAX/200) && rotate_allowed ) { robot_rotate = -robot_rotate; rotate( 1, robot_rotate ); if( debug_level >= 2 ) cout << "Debug " << _("New") << " robot_rotate : " << robot_rotate << endl; } } // This function handles all the message checking and // calls the appropriate function. // This function is called whenever a SIGUSR1 (decided in the // robotoption sent to the server) signal is received. void RotateAndFire::check_messages( ) { quitting = false; char msg_name[81]; message_to_robot_type msg_t; cin.clear(); while( !cin.eof() && !quitting ) { pre_checking_messages(); cin >> msg_name; msg_t = name2msg_to_robot_type(msg_name); switch(msg_t) { case INITIALIZE: { int init; cin >> init; initialize( init ); } break; case YOUR_NAME: { char name[81]; cin >> name; your_name( name ); } break; case YOUR_COLOUR: { char col[81]; cin >> col; your_colour( col ); } break; case GAME_OPTION: { int nr; double value; cin >> nr >> value; game_option( nr, value ); } break; case GAME_STARTS: game_starts(); break; case RADAR: { double dist, angle; int object; cin >> dist >> object >> angle; switch(object) { case NOOBJECT: radar_noobject( dist, angle ); break; case ROBOT: radar_robot( dist, angle ); break; case WALL: radar_wall( dist, angle ); break; case SHOT: radar_shot( dist, angle ); break; case COOKIE: radar_cookie( dist, angle ); break; case MINE: radar_mine( dist, angle ); break; default: cout << "Print" << _("Unknown Object seen!") << endl; break; } } break; case COORDINATES: { double x, y, rotation; cin >> x >> y >> rotation; coordinates( x, y, rotation ); } break; case INFO: { double time, speed, cannon_angle; cin >> time >> speed >> cannon_angle; info( time, speed, cannon_angle ); } break; case ROBOT_INFO: { double energy; int enemy; cin >> energy >> enemy; robot_info( energy, enemy ); } break; case ROTATION_REACHED: { int what; cin >> what; rotation_reached( what ); } break; case ENERGY: { double en; cin >> en; energy( en ); } break; case ROBOTS_LEFT: { int nr; cin >> nr; robots_left( nr ); } break; case COLLISION: { int object; double angle; cin >> object >> angle; switch( object ) { case NOOBJECT: collision_noobject( angle ); break; case ROBOT: collision_robot( angle ); break; case WALL: collision_wall( angle ); break; case SHOT: collision_shot( angle ); break; case COOKIE: collision_cookie( angle ); break; case MINE: collision_mine( angle ); break; default: cout << "Print " << _("Collided with Unknown Object!") << endl; break; } } break; case WARNING: { int type; char text[81]; cin >> type; cin.getline(text,80,'\n'); warning( type, text ); } break; case DEAD: dead(); break; case GAME_FINISHES: game_finishes(); break; case EXIT_ROBOT: exit_robot(); break; default: break; } } } // A function to convert the messagename to an enum message_to_robot_type message_to_robot_type name2msg_to_robot_type(char* msg_name) { for(int i=0; message_to_robot[i].msg[0] != '\0'; i++) { if( strcmp(message_to_robot[i].msg, msg_name) == 0 ) return (message_to_robot_type)i; } return UNKNOWN_MESSAGE_TO_ROBOT; }