/*! */ 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::update( const WorldModel & wm ) { static GameTime s_update_time( -1, 0 ); if ( s_update_time == wm.time() ) { return; } s_update_time = wm.time(); updateSituation( wm ); updatePosition( wm ); }
/*! */ void ActionChainHolder::update( const WorldModel & wm ) { static GameTime s_update_time( 0, 0 ); static FieldEvaluator::ConstPtr s_update_evaluator; static ActionGenerator::ConstPtr s_update_generator; if ( s_update_time == wm.time() && s_update_evaluator == M_evaluator && s_update_generator == M_generator ) { return; } s_update_time = wm.time(); s_update_evaluator = M_evaluator; s_update_generator = M_generator; M_graph = ActionChainGraph::Ptr( new ActionChainGraph( M_evaluator, M_generator ) ); M_graph->calculate( wm ); }
/*! */ void DebugClient::writeAll( const WorldModel & world, const ActionEffector & effector ) { if ( M_on ) { this->toStr( world, effector ); if ( M_connected ) { this->send(); } if ( M_write_mode && world.time().stopped() == 0 ) { this->write( world.time().cycle() ); } this->clear(); } }
/*! */ 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 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 ActGen_SimpleDribble::generate( std::vector< ActionStatePair > * result, const PredictState & state, const WorldModel & current_wm, const std::vector< ActionStatePair > & path ) const { static thread_local GameTime s_last_call_time( 0, 0 ); static thread_local int s_action_count = 0; if ( current_wm.time() != s_last_call_time ) { s_action_count = 0; s_last_call_time = current_wm.time(); } if ( path.empty() ) { return; } const AbstractPlayerObject * holder = state.ballHolder(); if ( ! holder ) { return; } const int ANGLE_DIVS = 8; const double ANGLE_STEP = 360.0 / ANGLE_DIVS; const int DIST_DIVS = 3; const double DIST_STEP = 1.75; const ServerParam & SP = ServerParam::i(); const double max_x= SP.pitchHalfLength() - 1.0; const double max_y= SP.pitchHalfWidth() - 1.0; const int bonus_step = 2; const PlayerType * ptype = holder->playerTypePtr(); int generated_count = 0; for ( int a = 0; a < ANGLE_DIVS; ++a ) { const AngleDeg target_angle = ANGLE_STEP * a; if ( holder->pos().x < 16.0 && target_angle.abs() > 100.0 ) { #ifdef DEBUG_PRINT dlog.addText( Logger::ACTION_CHAIN, __FILE__": %d: (%.2f %.2f) danger angle(1) %.1f", generated_count, target_angle.degree() ); #endif continue; } if ( holder->pos().x < -36.0 && holder->pos().absY() < 20.0 && target_angle.abs() > 45.0 ) { #ifdef DEBUG_PRINT dlog.addText( Logger::ACTION_CHAIN, __FILE__": %d: (%.2f %.2f) danger angle(2) %.1f", generated_count, target_angle.degree() ); #endif continue; } const Vector2D unit_vec = Vector2D::from_polar( 1.0, target_angle ); for ( int d = 1; d <= DIST_DIVS; ++d ) { const double holder_move_dist = DIST_STEP * d; const Vector2D target_point = holder->pos() + unit_vec.setLengthVector( holder_move_dist ); if ( target_point.absX() > max_x || target_point.absY() > max_y ) { #ifdef DEBUG_PRINT dlog.addText( Logger::ACTION_CHAIN, __FILE__": %d: (%.2f %.2f) out of pitch.", generated_count, target_point.x, target_point.y ); #endif continue; } const int holder_reach_step = 1 + 1 // kick + turn + ptype->cyclesToReachDistance( holder_move_dist - ptype->kickableArea() * 0.5 ); // // check opponent // bool exist_opponent = false; for ( PlayerCont::const_iterator o = state.opponents().begin(); o != state.opponents().end(); ++o ) { double opp_move_dist = o->pos().dist( target_point ); int o_step = 1 // turn step + o->playerTypePtr()->cyclesToReachDistance( opp_move_dist - ptype->kickableArea() ); if ( o_step - bonus_step <= holder_reach_step ) { exist_opponent = true; break; } } if ( exist_opponent ) { #ifdef DEBUG_PRINT dlog.addText( Logger::ACTION_CHAIN, __FILE__": %d: (%.2f %.2f) exist opponent.", generated_count, target_point.x, target_point.y ); #endif continue; } const double ball_speed = SP.firstBallSpeed( state.ball().pos().dist( target_point ), holder_reach_step ); PredictState::ConstPtr result_state( new PredictState( state, holder_reach_step, holder->unum(), target_point ) ); CooperativeAction::Ptr action( new Dribble( holder->unum(), target_point, ball_speed, 1, 1, holder_reach_step - 2, "actgenDribble" ) ); ++s_action_count; ++generated_count; action->setIndex( s_action_count ); result->push_back( ActionStatePair( action, result_state ) ); } } #ifdef DEBUG_PRINT dlog.addText( Logger::ACTION_CHAIN, __FILE__": Dribble path=%d, holder=%d generated=%d/%d", path.size(), holder->unum(), generated_count, s_action_count ); #endif }
/*! */ 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::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 }
/*! */ 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" ); } }