/*! */ void TackleGenerator::generate( const WorldModel & wm ) { static GameTime s_update_time( 0, 0 ); if ( s_update_time == wm.time() ) { // dlog.addText( Logger::CLEAR, // __FILE__": already updated" ); return; } s_update_time = wm.time(); clear(); if ( wm.self().isKickable() ) { // dlog.addText( Logger::CLEAR, // __FILE__": kickable" ); return; } if ( wm.self().tackleProbability() < 0.001 && wm.self().foulProbability() < 0.001 ) { // dlog.addText( Logger::CLEAR, // __FILE__": never tacklable" ); return; } if ( wm.time().stopped() > 0 ) { // dlog.addText( Logger::CLEAR, // __FILE__": time stopped" ); return; } if ( wm.gameMode().type() != GameMode::PlayOn && ! wm.gameMode().isPenaltyKickMode() ) { // dlog.addText( Logger::CLEAR, // __FILE__": illegal playmode " ); return; } #ifdef DEBUG_PROFILE MSecTimer timer; #endif calculate( wm ); #ifdef DEBUG_PROFILE dlog.addText( Logger::CLEAR, __FILE__": PROFILE. elapsed=%.3f [ms]", timer.elapsedReal() ); #endif }
/*! */ void Strategy::updateSituation( const WorldModel & wm ) { M_current_situation = Normal_Situation; if ( wm.gameMode().type() != GameMode::PlayOn ) { if ( wm.gameMode().isPenaltyKickMode() ) { dlog.addText( Logger::TEAM, __FILE__": Situation PenaltyKick" ); M_current_situation = PenaltyKick_Situation; } else if ( wm.gameMode().isPenaltyKickMode() ) { dlog.addText( Logger::TEAM, __FILE__": Situation OurSetPlay" ); M_current_situation = OurSetPlay_Situation; } else { dlog.addText( Logger::TEAM, __FILE__": Situation OppSetPlay" ); M_current_situation = OppSetPlay_Situation; } return; } int self_min = wm.interceptTable()->selfReachCycle(); int mate_min = wm.interceptTable()->teammateReachCycle(); int opp_min = wm.interceptTable()->opponentReachCycle(); int our_min = std::min( self_min, mate_min ); if ( opp_min <= our_min - 2 ) { dlog.addText( Logger::TEAM, __FILE__": Situation Defense" ); M_current_situation = Defense_Situation; return; } if ( our_min <= opp_min - 2 ) { dlog.addText( Logger::TEAM, __FILE__": Situation Offense" ); M_current_situation = Offense_Situation; return; } dlog.addText( Logger::TEAM, __FILE__": Situation Normal" ); }
/*! */ void ShootGenerator::createShoot( const WorldModel & wm, const Vector2D & target_point ) { const AngleDeg ball_move_angle = ( target_point - M_first_ball_pos ).th(); const PlayerObject * goalie = wm.getOpponentGoalie(); if ( goalie && 5 < goalie->posCount() && goalie->posCount() < 30 && wm.dirCount( ball_move_angle ) > 3 ) { #ifdef DEBUG_PRINT dlog.addText( Logger::SHOOT, "%d: __ xxx goalie_count=%d, low dir accuracy", M_total_count, goalie->posCount() ); #endif return; } const ServerParam & SP = ServerParam::i(); const double ball_speed_max = ( wm.gameMode().type() == GameMode::PlayOn || wm.gameMode().isPenaltyKickMode() ? SP.ballSpeedMax() : wm.self().kickRate() * SP.maxPower() ); const double ball_move_dist = M_first_ball_pos.dist( target_point ); const Vector2D max_one_step_vel = ( wm.self().isKickable() ? KickTable::calc_max_velocity( ball_move_angle, wm.self().kickRate(), wm.ball().vel() ) : ( target_point - M_first_ball_pos ).setLengthVector( 0.1 ) ); const double max_one_step_speed = max_one_step_vel.r(); double first_ball_speed = std::max( ( ball_move_dist + 5.0 ) * ( 1.0 - SP.ballDecay() ), std::max( max_one_step_speed, 1.5 ) ); bool over_max = false; #ifdef DEBUG_PRINT_FAILED_COURSE bool success = false; #endif while ( ! over_max ) { if ( first_ball_speed > ball_speed_max - 0.001 ) { over_max = true; first_ball_speed = ball_speed_max; } if ( createShoot( wm, target_point, first_ball_speed, ball_move_angle, ball_move_dist ) ) { Course & course = M_courses.back(); if ( first_ball_speed <= max_one_step_speed + 0.001 ) { course.kick_step_ = 1; } #ifdef DEBUG_PRINT_SUCCESS_COURSE dlog.addText( Logger::SHOOT, "%d: ok shoot target=(%.2f %.2f)" " speed=%.3f angle=%.1f", M_total_count, target_point.x, target_point.y, first_ball_speed, ball_move_angle.degree() ); dlog.addRect( Logger::SHOOT, target_point.x - 0.1, target_point.y - 0.1, 0.2, 0.2, "#00ff00" ); char num[8]; snprintf( num, 8, "%d", M_total_count ); dlog.addMessage( Logger::SHOOT, target_point, num, "#ffffff" ); #endif #ifdef DEBUG_PRINT_FAILED_COURSE success = true; #endif #ifdef SEARCH_UNTIL_MAX_SPEED_AT_SAME_POINT if ( course.goalie_never_reach_ && course.opponent_never_reach_ ) { return; } ++M_total_count; #else return; #endif } first_ball_speed += 0.3; } #ifdef DEBUG_PRINT_FAILED_COURSE if ( success ) { return; } dlog.addText( Logger::SHOOT, "%d: xxx shoot target=(%.2f %.2f)" " speed=%.3f angle=%.1f", M_total_count, target_point.x, target_point.y, first_ball_speed, ball_move_angle.degree() ); dlog.addRect( Logger::SHOOT, target_point.x - 0.1, target_point.y - 0.1, 0.2, 0.2, "#ff0000" ); char num[8]; snprintf( num, 8, "%d", M_total_count ); dlog.addMessage( Logger::SHOOT, target_point, num, "#ffffff" ); #endif }
/*! */ void ShootGenerator::generate( const WorldModel & wm, bool consider_shot_distance ) { #ifdef __APPLE__ static GameTime s_update_time( 0, 0 ); #else static thread_local GameTime s_update_time( 0, 0 ); #endif if ( s_update_time == wm.time() ) { return; } s_update_time = wm.time(); clear(); if ( ! wm.self().isKickable() && wm.interceptTable()->selfReachCycle() > 1 ) { return; } if ( wm.time().stopped() > 0 || wm.gameMode().type() == GameMode::KickOff_ // || wm.gameMode().type() == GameMode::KickIn_ || wm.gameMode().type() == GameMode::IndFreeKick_ ) { return; } const ServerParam & SP = ServerParam::i(); if ( consider_shot_distance && wm.self().pos().dist2( SP.theirTeamGoalPos() ) > std::pow( 30.0, 2 ) ) { #ifdef DEBUG_PRINT dlog.addText( Logger::SHOOT, __FILE__": over shootable distance" ); #endif return; } M_first_ball_pos = ( wm.self().isKickable() ? wm.ball().pos() : wm.ball().pos() + wm.ball().vel() ); #ifdef DEBUG_PROFILE MSecTimer timer; #endif Vector2D goal_l( SP.pitchHalfLength(), -SP.goalHalfWidth() ); Vector2D goal_r( SP.pitchHalfLength(), +SP.goalHalfWidth() ); goal_l.y += std::min( 1.5, 0.6 + goal_l.dist( M_first_ball_pos ) * 0.042 ); goal_r.y -= std::min( 1.5, 0.6 + goal_r.dist( M_first_ball_pos ) * 0.042 ); if ( wm.self().pos().x > SP.pitchHalfLength() - 1.0 && wm.self().pos().absY() < SP.goalHalfWidth() ) { goal_l.x = wm.self().pos().x + 1.5; goal_r.x = wm.self().pos().x + 1.5; } const int DIST_DIVS = 25; const double dist_step = std::fabs( goal_l.y - goal_r.y ) / ( DIST_DIVS - 1 ); #ifdef DEBUG_PRINT dlog.addText( Logger::SHOOT, __FILE__": ===== Shoot search range=(%.1f %.1f)-(%.1f %.1f) dist_step=%.1f =====", goal_l.x, goal_l.y, goal_r.x, goal_r.y, dist_step ); #endif for ( int i = 0; i < DIST_DIVS; ++i ) { ++M_total_count; Vector2D target_point = goal_l; target_point.y += dist_step * i; #ifdef DEBUG_PRINT dlog.addText( Logger::SHOOT, "%d: ===== shoot target(%.2f %.2f) ===== ", M_total_count, target_point.x, target_point.y ); #endif createShoot( wm, target_point ); } evaluateCourses( wm ); #ifdef DEBUG_PROFILE dlog.addText( Logger::SHOOT, __FILE__": PROFILE %d/%d. elapsed=%.3f [ms]", (int)M_courses.size(), DIST_DIVS, timer.elapsedReal() ); #endif }
/*! */ void CrossGenerator::createCross( const WorldModel & wm, const AbstractPlayerObject * receiver ) { static const int MIN_RECEIVE_STEP = 2; static const int MAX_RECEIVE_STEP = 12; // Magic Number static const double MIN_RECEIVE_BALL_SPEED = ServerParam::i().defaultPlayerSpeedMax(); // = std::max( ServerParam::i().defaultPlayerSpeedMax(), // ServerParam::i().ballSpeedMax() // * std::pow( ServerParam::i().ballDecay(), MAX_RECEIVE_STEP ) ); // static const MAX_RECEIVE_BALL_SPEED // = ServerParam::i().ballSpeedMax() // * std::pow( ServerParam::i().ballDecay(), MIN_RECEIVE_STEP ); static const double ANGLE_STEP = 3.0; static const double DIST_STEP = 0.9; const ServerParam & SP = ServerParam::i(); const double min_first_ball_speed = SP.ballSpeedMax() * 0.67; // Magic Number const double max_first_ball_speed = ( wm.gameMode().type() == GameMode::PlayOn ? SP.ballSpeedMax() : wm.self().isKickable() ? wm.self().kickRate() * SP.maxPower() : SP.kickPowerRate() * SP.maxPower() ); const PlayerType * ptype = receiver->playerTypePtr(); const Vector2D receiver_pos = receiver->inertiaFinalPoint(); const double receiver_dist = M_first_point.dist( receiver_pos ); const AngleDeg receiver_angle_from_ball = ( receiver_pos - M_first_point ).th(); #ifdef USE_ONLY_MAX_ANGLE_WIDTH double max_angle_diff = -1.0; CooperativeAction::Ptr best_action; #endif // // angle loop // for ( int a = -2; a < 3; ++a ) { const AngleDeg cross_angle = receiver_angle_from_ball + ( ANGLE_STEP * a ); // // distance loop // for ( int d = 0; d < 5; ++d ) { const double sub_dist = DIST_STEP * d; const double ball_move_dist = receiver_dist - sub_dist; const Vector2D receive_point = M_first_point + Vector2D::from_polar( ball_move_dist, cross_angle ); #ifdef DEBUG_PRINT dlog.addText( Logger::CROSS, "==== receiver=%d receivePos=(%.2f %.2f) loop=%d angle=%.1f", receiver->unum(), receive_point.x, receive_point.y, a, cross_angle.degree() ); #endif if ( receive_point.x > SP.pitchHalfLength() - 0.5 || receive_point.absY() > SP.pitchHalfWidth() - 3.0 ) { #ifdef DEBUG_PRINT dlog.addText( Logger::CROSS, "%d: xxx unum=%d (%.2f %.2f) outOfBounds", M_total_count, receiver->unum(), receive_point.x, receive_point.y ); debug_paint_failed( M_total_count, receive_point ); #endif continue; } const int receiver_step = ptype->cyclesToReachDistance( sub_dist ) + 1; // // step loop // for ( int step = std::max( MIN_RECEIVE_STEP, receiver_step ); step <= MAX_RECEIVE_STEP; ++step ) { ++M_total_count; double first_ball_speed = calc_first_term_geom_series( ball_move_dist, SP.ballDecay(), step ); if ( first_ball_speed < min_first_ball_speed ) { #ifdef DEBUG_PRINT_FAILED_COURSE dlog.addText( Logger::CROSS, "%d: xxx unum=%d (%.1f %.1f) step=%d firstSpeed=%.3f < min=%.3f", M_total_count, receiver->unum(), receive_point.x, receive_point.y, step, first_ball_speed, min_first_ball_speed ); //debug_paint_failed( M_total_count, receive_point ); #endif break; } if ( max_first_ball_speed < first_ball_speed ) { #ifdef DEBUG_PRINT_FAILED_COURSE dlog.addText( Logger::CROSS, "%d: xxx unum=%d (%.1f %.1f) step=%d firstSpeed=%.3f > max=%.3f", M_total_count, receiver->unum(), receive_point.x, receive_point.y, step, first_ball_speed, max_first_ball_speed ); //debug_paint_failed( M_total_count, receive_point ); #endif continue; } double receive_ball_speed = first_ball_speed * std::pow( SP.ballDecay(), step ); if ( receive_ball_speed < MIN_RECEIVE_BALL_SPEED ) { #ifdef DEBUG_PRINT_FAILED_COURSE dlog.addText( Logger::CROSS, "%d: xxx unum=%d (%.1f %.1f) step=%d recvSpeed=%.3f < min=%.3f", M_total_count, receiver->unum(), receive_point.x, receive_point.y, step, receive_ball_speed, min_first_ball_speed ); //debug_paint_failed( M_total_count, receive_point ); #endif break; } int kick_count = FieldAnalyzer::predict_kick_count( wm, M_passer, first_ball_speed, cross_angle ); if ( ! checkOpponent( M_first_point, receiver, receive_point, first_ball_speed, cross_angle, step + kick_count - 1 ) ) // 1 step penalty for observation delay { break; } #ifdef USE_ONLY_MAX_ANGLE_WIDTH double min_angle_diff = getMinimumAngleWidth( ball_move_dist, cross_angle ); if ( min_angle_diff > max_angle_diff ) { CooperativeAction::Ptr ptr( new Pass( M_passer->unum(), receiver->unum(), receive_point, first_ball_speed, step + kick_count, kick_count, false, "cross" ) ); ptr->setIndex( M_total_count ); max_angle_diff = min_angle_diff; best_action = ptr; } #else CooperativeAction::Ptr ptr( new Pass( M_passer->unum(), receiver->unum(), receive_point, first_ball_speed, step + kick_count, kick_count, false, "cross" ) ); ptr->setIndex( M_total_count ); M_courses.push_back( ptr ); #endif // M_courses.push_back( ptr ); #ifdef DEBUG_PRINT_SUCCESS_COURSE dlog.addText( Logger::CROSS, "%d: ok Cross step=%d pos=(%.1f %.1f) speed=%.3f->%.3f nKick=%d", M_total_count, step, kick_count, receive_point.x, receive_point.y, first_ball_speed, receive_ball_speed, kick_count ); char num[8]; snprintf( num, 8, "%d", M_total_count ); dlog.addMessage( Logger::CROSS, receive_point, num ); dlog.addRect( Logger::CROSS, receive_point.x - 0.1, receive_point.y - 0.1, 0.2, 0.2, "#00ff00" ); #endif break; } } } #ifdef USE_ONLY_MAX_ANGLE_WIDTH if ( best_action ) { M_courses.push_back( best_action ); } #endif }
/*! */ void CrossGenerator::generate( const WorldModel & wm ) { static thread_local GameTime s_update_time( -1, 0 ); if ( s_update_time == wm.time() ) { return; } s_update_time = wm.time(); clear(); if ( wm.time().stopped() > 0 || wm.gameMode().isPenaltyKickMode() ) { return; } #ifdef DEBUG_PROFILE Timer timer; #endif updatePasser( wm ); if ( ! M_passer || ! M_first_point.isValid() ) { dlog.addText( Logger::CROSS, __FILE__" (generate) passer not found." ); return; } if ( ServerParam::i().theirTeamGoalPos().dist( M_first_point ) > 35.0 ) { dlog.addText( Logger::CROSS, __FILE__" (generate) first point(%.1f %.1f) is too far from the goal.", M_first_point.x, M_first_point.y ); return; } updateReceivers( wm ); if ( M_receiver_candidates.empty() ) { dlog.addText( Logger::CROSS, __FILE__" (generate) no receiver." ); return; } updateOpponents( wm ); createCourses( wm ); #ifdef DEBUG_PROFILE dlog.addText( Logger::CROSS, __FILE__" (generate) PROFILE course_size=%d/%d elapsed %f [ms]", (int)M_courses.size(), M_total_count, timer.elapsedReal() ); #endif }
/*! */ Formation::Ptr Strategy::getFormation( const WorldModel & wm ) const { // // play on // if ( wm.gameMode().type() == GameMode::PlayOn ) { switch ( M_current_situation ) { case Defense_Situation: return M_defense_formation; case Offense_Situation: return M_offense_formation; default: break; } return M_normal_formation; } // // kick in, corner kick // if ( wm.gameMode().type() == GameMode::KickIn_ || wm.gameMode().type() == GameMode::CornerKick_ ) { if ( wm.ourSide() == wm.gameMode().side() ) { // our kick-in or corner-kick return M_kickin_our_formation; } else { return M_setplay_opp_formation; } } // // our indirect free kick // if ( ( wm.gameMode().type() == GameMode::BackPass_ && wm.gameMode().side() == wm.theirSide() ) || ( wm.gameMode().type() == GameMode::IndFreeKick_ && wm.gameMode().side() == wm.ourSide() ) ) { return M_indirect_freekick_our_formation; } // // opponent indirect free kick // if ( ( wm.gameMode().type() == GameMode::BackPass_ && wm.gameMode().side() == wm.ourSide() ) || ( wm.gameMode().type() == GameMode::IndFreeKick_ && wm.gameMode().side() == wm.theirSide() ) ) { return M_indirect_freekick_opp_formation; } // // after foul // if ( wm.gameMode().type() == GameMode::FoulCharge_ || wm.gameMode().type() == GameMode::FoulPush_ ) { if ( wm.gameMode().side() == wm.ourSide() ) { // // opponent (indirect) free kick // if ( wm.ball().pos().x < ServerParam::i().ourPenaltyAreaLineX() + 1.0 && wm.ball().pos().absY() < ServerParam::i().penaltyAreaHalfWidth() + 1.0 ) { return M_indirect_freekick_opp_formation; } else { return M_setplay_opp_formation; } } else { // // our (indirect) free kick // if ( wm.ball().pos().x > ServerParam::i().theirPenaltyAreaLineX() && wm.ball().pos().absY() < ServerParam::i().penaltyAreaHalfWidth() ) { return M_indirect_freekick_our_formation; } else { return M_setplay_our_formation; } } } // // goal kick // if ( wm.gameMode().type() == GameMode::GoalKick_ ) { if ( wm.gameMode().side() == wm.ourSide() ) { return M_goal_kick_our_formation; } else { return M_goal_kick_opp_formation; } } // // goalie catch // if ( wm.gameMode().type() == GameMode::GoalieCatch_ ) { if ( wm.gameMode().side() == wm.ourSide() ) { return M_goalie_catch_our_formation; } else { return M_goalie_catch_opp_formation; } } // // before kick off // if ( wm.gameMode().type() == GameMode::BeforeKickOff || wm.gameMode().type() == GameMode::AfterGoal_ ) { return M_before_kick_off_formation; } // // other set play // if ( wm.gameMode().isOurSetPlay( wm.ourSide() ) ) { return M_setplay_our_formation; } if ( wm.gameMode().type() != GameMode::PlayOn ) { return M_setplay_opp_formation; } // // unknown // switch ( M_current_situation ) { case Defense_Situation: return M_defense_formation; case Offense_Situation: return M_offense_formation; default: break; } return M_normal_formation; }
/*! */ void Strategy::updatePosition( const WorldModel & wm ) { static GameTime s_update_time( 0, 0 ); if ( s_update_time == wm.time() ) { return; } s_update_time = wm.time(); Formation::Ptr f = getFormation( wm ); if ( ! f ) { std::cerr << wm.teamName() << ':' << wm.self().unum() << ": " << wm.time() << " ***ERROR*** could not get the current formation" << std::endl; return; } int ball_step = 0; if ( wm.gameMode().type() == GameMode::PlayOn || wm.gameMode().type() == GameMode::GoalKick_ ) { ball_step = std::min( 1000, wm.interceptTable()->teammateReachCycle() ); ball_step = std::min( ball_step, wm.interceptTable()->opponentReachCycle() ); ball_step = std::min( ball_step, wm.interceptTable()->selfReachCycle() ); } Vector2D ball_pos = wm.ball().inertiaPoint( ball_step ); dlog.addText( Logger::TEAM, __FILE__": HOME POSITION: ball pos=(%.1f %.1f) step=%d", ball_pos.x, ball_pos.y, ball_step ); M_positions.clear(); f->getPositions( ball_pos, M_positions ); if ( ServerParam::i().useOffside() ) { double max_x = wm.offsideLineX(); if ( ServerParam::i().kickoffOffside() && ( wm.gameMode().type() == GameMode::BeforeKickOff || wm.gameMode().type() == GameMode::AfterGoal_ ) ) { max_x = 0.0; } else { int mate_step = wm.interceptTable()->teammateReachCycle(); if ( mate_step < 50 ) { Vector2D trap_pos = wm.ball().inertiaPoint( mate_step ); if ( trap_pos.x > max_x ) max_x = trap_pos.x; } max_x -= 1.0; } for ( int unum = 1; unum <= 11; ++unum ) { if ( M_positions[unum-1].x > max_x ) { dlog.addText( Logger::TEAM, "____ %d offside. home_pos_x %.2f -> %.2f", unum, M_positions[unum-1].x, max_x ); M_positions[unum-1].x = max_x; } } } M_position_types.clear(); for ( int unum = 1; unum <= 11; ++unum ) { PositionType type = Position_Center; if ( f->isSideType( unum ) ) { type = Position_Left; } else if ( f->isSymmetryType( unum ) ) { type = Position_Right; } M_position_types.push_back( type ); dlog.addText( Logger::TEAM, "__ %d home pos (%.2f %.2f) type=%d", unum, M_positions[unum-1].x, M_positions[unum-1].y, type ); dlog.addCircle( Logger::TEAM, M_positions[unum-1], 0.5, "#000000" ); } }