/*! */ 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 CrossGenerator::updateReceivers( const WorldModel & wm ) { static const double shootable_dist2 = std::pow( 16.0, 2 ); // Magic Number static const double min_cross_dist2 = std::pow( ServerParam::i().defaultKickableArea() * 2.2, 2 ); static const double max_cross_dist2 = std::pow( inertia_n_step_distance( ServerParam::i().ballSpeedMax(), 9, ServerParam::i().ballDecay() ), 2 ); const Vector2D goal = ServerParam::i().theirTeamGoalPos(); const bool is_self_passer = ( M_passer->unum() == wm.self().unum() ); for ( AbstractPlayerCont::const_iterator p = wm.ourPlayers().begin(), end = wm.ourPlayers().end(); p != end; ++p ) { if ( *p == M_passer ) continue; if ( is_self_passer ) { if ( (*p)->isGhost() ) continue; if ( (*p)->posCount() >= 4 ) continue; if ( (*p)->pos().x > wm.offsideLineX() ) continue; } else { // ignore other players if ( (*p)->unum() != wm.self().unum() ) { continue; } } if ( (*p)->pos().dist2( goal ) > shootable_dist2 ) continue; double d2 = (*p)->pos().dist2( M_first_point ); if ( d2 < min_cross_dist2 ) continue; if ( max_cross_dist2 < d2 ) continue; M_receiver_candidates.push_back( *p ); #ifdef DEBUG_UPDATE_OPPONENT dlog.addText( Logger::CROSS, "Cross receiver %d pos(%.1f %.1f)", (*p)->unum(), (*p)->pos().x, (*p)->pos().y ); #endif } }
/*! */ Vector2D Bhv_ChainAction::getKeepBallVel( const WorldModel & wm ) { static GameTime s_update_time( 0, 0 ); static Vector2D s_best_ball_vel( 0.0, 0.0 ); if ( s_update_time == wm.time() ) { return s_best_ball_vel; } s_update_time = wm.time(); // // // const int ANGLE_DIVS = 12; const ServerParam & SP = ServerParam::i(); const PlayerType & ptype = wm.self().playerType(); const double collide_dist2 = std::pow( ptype.playerSize() + SP.ballSize(), 2 ); const double keep_dist = ptype.playerSize() + ptype.kickableMargin() * 0.5 + ServerParam::i().ballSize(); const Vector2D next_self_pos = wm.self().pos() + wm.self().vel(); const Vector2D next2_self_pos = next_self_pos + wm.self().vel() * ptype.playerDecay(); // // create keep target point // Vector2D best_ball_vel = Vector2D::INVALIDATED; int best_opponent_step = 0; double best_ball_speed = 1000.0; for ( int a = 0; a < ANGLE_DIVS; ++a ) { Vector2D keep_pos = next2_self_pos + Vector2D::from_polar( keep_dist, 360.0/ANGLE_DIVS * a ); if ( keep_pos.absX() > SP.pitchHalfLength() - 0.2 || keep_pos.absY() > SP.pitchHalfWidth() - 0.2 ) { continue; } Vector2D ball_move = keep_pos - wm.ball().pos(); double ball_speed = ball_move.r() / ( 1.0 + SP.ballDecay() ); Vector2D max_vel = KickTable::calc_max_velocity( ball_move.th(), wm.self().kickRate(), wm.ball().vel() ); if ( max_vel.r2() < std::pow( ball_speed, 2 ) ) { continue; } Vector2D ball_next_next = keep_pos; Vector2D ball_vel = ball_move.setLengthVector( ball_speed ); Vector2D ball_next = wm.ball().pos() + ball_vel; if ( next_self_pos.dist2( ball_next ) < collide_dist2 ) { ball_next_next = ball_next; ball_next_next += ball_vel * ( SP.ballDecay() * -0.1 ); } #ifdef DEBUG_PRINT dlog.addText( Logger::TEAM, __FILE__": (getKeepBallVel) %d: ball_move th=%.1f speed=%.2f max=%.2f", a, ball_move.th().degree(), ball_speed, max_vel.r() ); dlog.addText( Logger::TEAM, __FILE__": __ ball_next=(%.2f %.2f) ball_next2=(%.2f %.2f)", ball_next.x, ball_next.y, ball_next_next.x, ball_next_next.y ); #endif // // check opponent // int min_step = 1000; for ( PlayerPtrCont::const_iterator o = wm.opponentsFromSelf().begin(); o != wm.opponentsFromSelf().end(); ++o ) { if ( (*o)->distFromSelf() > 10.0 ) { break; } int o_step = FieldAnalyzer::predict_player_reach_cycle( *o, ball_next_next, (*o)->playerTypePtr()->kickableArea(), 0.0, // penalty distance 1, // body count thr 1, // default turn step 0, // wait cycle true ); if ( o_step <= 0 ) { break; } if ( o_step < min_step ) { min_step = o_step; } } #ifdef DEBUG_PRINT dlog.addText( Logger::TEAM, __FILE__": (getKeepBallVel) %d: keepPos=(%.2f %.2f)" " ballNext2=(%.2f %.2f) ballVel=(%.2f %.2f) speed=%.2f o_step=%d", a, keep_pos.x, keep_pos.y, ball_next_next.x, ball_next_next.y, ball_vel.x, ball_vel.y, ball_speed, min_step ); #endif if ( min_step > best_opponent_step ) { best_ball_vel = ball_vel; best_opponent_step = min_step; best_ball_speed = ball_speed; } else if ( min_step == best_opponent_step ) { if ( best_ball_speed > ball_speed ) { best_ball_vel = ball_vel; best_opponent_step = min_step; best_ball_speed = ball_speed; } } } s_best_ball_vel = best_ball_vel; return s_best_ball_vel; }
/*! */ void PredictState::init( const WorldModel & wm ) { // // initialize world // M_world = &wm; // // initialize spend_time // M_spend_time = 0; // // initialize ball pos & vel // M_ball.assign( wm.ball().pos(), wm.ball().vel() ); // // initialize self_unum // M_self_unum = wm.self().unum(); // // initialize ball holder // const AbstractPlayerObject * h = wm.getTeammateNearestToBall( VALID_PLAYER_THRESHOLD ); if ( h && wm.ball().pos().dist2( h->pos() ) < wm.ball().pos().dist2( wm.self().pos() ) ) { M_ball_holder_unum = h->unum(); } else { M_ball_holder_unum = wm.self().unum(); } // // initialize all teammates // M_our_players.reserve( 11 ); for ( int n = 1; n <= 11; ++n ) { PredictPlayerObject::Ptr ptr; if ( n == M_self_unum ) { ptr = PredictPlayerObject::Ptr( new PredictPlayerObject( wm.self() ) ); } else { const AbstractPlayerObject * t = wm.ourPlayer( n ); if ( t ) { ptr = PredictPlayerObject::Ptr( new PredictPlayerObject( *t ) ); } else { ptr = PredictPlayerObject::Ptr( new PredictPlayerObject() ); } } M_our_players.push_back( ptr ); #ifndef STRICT_LINE_UPDATE if ( ptr->isValid() && M_our_offense_player_line_x < ptr->pos().x ) { M_our_offense_player_line_x = ptr->pos().x; } #endif } updateLines(); }
/*! */ 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 FullstateSensor::printWithWorld( const WorldModel & world ) const { Vector2D tmpv; double tmpval; dlog.addText( Logger::WORLD, "FS ball (%+.3f %+.3f) (%+.3f %+.3f) %.3f", ball().pos_.x, ball().pos_.y, ball().vel_.x, ball().vel_.y, ball().vel_.r() ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) (%+.3f %+.3f) %.3f gconf=%d rconf=%d", world.ball().pos().x, world.ball().pos().y, world.ball().vel().x, world.ball().vel().y, world.ball().vel().r(), world.ball().posCount(), world.ball().rposCount() ); tmpv = ball().pos_ - world.ball().pos(); dlog.addText( Logger::WORLD, "__ball pos err (%+.3f %+.3f) %.3f", tmpv.x, tmpv.y, tmpv.r() ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f)", world.ball().posError().x, world.ball().posError().y ); tmpv = ball().vel_ - world.ball().vel(); tmpval = tmpv.r(); dlog.addText( Logger::WORLD, "__ball vel err (%+.3f %+.3f) %.3f %s", tmpv.x, tmpv.y, tmpval, (tmpval > 1.0 ? "big error" : "" ) ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f)", world.ball().velError().x, world.ball().velError().y ); const FullstateSensor::PlayerCont& player_cont = ( world.isOurLeft() ? leftTeam() : rightTeam() ); for ( FullstateSensor::PlayerCont::const_iterator it = player_cont.begin(); it != player_cont.end(); ++it ) { if ( it->unum_ == world.self().unum() ) { dlog.addText( Logger::WORLD, "FS self (%+.3f %+.3f) (%+.3f %+.3f) b=%+.2f n=%+.2f f=%+.2f", it->pos_.x, it->pos_.y, it->vel_.x, it->vel_.y, it->body_, it->neck_, AngleDeg::normalize_angle( it->body_ + it->neck_ ) ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) (%+.3f %+.3f) b=%+.2f n=%+.2f f=%+.2f", world.self().pos().x, world.self().pos().y, world.self().vel().x, world.self().vel().y, world.self().body().degree(), world.self().neck().degree(), world.self().face().degree() ); tmpv = it->pos_ - world.self().pos(); double d = tmpv.r(); dlog.addText( Logger::WORLD, "__self pos err (%+.3f %+.3f) %.3f %s", tmpv.x, tmpv.y, d, ( d > 0.3 ? " big error" : "" ) ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) %.3f", world.self().posError().x, world.self().posError().y, world.self().posError().r() ); tmpv = it->vel_ - world.self().vel(); dlog.addText( Logger::WORLD, "__self vel err (%+.3f %+.3f) %.3f", tmpv.x, tmpv.y, tmpv.r() ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) %.3f", world.self().velError().x, world.self().velError().y, world.self().velError().r() ); tmpv = ball().pos_ - it->pos_; dlog.addText( Logger::WORLD, "__ball rpos (%+.3f %+.3f) %.3f", tmpv.x, tmpv.y, tmpv.r() ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) %.3f", world.ball().rpos().x, world.ball().rpos().y, world.ball().rpos().r() ); tmpv -= world.ball().rpos(); dlog.addText( Logger::WORLD, "__ball rpos err (%+.3f %+.3f) %.3f", tmpv.x, tmpv.y, tmpv.r() ); dlog.addText( Logger::WORLD, "____internal (%+.3f %+.3f) %.3f", world.ball().rposError().x, world.ball().rposError().y, world.ball().rposError().r() ); break; } } }
/*! */ void DebugClient::toStr( const WorldModel & world, const ActionEffector & effector ) { std::ostringstream ostr; ostr << "((debug (format-version 3)) (time " << world.time().cycle() << ")"; // self /* SELF ::= (s SIDE PLAYER_NUMBER POS_X POS_Y VEL_X VEL_Y BODY_DIRECTION FACE_DIRECTION [(c "COMMENT")]) where SIDE is 'l' or 'r'. where PLAYER_NUMBER is 1 to 11. where POS_X and POS_Y is absolute coordinate. where VEL_X and VEL_Y is absolute velocity. where BODY_DIRECTION is absolute player body direction (degree). where NECK_DIRECTION is body relative face direction (degree). This is equals to (absolute_face_direction - BODY_DIRECTION). where COMMENT is a string. Typically, it is used as information accuracy. */ if ( world.self().posValid() ) { ostr << " (s " << ( world.ourSide() == LEFT ? "l " : "r " ) << world.self().unum() << ' ' << ROUND(world.self().pos().x, 0.01) << ' ' << ROUND(world.self().pos().y, 0.01) << ' ' << ROUND(world.self().vel().x, 0.01) << ' ' << ROUND(world.self().vel().y, 0.01) << ' ' << ROUND(world.self().body().degree(), 0.1) << ' ' << ROUND(world.self().neck().degree(), 0.1) << " (c \"" << world.self().posCount() << ' ' //<< '(' << ROUND(world.self().posError().x, 0.001) //<< ", " << ROUND(world.self().posError().y, 0.001) << ") " << world.self().velCount() << ' ' << world.self().faceCount(); if ( world.self().card() == YELLOW ) ostr << "y"; ostr << "\"))"; } // ball /* BALL_INFO ::= (b POS_X POS_Y [VEL_X VEL_Y] [(c "COMMENT")]) */ if ( world.ball().posValid() ) { ostr << " (b " << ROUND(world.ball().pos().x, 0.01) << ' ' << ROUND(world.ball().pos().y, 0.01); if ( world.ball().velValid() ) { ostr << ' ' << ROUND(world.ball().vel().x, 0.01) << ' ' << ROUND(world.ball().vel().y, 0.01); } ostr << " (c \"g" << world.ball().posCount() << 'r' << world.ball().rposCount() //<< "(" << ROUND(world.ball().rpos().x, 0.01) // << ", " << ROUND(world.ball().rpos().y, 0.01) << ')' << 'v' << world.ball().velCount() //<< "(" << ROUND(world.ball().vel().x, 0.01) // << ", " << ROUND(world.ball().vel().y, 0.01) << ')' << "\"))"; } // players /* PLAYER_INFO ::= (TEAM [PLAYER_NUMBER] POS_X POS_Y [(bd BODY_DIRECTION)] [(c "COMMENT")]) TEAM is one of follows. 't' (teammate), 'o' (opponent), 'u' (unknown), 'ut' (unknown teammate), 'ut' (unknown opponent). When TEAM is 't' or 'o', PLAYER_NUMBER must be specified. Otherwise PLAYER_NUMBER must not be specified. Body direction and comment is optional. */ std::for_each( world.teammates().begin(), world.teammates().end(), PlayerPrinter( ostr, 't' ) ); std::for_each( world.opponents().begin(), world.opponents().end(), PlayerPrinter( ostr, 'o' ) ); std::for_each( world.unknownPlayers().begin(), world.unknownPlayers().end(), PlayerPrinter( ostr, 'u' ) ); // say message if ( ! effector.getSayMessage().empty() ) { ostr << " (say \""; for ( std::vector< const SayMessage * >::const_iterator it = effector.sayMessageCont().begin(); it != effector.sayMessageCont().end(); ++it ) { (*it)->printDebug( ostr ); } ostr << " {" << effector.getSayMessage() << "}\")"; } // heard information if ( world.audioMemory().time() == world.time() ) { ostr << " (hear "; world.audioMemory().printDebug( ostr ); ostr << ')'; } // target number if ( M_target_unum != Unum_Unknown ) { ostr << " (target-teammate " << M_target_unum << ")"; } // target point if ( M_target_point.isValid() ) { ostr << " (target-point " << M_target_point.x << " " << M_target_point.y << ")"; } // message if ( ! M_message.empty() ) { ostr << " (message \"" << M_message << "\")"; } // lines std::for_each( M_lines.begin(), M_lines.end(), LinePrinter( ostr ) ); // triangles std::for_each( M_triangles.begin(), M_triangles.end(), TrianglePrinter( ostr ) ); // rectangles std::for_each( M_rectangles.begin(), M_rectangles.end(), RectPrinter( ostr ) ); // circles std::for_each( M_circles.begin(), M_circles.end(), CirclePrinter( ostr ) ); ostr << ")"; M_main_buffer.assign( ostr.str() ); }
/*! */ 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::updatePasser( const WorldModel & wm ) { if ( wm.self().isKickable() && ! wm.self().isFrozen() ) { M_passer = &wm.self(); M_first_point = wm.ball().pos(); #ifdef DEBUG_UPDATE_PASSER dlog.addText( Logger::CROSS, __FILE__" (updatePasser) self kickable." ); #endif return; } int s_min = wm.interceptTable()->selfReachCycle(); int t_min = wm.interceptTable()->teammateReachCycle(); int o_min = wm.interceptTable()->opponentReachCycle(); int our_min = std::min( s_min, t_min ); if ( o_min < std::min( our_min - 4, (int)rint( our_min * 0.9 ) ) ) { #ifdef DEBUG_UPDATE_PASSER dlog.addText( Logger::CROSS, __FILE__" (updatePasser) opponent ball." ); #endif return; } if ( s_min <= t_min ) { if ( s_min <= 2 ) { M_passer = &wm.self(); M_first_point = wm.ball().inertiaPoint( s_min ); } } else { if ( t_min <= 2 ) { M_passer = wm.interceptTable()->fastestTeammate(); M_first_point = wm.ball().inertiaPoint( t_min ); } } if ( ! M_passer ) { #ifdef DEBUG_UPDATE_PASSER dlog.addText( Logger::CROSS, __FILE__" (updatePasser) no passer." ); #endif return; } if ( M_passer->unum() != wm.self().unum() ) { if ( M_first_point.dist2( wm.self().pos() ) > std::pow( 20.0, 2 ) ) { M_passer = static_cast< const AbstractPlayerObject * >( 0 ); #ifdef DEBUG_UPDATE_PASSER dlog.addText( Logger::CROSS, __FILE__" (updatePasser) passer is too far." ); #endif return; } } #ifdef DEBUG_UPDATE_PASSER dlog.addText( Logger::CROSS, __FILE__" (updatePasser) passer=%d(%.1f %.1f) reachStep=%d startPos=(%.1f %.1f)", M_passer->unum(), M_passer->pos().x, M_passer->pos().y, t_min, M_first_point.x, M_first_point.y ); #endif }
/*! */ void TackleGenerator::calculate( const WorldModel & wm ) { const ServerParam & SP = ServerParam::i(); const double min_angle = SP.minMoment(); const double max_angle = SP.maxMoment(); const double angle_step = std::fabs( max_angle - min_angle ) / ANGLE_DIVS; #ifdef ASSUME_OPPONENT_KICK const Vector2D goal_pos = SP.ourTeamGoalPos(); const bool shootable_area = ( wm.ball().pos().dist2( goal_pos ) < std::pow( 18.0, 2 ) ); const Vector2D shoot_accel = ( goal_pos - wm.ball().pos() ).setLengthVector( 2.0 ); #endif const AngleDeg ball_rel_angle = wm.ball().angleFromSelf() - wm.self().body(); const double tackle_rate = SP.tacklePowerRate() * ( 1.0 - 0.5 * ball_rel_angle.abs() / 180.0 ); #ifdef DEBUG_PRINT dlog.addText( Logger::CLEAR, __FILE__": min_angle=%.1f max_angle=%.1f angle_step=%.1f", min_angle, max_angle, angle_step ); dlog.addText( Logger::CLEAR, __FILE__": ball_rel_angle=%.1f tackle_rate=%.1f", ball_rel_angle.degree(), tackle_rate ); #endif for ( int a = 0; a < ANGLE_DIVS; ++a ) { const AngleDeg dir = min_angle + angle_step * a; double eff_power= ( SP.maxBackTacklePower() + ( SP.maxTacklePower() - SP.maxBackTacklePower() ) * ( 1.0 - ( dir.abs() / 180.0 ) ) ); eff_power *= tackle_rate; AngleDeg angle = wm.self().body() + dir; Vector2D accel = Vector2D::from_polar( eff_power, angle ); #ifdef ASSUME_OPPONENT_KICK if ( shootable_area && wm.existKickableOpponent() ) { accel += shoot_accel; double d = accel.r(); if ( d > SP.ballAccelMax() ) { accel *= ( SP.ballAccelMax() / d ); } } #endif Vector2D vel = wm.ball().vel() + accel; double speed = vel.r(); if ( speed > SP.ballSpeedMax() ) { vel *= ( SP.ballSpeedMax() / speed ); } M_candidates.push_back( TackleResult( angle, vel ) ); #ifdef DEBUG_PRINT const TackleResult & result = M_candidates.back(); dlog.addText( Logger::CLEAR, "%d: angle=%.1f(dir=%.1f), result: vel(%.2f %.2f ) speed=%.2f move_angle=%.1f", a, result.tackle_angle_.degree(), dir.degree(), result.ball_vel_.x, result.ball_vel_.y, result.ball_speed_, result.ball_move_angle_.degree() ); #endif } M_best_result.clear(); const Container::iterator end = M_candidates.end(); for ( Container::iterator it = M_candidates.begin(); it != end; ++it ) { it->score_ = evaluate( wm, *it ); #ifdef DEBUG_PRINT Vector2D ball_end_point = inertia_final_point( wm.ball().pos(), it->ball_vel_, SP.ballDecay() ); dlog.addLine( Logger::CLEAR, wm.ball().pos(), ball_end_point, "#0000ff" ); char buf[16]; snprintf( buf, 16, "%.3f", it->score_ ); dlog.addMessage( Logger::CLEAR, ball_end_point, buf, "#ffffff" ); #endif if ( it->score_ > M_best_result.score_ ) { #ifdef DEBUG_PRINT dlog.addText( Logger::CLEAR, ">>>> updated" ); #endif M_best_result = *it; } } #ifdef DEBUG_PRINT dlog.addLine( Logger::CLEAR, wm.ball().pos(), inertia_final_point( wm.ball().pos(), M_best_result.ball_vel_, SP.ballDecay() ), "#ff0000" ); dlog.addText( Logger::CLEAR, "==== best_angle=%.1f score=%f speed=%.3f move_angle=%.1f", M_best_result.tackle_angle_.degree(), M_best_result.score_, M_best_result.ball_speed_, M_best_result.ball_move_angle_.degree() ); #endif }
/*! */ 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" ); } }
/*! */ double Strategy::get_normal_dash_power( const WorldModel & wm ) { static bool s_recover_mode = false; if ( wm.self().staminaModel().capacityIsEmpty() ) { return std::min( ServerParam::i().maxDashPower(), wm.self().stamina() + wm.self().playerType().extraStamina() ); } const int self_min = wm.interceptTable()->selfReachCycle(); const int mate_min = wm.interceptTable()->teammateReachCycle(); const int opp_min = wm.interceptTable()->opponentReachCycle(); // check recover if ( wm.self().staminaModel().capacityIsEmpty() ) { s_recover_mode = false; } else if ( wm.self().stamina() < ServerParam::i().staminaMax() * 0.5 ) { s_recover_mode = true; } else if ( wm.self().stamina() > ServerParam::i().staminaMax() * 0.7 ) { s_recover_mode = false; } /*--------------------------------------------------------*/ double dash_power = ServerParam::i().maxDashPower(); const double my_inc = wm.self().playerType().staminaIncMax() * wm.self().recovery(); if ( wm.ourDefenseLineX() > wm.self().pos().x && wm.ball().pos().x < wm.ourDefenseLineX() + 20.0 ) { dlog.addText( Logger::TEAM, __FILE__": (get_normal_dash_power) correct DF line. keep max power" ); // keep max power dash_power = ServerParam::i().maxDashPower(); } else if ( s_recover_mode ) { dash_power = my_inc - 25.0; // preffered recover value if ( dash_power < 0.0 ) dash_power = 0.0; dlog.addText( Logger::TEAM, __FILE__": (get_normal_dash_power) recovering" ); } // exist kickable teammate else if ( wm.existKickableTeammate() && wm.ball().distFromSelf() < 20.0 ) { dash_power = std::min( my_inc * 1.1, ServerParam::i().maxDashPower() ); dlog.addText( Logger::TEAM, __FILE__": (get_normal_dash_power) exist kickable teammate. dash_power=%.1f", dash_power ); } // in offside area else if ( wm.self().pos().x > wm.offsideLineX() ) { dash_power = ServerParam::i().maxDashPower(); dlog.addText( Logger::TEAM, __FILE__": in offside area. dash_power=%.1f", dash_power ); } else if ( wm.ball().pos().x > 25.0 && wm.ball().pos().x > wm.self().pos().x + 10.0 && self_min < opp_min - 6 && mate_min < opp_min - 6 ) { dash_power = bound( ServerParam::i().maxDashPower() * 0.1, my_inc * 0.5, ServerParam::i().maxDashPower() ); dlog.addText( Logger::TEAM, __FILE__": (get_normal_dash_power) opponent ball dash_power=%.1f", dash_power ); } // normal else { dash_power = std::min( my_inc * 1.7, ServerParam::i().maxDashPower() ); dlog.addText( Logger::TEAM, __FILE__": (get_normal_dash_power) normal mode dash_power=%.1f", dash_power ); } return dash_power; }