Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

BasicPlayer.C

Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2000,2001, Jelle Kok, University of Amsterdam
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without 
00006 modification, are permitted provided that the following conditions are met:
00007 
00008 1. Redistributions of source code must retain the above copyright notice, this 
00009 list of conditions and the following disclaimer. 
00010 
00011 2. Redistributions in binary form must reproduce the above copyright notice, 
00012 this list of conditions and the following disclaimer in the documentation 
00013 and/or other materials provided with the distribution. 
00014 
00015 3. Neither the name of the University of Amsterdam nor the names of its 
00016 contributors may be used to endorse or promote products derived from this 
00017 software without specific prior written permission. 
00018 
00019 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
00020 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
00021 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00022 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 
00023 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
00024 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
00025 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
00026 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
00027 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
00028 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 */
00044 #include "BasicPlayer.h"
00045 
00046 /********************** LOW-LEVEL SKILLS *************************************/
00047 
00052 SoccerCommand BasicPlayer::alignNeckWithBody( )
00053 {
00054   return SoccerCommand( CMD_TURNNECK, WM->getAgentBodyAngleRelToNeck( ) );
00055 }
00056 
00075 SoccerCommand BasicPlayer::turnBodyToPoint( VecPosition pos, int iCycles = 1 )
00076 {
00077   VecPosition posGlobal = WM->predictAgentPos(iCycles, 0);
00078   AngDeg angTurn        = (pos - posGlobal).getDirection();
00079   angTurn              -= WM->getAgentGlobalBodyAngle();
00080   angTurn               = VecPosition::normalizeAngle( angTurn );
00081   angTurn               = WM->getAngleForTurn( angTurn, WM->getAgentSpeed() );
00082 
00083   return SoccerCommand( CMD_TURN, angTurn );
00084 }
00085 
00098 SoccerCommand BasicPlayer::turnBackToPoint( VecPosition pos, int iCycles = 1 )
00099 {
00100   VecPosition posGlobal = WM->predictAgentPos(iCycles, 0);
00101   AngDeg angTurn        = (pos - posGlobal).getDirection();
00102   angTurn              -= (WM->getAgentGlobalBodyAngle() + 180);
00103   angTurn               = VecPosition::normalizeAngle( angTurn );
00104   angTurn               = WM->getAngleForTurn( angTurn, WM->getAgentSpeed() );
00105 
00106   return SoccerCommand( CMD_TURN, angTurn );
00107 }
00108 
00130 SoccerCommand BasicPlayer::turnNeckToPoint(VecPosition pos, SoccerCommand soc)
00131 {
00132   VecPosition posMe,   velMe;
00133   AngDeg      angBody, angNeck, angActual;
00134   Stamina     sta;
00135 
00136   // predict agent information after command 'soc' is performed
00137   // calculate the desired global angle of the neck
00138   // calculate the desired angle of the neck relative to the body
00139   WM->predictAgentStateAfterCommand(soc,&posMe,&velMe,&angBody,&angNeck,&sta);
00140   AngDeg angDesGlobNeck   = (pos - posMe).getDirection();
00141   AngDeg angNeckRelToBody = VecPosition::normalizeAngle(angDesGlobNeck-angBody);
00142 
00143   // calculate the current angle of the body relative to the neck
00144   // check if the desired neck angle relative to the body is possible:
00145   // if angle is smaller than the minimum or larger than the maximum neck angle
00146   //  turn neck to the minimum or maximum neck angle + the current neck angle
00147   // else calculate the desired angle relative to the body
00148   AngDeg angBodyRelToNeck = VecPosition::normalizeAngle(angBody-angNeck);
00149   if( angNeckRelToBody < SS->getMinNeckAng() )
00150     angActual = SS->getMinNeckAng() + angBodyRelToNeck;
00151   else if( angNeckRelToBody > SS->getMaxNeckAng() )
00152     angActual = SS->getMaxNeckAng() + angBodyRelToNeck;
00153   else
00154     angActual = angNeckRelToBody + angBodyRelToNeck;
00155   return SoccerCommand( CMD_TURNNECK, angActual );
00156 }
00157 
00169 SoccerCommand BasicPlayer::searchBall()
00170 {
00171   static Time timeLastSearch;
00172   static int  iSign       = 1;
00173 
00174   // calculate maximum turn angle
00175   AngDeg ang = 2*SoccerTypes::getHalfViewAngleValue( WM->getAgentViewAngle() );
00176   ang        = WM->getAngleForTurn( ang - ang/10.0, WM->getAgentSpeed() );
00177 
00178   // calculate whether expected ball position is too the left or right of body
00179   // do this by making angle in directon body and back of body and check
00180   // whether estimated ball prediction lies between these two angles
00181   // only change sign when not searched in previous cycles, otherwise could
00182   // turn left, right, left, right and never find ball
00183   AngDeg angBody = WM->getAgentGlobalBodyAngle();
00184   AngDeg angMax  = VecPosition::normalizeAngle( angBody + 180 );
00185   AngDeg angBall = (WM->getBallPos()-
00186                                   WM->getAgentGlobalPosition()).getDirection();
00187 
00188   if( abs( WM->getCurrentTime() - timeLastSearch ) > 3 )
00189     iSign = isAngInInterval( angBall, angBody, angMax ) ? 1: -1;
00190   timeLastSearch = WM->getCurrentTime();
00191 
00192   if( WM->getCurrentTime() != WM->getTimeLastSeeMessage() )
00193     return SoccerCommand( CMD_TURN, iSign * ang );
00194   return SoccerCommand( CMD_TURN, iSign * ang );
00195 }
00196 
00197 
00210 SoccerCommand BasicPlayer::dashToPoint( VecPosition pos )
00211 {
00212   double dDashPower = WM->getPowerForDash(
00213                                  pos - WM->getAgentGlobalPosition(),
00214                                  WM->getAgentGlobalBodyAngle(),
00215                                  WM->getAgentGlobalVelocity(),
00216                                  WM->getAgentEffort()                );
00217   return SoccerCommand( CMD_DASH, dDashPower );
00218 
00219 }
00220 
00233 SoccerCommand BasicPlayer::freezeBall( )
00234 {
00235   // determine power needed to kick the ball to compensate for current speed
00236   // get opposite direction (current direction + 180) relative to body
00237   // and make the kick command.
00238 
00239   double dPower = WM->getKickPowerForSpeed( WM->getBallSpeed() );
00240   if( dPower > SS->getMaxPower() )
00241   {
00242     Log.log( 552, "%d: freeze ball has to much power", WM->getCurrentCycle() );
00243     dPower = (double)SS->getMaxPower();
00244   }
00245   double dAngle = WM->getBallDirection() + 180 - WM->getAgentGlobalBodyAngle();
00246   dAngle        = VecPosition::normalizeAngle( dAngle );
00247   return SoccerCommand( CMD_KICK, dPower, dAngle );
00248 }
00249 
00269 SoccerCommand BasicPlayer::kickBallCloseToBody( AngDeg ang )
00270 {
00271   AngDeg      angBody    = WM->getAgentGlobalBodyAngle();
00272   VecPosition posAgent   = WM->predictAgentPos( 1, 0 );
00273   double      dDist      = SS->getPlayerSize() +
00274                            SS->getBallSize()   +
00275                            SS->getKickableMargin()/6.0;
00276   AngDeg      angGlobal  = VecPosition::normalizeAngle( angBody + ang );
00277   VecPosition posDesBall = posAgent   + VecPosition( dDist, angGlobal, POLAR );
00278   VecPosition vecDesired = posDesBall - WM->getBallPos();
00279   VecPosition vecShoot   = vecDesired - WM->getGlobalVelocity( OBJECT_BALL );
00280   double      dPower     = WM->getKickPowerForSpeed( vecShoot.getMagnitude() );
00281   AngDeg      angActual  = vecShoot.getDirection() - angBody;
00282               angActual  = VecPosition::normalizeAngle( angActual );
00283 
00284   if( dPower > SS->getMaxPower() )
00285   {
00286     Log.log( 500, "kickBallCloseToBody: cannot compensate for ball speed, freeze");
00287     Log.log( 101, "kickBallCloseToBody: cannot compensate for ball speed, freeze");    
00288     return freezeBall();
00289   }
00290   else
00291     Log.log( 101, "(kick %f %f), vecDesired (%f,%f)", dPower, angActual,
00292     vecDesired.getX(), vecDesired.getY() );
00293   return SoccerCommand( CMD_KICK, dPower, angActual );
00294 }
00295 
00314 SoccerCommand BasicPlayer::accelerateBallToVelocity( VecPosition velDes )
00315 {
00316   AngDeg      angBody  = WM->getAgentGlobalBodyAngle();
00317   VecPosition velBall  = WM->getGlobalVelocity( OBJECT_BALL );
00318   VecPosition accDes   = velDes - velBall;
00319   double      dPower;
00320   double      angActual;
00321 
00322   // if acceleration can be reached, create shooting vector
00323   if( accDes.getMagnitude() < SS->getBallAccelMax() )
00324   {
00325     dPower    = WM->getKickPowerForSpeed   ( accDes.getMagnitude() );
00326     angActual = VecPosition::normalizeAngle( accDes.getDirection() - angBody );
00327     if( dPower <= SS->getMaxPower() )
00328       return SoccerCommand( CMD_KICK, dPower, angActual );
00329   }
00330 
00331   // else determine vector that is in direction 'velDes' (magnitude is lower)
00332          dPower    = SS->getMaxPower();
00333   double dSpeed    = WM->getActualKickPowerRate() * dPower;
00334   double tmp       = velBall.rotate(-velDes.getDirection()).getY();
00335          angActual = velDes.getDirection() - asinDeg( tmp / dSpeed );
00336          angActual = VecPosition::normalizeAngle( angActual - angBody );
00337 
00338   return SoccerCommand( CMD_KICK, dPower, angActual );
00339 }
00340 
00349 SoccerCommand BasicPlayer::catchBall()
00350 {
00351   // true means returned angle is relative to body instead of neck
00352   return SoccerCommand( CMD_CATCH, WM->getRelativeAngle( OBJECT_BALL, true ));
00353 }
00354 
00355 
00361 SoccerCommand BasicPlayer::communicate( char *str )
00362 {
00363   return SoccerCommand( CMD_SAY, str );
00364 }
00365 
00370 SoccerCommand BasicPlayer::teleportToPos( VecPosition pos )
00371 {
00372   return SoccerCommand( CMD_MOVE, pos.getX(), pos.getY() );
00373 
00374 }
00375 
00376 /********************** INTERMEDIATE LEVEL SKILLS ****************************/
00377 
00386 SoccerCommand BasicPlayer::turnBodyToObject( ObjectT o )
00387 {
00388   return turnBodyToPoint( WM->predictPosAfterNrCycles(o, 1) );
00389 }
00390 
00406 SoccerCommand BasicPlayer::turnNeckToObject( ObjectT o, SoccerCommand soc )
00407 {
00408   return turnNeckToPoint( WM->predictPosAfterNrCycles(o, 1), soc );
00409 }
00410 
00442 SoccerCommand BasicPlayer::moveToPos( VecPosition posTo, AngDeg angWhenToTurn,
00443                                       double dDistBack, bool bMoveBack )
00444 {
00445   VecPosition posPred   = WM->predictAgentPos( 1, 0 );
00446   AngDeg      angBody   = WM->getAgentGlobalBodyAngle();
00447   VecPosition posAgent  = WM->getAgentGlobalPosition();  
00448   AngDeg      angTo     = ( posTo - posPred ).getDirection();
00449               angTo     = VecPosition::normalizeAngle( angTo - angBody );
00450   AngDeg      angBackTo = VecPosition::normalizeAngle( angTo + 180 );
00451   double      dDist     = posAgent.getDistanceTo( posTo );
00452 
00453   if( bMoveBack )
00454   {
00455     if( fabs( angBackTo ) < angWhenToTurn )
00456       return dashToPoint( posTo );
00457     else
00458       return turnBackToPoint( posTo );
00459   }
00460   else if(  fabs( angTo     ) < angWhenToTurn ||
00461            (fabs( angBackTo ) < angWhenToTurn && dDist < dDistBack ) )
00462     return dashToPoint( posTo );
00463   else
00464     return turnBodyToPoint( posTo );
00465 }
00466 
00531 SoccerCommand BasicPlayer::interceptClose( )
00532 {
00533   SoccerCommand soc;
00534   double        dPower, dDist;
00535   AngDeg        ang,    ang2;
00536   VecPosition   s1,     s2;
00537 
00538   // first determine whether if distance to ball is not too large
00539   dDist = 2*SS->getPlayerSpeedMax()
00540           + (1.0 + SS->getBallDecay())*SS->getBallSpeedMax()
00541           + SS->getMaximalKickDist();
00542   if( WM->getRelativeDistance( OBJECT_BALL ) > dDist )
00543     return SoccerCommand( CMD_ILLEGAL );
00544 
00545   // initialize all variables with information from worldmodel.
00546   VecPosition   posAgent = WM->getAgentGlobalPosition( );
00547   VecPosition   posPred  = WM->predictAgentPos( 1, 0 );
00548   VecPosition   posBall  = WM->predictPosAfterNrCycles( OBJECT_BALL, 1 );
00549   VecPosition   velMe    = WM->getAgentGlobalVelocity( );
00550   Stamina       sta      = WM->getAgentStamina( );
00551   AngDeg        angBody  = WM->getAgentGlobalBodyAngle( );
00552 
00553   // make a line from center of body in next cycle with direction of body
00554   // use next cycle since current velocity is always propogated to position in
00555   // next cycle.  Make a circle around the ball with a radius equal to the
00556   // sum of your own body, the ball size and a small buffer. Then calculate
00557   // the intersection between the line and this circle. These are the (two)
00558   // points that denote the possible agent locations close to the ball
00559   // From these two points we take the point where the body direction of the
00560   // agent makes the smallest angle with the ball (with backward
00561   // dashing we sometime have to dash "over" the ball to face it up front)
00562   Line line = Line::makeLineFromPositionAndAngle(posPred,angBody);
00563   dDist     = SS->getPlayerSize()+SS->getBallSize()+SS->getKickableMargin()/6;
00564   int  iSol = line.getCircleIntersectionPoints( Circle(posBall,dDist), &s1, &s2);
00565   if (iSol > 0)                                          // if a solution
00566   {
00567     if (iSol == 2)                                       // take the best one
00568     {
00569      ang  = VecPosition::normalizeAngle((posBall - s1).getDirection() -angBody);
00570      ang2 = VecPosition::normalizeAngle((posBall - s2).getDirection() -angBody);
00571      if ( fabs(ang2) < 90)
00572        s1 = s2;                                          // and put it in s1
00573     }
00574 
00575     // try one dash
00576     // now we have the interception point we try to reach in one cycle. We
00577     // calculate the needed dash power from the current position to this point,
00578     // predict were we will stand if we execute this command and check whether
00579     // we are in the kickable distance
00580     dPower  = WM->getPowerForDash(s1-posAgent, angBody, velMe,sta.getEffort() );
00581     posPred = WM->predictAgentPos( 1, (int)dPower);
00582     if ( posPred.getDistanceTo( posBall ) < SS->getMaximalKickDist() )
00583       return SoccerCommand( CMD_DASH, dPower );
00584   }
00585 
00586   // try turn and then dash
00587   // first predict the angle between the agent and the ball after two cycles,
00588   // is this larger than the angle when to turn, turn to position of the ball
00589   // after two cycles. Then perform a dash based on the position of the ball
00590   // after two cycles and the position of the agent after the turn. If after
00591   // these two command the agent is in the kickable distance, return turn
00592   // command.
00593   posBall = WM->predictPosAfterNrCycles( OBJECT_BALL, 2 );
00594   posPred = WM->predictAgentPos( 2, 0 );
00595   ang     = (posBall - posPred).getDirection();
00596   ang     = VecPosition::normalizeAngle( ang - angBody );
00597   if (fabs( ang ) > PS->getPlayerWhenToTurnAngle() ) // if we want to turn
00598   {
00599     soc = turnBodyToPoint( posBall, 2 );             // perform turn
00600     WM->predictAgentStateAfterCommand(soc,&posPred,&velMe,&angBody,&ang,&sta );
00601     dPower = WM->getPowerForDash(posBall-posPred,angBody,velMe,sta.getEffort());
00602     WM->predictStateAfterDash( dPower, &posPred, &velMe, &sta, angBody);
00603     if (posPred.getDistanceTo(posBall) < SS->getMaximalKickDist())
00604       return soc;
00605   }
00606 
00607   // try two dashes
00608   // first predict the position in the next cycle when dash with full power
00609   // is performed. Then calculate the dash power to reach the point where the
00610   // ball will be in two cycles and predict the global position of the agent
00611   // after a dash with this power. If the position is in the kickable distance
00612   // return a dash with full power.
00613   soc = SoccerCommand( CMD_DASH, SS->getMaxPower() );
00614   WM->predictAgentStateAfterCommand(soc,&posPred,&velMe,&angBody,&ang,&sta );
00615   dPower=WM->getPowerForDash(posBall-posPred,angBody,velMe,sta.getEffort());
00616   WM->predictStateAfterDash( dPower, &posPred, &velMe, &sta, angBody );
00617   if (posPred.getDistanceTo(posBall) < SS->getMaximalKickDist())
00618     return soc;
00619 
00620   // try three dashes
00621   // same as with two dashes, but now try two maximum dashes and
00622   posBall = WM->predictPosAfterNrCycles( OBJECT_BALL, 3 );
00623   soc = SoccerCommand( CMD_DASH, SS->getMaxPower() );
00624   WM->predictAgentStateAfterCommand(soc,&posPred,&velMe,&angBody,&ang,&sta );
00625   WM->predictStateAfterCommand( soc, &posPred, &velMe, &angBody, &ang,&sta );
00626   dPower=WM->getPowerForDash(posBall-posPred,angBody,velMe,sta.getEffort());
00627   WM->predictStateAfterDash( dPower, &posPred, &velMe, &sta, angBody );
00628   if (posPred.getDistanceTo(posBall) < SS->getMaximalKickDist())
00629     return soc;
00630 
00631   // cannot intercept ball in two cycles
00632   return SoccerCommand( CMD_ILLEGAL );
00633 }
00634 
00671 SoccerCommand BasicPlayer::interceptCloseGoalie( )
00672 {
00673   SoccerCommand soc;
00674   double        dPower, dDist;
00675   AngDeg        ang;
00676   VecPosition   posClosestToBall;
00677 
00678   // initialize all variables with information from worldmodel.
00679   VecPosition   posPred   = WM->predictAgentPos( 1, 0 );
00680   VecPosition   posBall   = WM->predictPosAfterNrCycles( OBJECT_BALL, 1 );
00681   VecPosition   velMe     = WM->getAgentGlobalVelocity( );
00682   Stamina       sta       = WM->getAgentStamina( );
00683   AngDeg        angBody   = WM->getAgentGlobalBodyAngle( );
00684   Line          lineGoalie=Line::makeLineFromPositionAndAngle(posPred,angBody);
00685 
00686   // when it is theoretical possible
00687   // try one dash and check whether ball is in catchable area
00688   dDist = SS->getBallSpeedMax()+SS->getPlayerSpeedMax()+SS->getCatchableAreaL();
00689   if( WM->getRelativeDistance( OBJECT_BALL ) < dDist )
00690   {
00691     posClosestToBall = lineGoalie.getPointOnLineClosestTo( posBall );
00692     dPower           = WM->getPowerForDash(
00693                           posClosestToBall-posPred,
00694                           angBody,
00695                           velMe,
00696                           sta.getEffort()           );
00697     posPred          = WM->predictAgentPos( 1, (int)dPower);
00698     if ( posPred.getDistanceTo( posBall ) < SS->getCatchableAreaL() )
00699       return SoccerCommand( CMD_DASH, dPower );
00700   }
00701 
00702   // when it is theoretical possible
00703   // try two dashes and check whether ball is in catchable area
00704   // otherwise try first two  dashes and check whether ball is in catchable
00705   // area, thereafter for turn and dash.
00706   dDist = SS->getBallSpeedMax()*(1.0+SS->getBallDecay())
00707            + 2*SS->getPlayerSpeedMax()
00708            + SS->getCatchableAreaL();
00709   if( WM->getRelativeDistance( OBJECT_BALL ) < dDist )
00710   {
00711     // try two dashes
00712     // first predict the position in the next cycle when dash with full power
00713     // is performed. Then calculate the dash power to reach the point where the
00714     // ball will be in two cycles and predict the global position of the agent
00715     // after a dash with this power. If the position is in the catchable area
00716     // return a dash with full power.
00717     posBall = WM->predictPosAfterNrCycles( OBJECT_BALL, 2 );
00718     soc     = dashToPoint( posBall );
00719     WM->predictAgentStateAfterCommand(soc,&posPred,&velMe,&angBody,&ang,&sta );
00720     dPower=WM->getPowerForDash(posBall-posPred,angBody,velMe,sta.getEffort());
00721     WM->predictStateAfterDash( dPower, &posPred, &velMe, &sta, angBody );
00722     if( posPred.getDistanceTo(posBall) < SS->getCatchableAreaL() )
00723       return soc;
00724 
00725     // try one turn and a dash
00726     posBall = WM->predictPosAfterNrCycles( OBJECT_BALL, 2 );
00727     posPred = WM->predictAgentPos( 2, 0 );
00728     ang     = (posBall - posPred).getDirection();
00729     ang     = VecPosition::normalizeAngle( ang - angBody );
00730     if (fabs( ang ) > PS->getPlayerWhenToTurnAngle() ) // if we want to turn
00731     {
00732       soc = turnBodyToPoint( posBall, 2 );             // perform turn
00733       WM->predictAgentStateAfterCommand(soc,&posPred,&velMe,&angBody,&ang,&sta );
00734       dPower=WM->getPowerForDash(posBall-posPred,angBody,velMe,sta.getEffort());
00735       WM->predictStateAfterDash( dPower, &posPred, &velMe, &sta, angBody);
00736       if( posPred.getDistanceTo(posBall) < SS->getCatchableAreaL() )
00737         return soc;
00738     }
00739   }
00740 
00741   // did not succeed
00742   return SoccerCommand( CMD_ILLEGAL );
00743 }
00744 
00775 SoccerCommand BasicPlayer::kickTo( VecPosition posTarget, double dEndSpeed )
00776 {
00777   VecPosition posBall = WM->getBallPos();
00778   VecPosition velBall = WM->getGlobalVelocity(OBJECT_BALL);
00779   VecPosition posTraj = posTarget - posBall;
00780   VecPosition velDes  = VecPosition(
00781                WM->getKickSpeedToTravel( posTraj.getMagnitude(), dEndSpeed ),
00782                posTraj.getDirection(),
00783                POLAR                                                        );
00784   double      dPower;
00785   AngDeg      angActual;
00786 
00787   Log.log( 101, "glob pos ball (%f,%f), glob pos agent (%f,%f), ang %f %f" , 
00788           WM->getBallPos().getX(), WM->getBallPos().getY(),
00789           WM->getAgentGlobalPosition().getX(),
00790           WM->getAgentGlobalPosition().getY(),          
00791           WM->getAgentGlobalBodyAngle(),
00792           WM->getAgentGlobalNeckAngle() );
00793   Log.log( 101, "rel pos body (%f,%f), velocity ball: (%f,%f)" , 
00794           WM->getRelativeDistance( OBJECT_BALL ),
00795           WM->getRelativeAngle( OBJECT_BALL, true ),
00796            velBall.getX(), velBall.getY() );
00797            
00798   if( velDes.getMagnitude() > SS->getBallSpeedMax() ) // can never reach point
00799   {
00800            dPower     = SS->getMaxPower();
00801     double dSpeed     = WM->getActualKickPowerRate() * dPower;
00802     double tmp        = velBall.rotate(-velDes.getDirection()).getY();
00803            angActual  = velDes.getDirection() - asinDeg( tmp / dSpeed );
00804     double dSpeedPred = ( WM->getGlobalVelocity(OBJECT_BALL)+
00805                          VecPosition(dSpeed,angActual, POLAR )).getMagnitude();
00806 
00807     // but ball acceleration in right direction is very high
00808     if( dSpeedPred > PS->getPlayerWhenToKick()*SS->getBallAccelMax() )
00809     {
00810       Log.log( 101, "point too far, but can acccelerate ball good to %f k=%f,%f",
00811                      dSpeedPred, dSpeed, tmp );
00812       return accelerateBallToVelocity( velDes );    // shoot nevertheless
00813     }
00814     else if( WM->getActualKickPowerRate() >
00815         PS->getPlayerWhenToKick() * SS->getKickPowerRate() )
00816     {
00817       Log.log( 101, "point too far, freeze ball" ); // ball well-positioned
00818       return freezeBall();                          // freeze ball
00819     }
00820     else
00821     {
00822       Log.log( 101, "point too far, reposition ball (k_r = %f)",
00823       WM->getActualKickPowerRate()/(SS->getKickPowerRate()) );
00824       return kickBallCloseToBody( 0 );            // else position ball better
00825     }
00826   }
00827   else                                            // can reach point
00828   {
00829     VecPosition accBallDes = velDes - velBall;
00830     dPower = WM->getKickPowerForSpeed(accBallDes.getMagnitude());
00831     if( dPower <= 0.95*SS->getMaxPower() )        // with current ball speed
00832     {                               // 0.95 since cannot get ball fully perfect
00833       Log.log( 101, "point good and can reach point" );
00834       return accelerateBallToVelocity( velDes );  // perform shooting action
00835     }
00836     else
00837     {
00838       Log.log( 101, "point good, but reposition ball since need %f",dPower );
00839       return kickBallCloseToBody( 0 );            // else position ball better
00840     }
00841   }
00842 }
00843 
00871 SoccerCommand BasicPlayer::turnWithBallTo( AngDeg ang, AngDeg angKickThr,
00872                                            double dFreezeThr )
00873 {
00874   // if opponent is close 
00875   // if ball is located more than 'angKickThr' degrees from ang
00876   //  kick ball to point right in front of player in direction ang
00877   // else if ball has still speed higher than 'dFreezeThr'
00879   // else
00880   //  turn to direction 'ang'
00881   VecPosition posAgent = WM->getAgentGlobalPosition();
00882   VecPosition posBall  = WM->getBallPos();
00883   AngDeg      angBody  = WM->getAgentGlobalBodyAngle();
00884   AngDeg      angDiff  = (posBall-posAgent).getDirection() - ang;
00885               angDiff  = VecPosition::normalizeAngle( angDiff );
00886   double      dDist;
00887   ObjectT     objOpp   = WM->getClosestInSetTo( OBJECT_SET_OPPONENTS,
00888                            WM->getAgentObjectType(), &dDist );
00889   VecPosition posOpp   = WM->getGlobalPosition( objOpp );
00890        
00891   if( objOpp != OBJECT_ILLEGAL && dDist < 2.5 )
00892   {
00893     if( posBall.getDistanceTo( posOpp ) < posBall.getDistanceTo( posAgent ) )
00894     {
00895       ang = (posOpp - posAgent).getDirection() + 180;
00896       return kickBallCloseToBody( VecPosition::normalizeAngle( ang - angBody ));  
00897     }
00898   }      
00899   else if( fabs( angDiff ) > angKickThr )
00900   {
00901     return kickBallCloseToBody( VecPosition::normalizeAngle( ang - angBody ) );
00902   }
00903   
00904   if( WM->getBallSpeed() > dFreezeThr )
00905   {
00906     return freezeBall();
00907   }
00908 
00909   ACT->putCommandInQueue( alignNeckWithBody() );
00910   return turnBodyToPoint( posAgent + VecPosition(1.0, ang, POLAR ) );
00911 }
00912 
00962 SoccerCommand BasicPlayer::moveToPosAlongLine( VecPosition pos, AngDeg ang,
00963     double dDistThr, int iSign, AngDeg angThr, AngDeg angCorr )
00964 {
00965   Line        l        = Line::makeLineFromPositionAndAngle( pos, ang );
00966   VecPosition posBall  = WM->getBallPos();
00967   VecPosition posAgent = WM->getAgentGlobalPosition();
00968   AngDeg      angBody  = WM->getAgentGlobalBodyAngle();
00969   VecPosition posProj  = l.getPointOnLineClosestTo( posAgent );
00970   double      dDist    = posAgent.getDistanceTo( posProj );
00971   double      dDiff    = pos.getDistanceTo     ( posProj );
00972   // if deviated too much from line, compensate
00973   if( dDist > dDistThr )
00974   {
00975     // check on which side of line agent is located
00976     VecPosition posOrg(0,0);
00977     Line        m            = Line::makeLineFromTwoPoints( posOrg, posAgent );
00978     VecPosition posIntersect = l.getIntersection( m );
00979     int         iSide;
00980     if( posAgent.getDistanceTo(posOrg) < posIntersect.getDistanceTo( posOrg ) )
00981       iSide = +1;
00982     else
00983       iSide = -1;
00984 
00985     // adjust desired turning angle to move back to line in coming cycles
00986     ang = ang + iSign * iSide * angCorr;
00987   }
00988   
00989   Log.log( 553, "y difference to defend point %f", dDiff );
00990   // if current body angle differs much from desired turning angle, turn body
00991   if( fabs( VecPosition::normalizeAngle( ang - angBody ) ) > angThr )
00992   {
00993     Log.log( 553, "angle differs too much body = %f, des = %f", angBody, ang );
00994     return turnBodyToPoint( posAgent + VecPosition( 1.0, ang, POLAR ) );
00995   }
00996   else if( ( posBall.getX() > -PITCH_LENGTH/4.0 && dDiff > 0.6 ) )
00997     return dashToPoint( pos );  // otherwise move to point
00998   else if( ( posBall.getX() < -PITCH_LENGTH/4.0 && dDiff > 0.3 ) )
00999     return dashToPoint( pos );  // otherwise move to point    
01000   else
01001     return SoccerCommand( CMD_ILLEGAL );
01002 }
01003 
01004 
01005 /********************** HIGH LEVEL SKILLS ************************************/
01006 
01016 SoccerCommand BasicPlayer::intercept( bool isGoalie )
01017 {
01018   SoccerCommand soc = (isGoalie) ? interceptCloseGoalie() : interceptClose();
01019   if( soc.commandType != CMD_ILLEGAL )
01020   {
01021     Log.log( 502, "intercept in two cycles" );
01022     return soc;
01023   }
01024 
01025   // else find the best interception point
01026   int         iSol;
01027   VecPosition posBall = getInterceptionPointBall( &iSol, isGoalie  );
01028   Log.log( 502, "intercept ball in %d cycles", iSol );
01029   return moveToPos( posBall, PS->getPlayerWhenToTurnAngle(), 3.0 );
01030 }
01031 
01070 SoccerCommand BasicPlayer::dribble( AngDeg ang, DribbleT dribbleT )
01071 {
01072   double      dLength;
01073 //  VecPosition posBall  = WM->getBallPos();
01074   AngDeg      angBody  = WM->getAgentGlobalBodyAngle();
01075   VecPosition posAgent = WM->getAgentGlobalPosition();
01076 
01077   switch( dribbleT )
01078   {
01079     case DRIBBLE_WITHBALL:
01080       dLength = 2.0;
01081       break;
01082     case DRIBBLE_SLOW:
01083       dLength = 3.0;
01084       break;
01085     case DRIBBLE_FAST:
01086       dLength = 8.0;
01087       break;
01088     default:
01089       dLength = 0.0;
01090       break;
01091   }
01092 
01093   // determine shooting point, relative to agent since moving in that dir.
01094   VecPosition posDribble = posAgent + VecPosition( dLength, ang, POLAR );
01095 
01096   // adjust when point lies outside side of field
01097   // to a point that lies at distance 2.0 from the side of the field
01098   if( ( fabs( posDribble.getY() ) > PITCH_WIDTH/2.0  - 3.0 && fabs(ang) > 3) ||
01099       ( fabs( posDribble.getX() ) > PITCH_LENGTH/2.0 - 3.0 ) )
01100     posDribble = WM->getOuterPositionInField( posAgent, ang, 2.0, false );
01101 
01102   // if not turned into correct direction, turn with the ball to that angle
01103   ang = VecPosition::normalizeAngle( ang - angBody );
01104   if( fabs( ang ) > 20 )
01105     return turnWithBallTo( (posDribble-posAgent).getDirection(),
01106                                           PS->getTurnWithBallAngThr(),
01107                                           PS->getTurnWithBallFreezeThr() );                                        
01108   return kickTo( posDribble, 0.5 );
01109 }
01110 
01120 SoccerCommand BasicPlayer::directPass( ObjectT o, PassT passType)
01121 {
01122   VecPosition pos = WM->getGlobalPosition( o );
01123   if( passType == PASS_NORMAL )
01124     return kickTo( pos, PS->getPassEndSpeed() );
01125   else if( passType == PASS_FAST )
01126     return kickTo( pos, PS->getFastPassEndSpeed() );
01127   else
01128     return SoccerCommand( CMD_ILLEGAL );
01129 }
01130 
01147 SoccerCommand BasicPlayer::leadingPass( ObjectT o, double dDist )
01148 {
01149   VecPosition posShoot = WM->getGlobalPosition( o )
01150                          + VecPosition( dDist, 0.0, POLAR );
01151   return kickTo( posShoot, PS->getPassEndSpeed() );
01152 }
01153 
01180 SoccerCommand BasicPlayer::throughPass( ObjectT o, VecPosition posEnd,
01181                                         AngDeg *angMax )
01182 {
01183   VecPosition posObj   = WM->getGlobalPosition( o );
01184   VecPosition posBegin = posObj + VecPosition( 3.0, 0.0 );
01185   VecPosition posShoot = getShootPositionOnLine( posBegin, posEnd, angMax );
01186   double      dEnd     = getEndSpeedForPass( o, posShoot );
01187 
01188   return kickTo( posShoot, dEnd );
01189 }
01190 
01271 SoccerCommand BasicPlayer::outplayOpponent( ObjectT o, VecPosition pos,
01272                                             VecPosition *posTo )
01273 {
01274   // future: take more than one opponent into account
01275 
01276   VecPosition posAgent   = WM->getAgentGlobalPosition();
01277   AngDeg      angBody    = WM->getAgentGlobalBodyAngle();
01278   AngDeg      ang        = (pos - posAgent).getDirection();
01279   Line        l          = Line::makeLineFromPositionAndAngle(posAgent,ang);
01280   VecPosition posObj     = WM->getGlobalPosition( o );
01281   VecPosition posProj    = l.getPointOnLineClosestTo( posObj );
01282   double      dDistOpp   = posProj.getDistanceTo( posObj );
01283   double      dDistAgent = posProj.getDistanceTo( posAgent );
01284   VecPosition posShoot;
01285 
01286   // we want to know when distance from ball to point p equals distance
01287   // from opp to point p :
01288   // d1 + d3 = sqrt(d2^2 + d3^2) > (d1+d3)^2 = d2^2 + d3^2 =>
01289   // d1^2 + 2*d1*d3 = d2^2 -> d3 = (d2^2 - d1^2 ) / 2*d1
01290   double dCalcDist;
01291   if( o != OBJECT_ILLEGAL )
01292   {
01293     dCalcDist = (dDistOpp*dDistOpp-dDistAgent*dDistAgent)/(2*dDistAgent);
01294     dCalcDist += dDistAgent;
01295   }
01296   else
01297     dCalcDist = 20;
01298   
01299 
01300   Log.log( 552, "outplay opponent %d, calc: %f, opp: %f, agent:  %f", 
01301      SoccerTypes::getIndex( o ) + 1, dCalcDist, dDistOpp, dDistAgent );
01302   Log.log( 560, "outplay opponent %d, calc: %f, opp: %f, agent:  %f", 
01303      SoccerTypes::getIndex( o ) + 1, dCalcDist, dDistOpp, dDistAgent );
01304      
01305   if( dCalcDist > 7.0 ) // if point far away, kick there
01306   {
01307     dCalcDist = min( posAgent.getDistanceTo( pos ), dCalcDist - 2.5 );
01308     dCalcDist = min( 20, dCalcDist );
01309     posShoot  = posAgent + VecPosition( dCalcDist, ang, POLAR );
01310   }
01311   else if( dDistAgent < dDistOpp - 0.3 ) // point close and well-positioned
01312   {                                      // shoot far away and outplay opp
01313     dCalcDist = min( posAgent.getDistanceTo( pos ), 20);
01314     posShoot = posAgent + VecPosition( dCalcDist, ang, POLAR );
01315   }
01316   else                                   // opponent stands in line
01317     return SoccerCommand( CMD_ILLEGAL );
01318 
01319   if( posShoot.getDistanceTo( WM->getAgentGlobalPosition() ) < 2.5 )
01320   {
01321     Log.log( 552, "calculated point too close" );
01322     Log.log( 560, "calculated point too close (%f,%f)", posShoot.getX(),
01323      posShoot.getY() );    
01324     return SoccerCommand( CMD_ILLEGAL );
01325   }
01326   else if( WM->getNrInSetInCone( OBJECT_SET_OPPONENTS,PS->getConeWidth(),
01327     posAgent, posShoot ) != 0 )
01328   {
01329     Log.log( 552, "outplay: is opponent in cone" );
01330     Log.log( 560, "outplay: is opponent in cone (%f,%f)", posShoot.getX(),
01331      posShoot.getY() );    
01332     return SoccerCommand( CMD_ILLEGAL );
01333   }
01334 
01335   // if not heading in the desired direction, first turn with the ball
01336   AngDeg angTmp = VecPosition::normalizeAngle( ang - angBody ) ;
01337   if( fabs( angTmp ) > 30 ) // PS->getTurnWithBallAngThr() )
01338     return turnWithBallTo( ang, PS->getTurnWithBallAngThr(),
01339                                 PS->getTurnWithBallFreezeThr() );
01340 
01341   if( posTo != NULL )
01342     *posTo = posShoot;
01343   return kickTo( posShoot, 0.5 );
01344 }
01345 
01375 SoccerCommand BasicPlayer::clearBall( ClearBallT type, SideT s, AngDeg *angMax )
01376 {
01377   VecPosition posBall = WM->getBallPos();
01378   VecPosition posLeft, posRight;
01379   double      clearDist = PS->getClearBallDist();
01380   
01381   double      dPitchY = PITCH_WIDTH / 2.0;
01382   if( type == CLEAR_BALL_DEFENSIVE )
01383   {
01384     posLeft.setVecPosition ( 0, - dPitchY + clearDist );
01385     posRight.setVecPosition( 0, + dPitchY - clearDist );
01386   }
01387   else if( type == CLEAR_BALL_OFFENSIVE )
01388   {
01389     posLeft.setVecPosition ( PENALTY_X - clearDist, - dPitchY + clearDist );
01390     posRight.setVecPosition( PENALTY_X - clearDist, + dPitchY - clearDist );
01391   }
01392   else if( type == CLEAR_BALL_GOAL && posBall.getY() > 0 )
01393   {
01394     posLeft.setVecPosition ( PENALTY_X - 3.0,  0.0 );
01395     posRight.setVecPosition( PITCH_LENGTH/2.0 - 10.0, 0.0 );
01396   }
01397   else if( type == CLEAR_BALL_GOAL && posBall.getY() < 0 )
01398   {
01399     posLeft.setVecPosition ( PITCH_LENGTH/2.0 - 10.0, 0.0 );
01400     posRight.setVecPosition( PENALTY_X - clearDist,  0.0 );
01401   }
01402   else
01403     return SoccerCommand( CMD_ILLEGAL );
01404 
01405   if( type != CLEAR_BALL_GOAL && s == SIDE_RIGHT ) // take only right part of
01406     posLeft.setY ( 0.0 );                          // field into account
01407   else if( type != CLEAR_BALL_GOAL && s == SIDE_LEFT )
01408     posRight.setY( 0.0 );
01409 
01410   // get angle of ball with left and right points
01411   // get the largest angle between these two angles
01412   AngDeg angLeft  = (posLeft  - posBall).getDirection();
01413   AngDeg angRight = (posRight - posBall).getDirection();
01414   AngDeg ang      = WM->getDirectionOfWidestAngle( posBall, angLeft, angRight,
01415                                         angMax, PS->getClearBallOppMaxDist() );
01416 
01417   // and the outer position still in the field in that direction
01418 //  bool        bWithPenalty = ( type == CLEAR_BALL_GOAL ) ? false: true;
01419 //  VecPosition posShoot = WM->getOuterPositionInField( posBall, ang, 3.0,
01420 //                                                               bWithPenalty );
01421 
01422   Line l1 = Line::makeLineFromPositionAndAngle( posBall, ang );
01423   Line l2 = Line::makeLineFromTwoPoints( posLeft, posRight );
01424   VecPosition posShoot = l1.getIntersection( l2 );
01425   Log.log( 560, "angLeft %f, right %f, best %f point (%f,%f)", 
01426   angLeft, angRight, ang, posShoot.getX(), posShoot.getY() );  
01427   if( type == CLEAR_BALL_GOAL  )
01428     return kickTo( posShoot, SS->getBallSpeedMax() );
01429   else
01430     return kickTo( posShoot, 0.5 );
01431 }
01432 
01476 SoccerCommand BasicPlayer::markOpponent( ObjectT o, double dDist, MarkT mark )
01477 {
01478   VecPosition posMark = getMarkingPosition( o, dDist, mark );
01479   return moveToPos( posMark, 30, 3, false );
01480 }
01481 
01482 
01521 SoccerCommand BasicPlayer::defendGoalLine( double dDist )
01522 {
01523   // determine defending point as intersection keeper line and line ball-goal
01524   VecPosition posBall    = WM->getBallPos(); // WM->predictPosAfterNrCycles( OBJECT_BALL, 1 );
01525   VecPosition posAgent   = WM->getAgentGlobalPosition();  
01526   Line        lineGoal   = Line::makeLineFromPositionAndAngle(
01527                             VecPosition( - PITCH_LENGTH/2.0 + dDist, 0 ), 90 );
01528 
01529 /*  // method 1
01530   VecPosition posGoal    = WM->getPosOwnGoal( );
01531   Line        lineBall   = Line::makeLineFromTwoPoints( posBall, posGoal );
01532   VecPosition posDefend  = lineGoal.getIntersection( lineBall );
01533 */
01534   // method2  
01535   VecPosition posGoalLeft ( -PITCH_LENGTH/2.0, -SS->getGoalWidth()/2.0 );
01536   VecPosition posGoalRight( -PITCH_LENGTH/2.0,  SS->getGoalWidth()/2.0 );
01537   Line left    = Line::makeLineFromTwoPoints( posBall, posGoalLeft  );
01538   Line right   = Line::makeLineFromTwoPoints( posBall, posGoalRight );
01539   posGoalLeft  = left.getIntersection ( lineGoal );
01540   posGoalRight = right.getIntersection( lineGoal );
01541   double dDistLeft  = posGoalLeft.getDistanceTo( posBall );
01542   double dDistRight = posGoalRight.getDistanceTo( posBall );
01543   double dDistLine  = posGoalLeft.getDistanceTo( posGoalRight );
01544   VecPosition posDefend  = posGoalLeft+
01545       VecPosition( 0, (dDistLeft/(dDistLeft+dDistRight))*dDistLine);  
01546   
01547   bool        bBallInPen = WM->isInOwnPenaltyArea( posBall );
01548   
01549   // do not stand further to side than goalpost
01550   if( fabs( posDefend.getY() ) > SS->getGoalWidth()/2.0 )
01551     posDefend.setY( sign(posDefend.getY())*SS->getGoalWidth()/2.0);
01552 
01553   // if too far away from line, move directly towards it
01554   double dDiff = ( bBallInPen == true ) ? 2.0 : 0.5;
01555   if( posDefend.getX() + dDiff < posAgent.getX()  )
01556   {
01557     Log.log( 553, "move backwards to guard point" );
01558     return moveToPos( posDefend, 30, -1.0, true ); // always backwards
01559   }
01560   else if( posDefend.getX() - dDiff > posAgent.getX() )
01561   {
01562     Log.log( 553, "move forward to guard point" );  
01563     return moveToPos( posDefend, 30, -1.0 );       // always forward
01564   }
01565 
01566   // desired body angle is in direction of the ball
01567   // predicted movement direction in subsequent cycles is in moving dir. ball
01568   AngDeg  angDes;
01569   if( fabs( posBall.getY() - posDefend.getY() ) > 0.5 )
01570     angDes = sign( posBall.getY() - posDefend.getY() )*90.0;
01571   else 
01572     angDes = sign( WM->getAgentGlobalBodyAngle() )*90.0;
01573   int     iSign     = sign( WM->getGlobalVelocity( OBJECT_BALL ).getY() );
01574 
01575   // move to position along line, when ball in penalty area, never adjust body
01576   // angle (value 3.0) and change trajectory when angle difference is > 5
01577   // when ball is outside pen. area, adjust angle to move to line when more
01578   // than 0.5 from desired line, adjust when angle diff > 2 with 12 degrees
01579   if( bBallInPen )
01580   {  
01581     Log.log( 553, "move along line, with ball in penalty area" );
01582     return moveToPosAlongLine( posDefend, angDes, 3.0, iSign, 7.0, 12.0 );  
01583   }
01584   else
01585   {  
01586     Log.log( 553, "move along line, with ball outside penalty area (%f,%f) (%f,%f) %f",
01587       WM->getAgentGlobalPosition().getX(), 
01588       WM->getAgentGlobalPosition().getY(),
01589       posBall.getX(), posBall.getY(), WM->getConfidence( OBJECT_BALL) );  
01590     Log.log( 553, "%s", WM->strLastSeeMessage );
01591     return moveToPosAlongLine( posDefend, angDes, 0.5, iSign, 2.0, 12.0 );
01592   }
01593 }
01594 
01595 
01596 /********************** UTILITY METHODS **************************************/
01597 
01611 VecPosition BasicPlayer::getInterceptionPointBall( int *iCyclesBall, 
01612                                                    bool isGoalie )
01613 {
01614   VecPosition posPred  = WM->getAgentGlobalPosition();
01615   VecPosition velMe    = WM->getAgentGlobalVelocity();
01616   double      dSpeed, dDistExtra;
01617   VecPosition posMe, posBall;
01618   AngDeg      ang, angBody, angNeck;
01619   Stamina     sta;
01620   double      dMaxDist;
01621   
01622   dMaxDist = (isGoalie) ? SS->getCatchableAreaL() : SS->getMaximalKickDist();
01623 
01624   // predict the position of the agent when current velocity is propogated
01625   dSpeed     = WM->getAgentSpeed();
01626   dDistExtra = Geometry::getSumInfGeomSeries( dSpeed, SS->getPlayerDecay() );
01627   posPred   += VecPosition( dDistExtra, velMe.getDirection(), POLAR );
01628 
01629   // for each loop, check whether agent can reach ball in less cycles
01630   for ( int i = 0; i <= 100; i++ )
01631   {
01632     // (re-)initialize all the needed variables
01633     // set ball prediction one further to get right in front of ball line
01634     velMe   = WM->getAgentGlobalVelocity();
01635     angBody = WM->getAgentGlobalBodyAngle();
01636     angNeck = WM->getAgentGlobalNeckAngle();
01637     posBall = WM->predictPosAfterNrCycles( OBJECT_BALL, i + 1 );
01638     posMe   = WM->getAgentGlobalPosition();
01639     ang     = (posBall - posPred).getDirection();
01640     ang     = VecPosition::normalizeAngle( ang - angBody );
01641     sta     = WM->getAgentStamina();
01642     int turn = 0;
01643 
01644     // as long as not correctly headed for point, simulate a turn command
01645     while (fabs(ang) > PS->getPlayerWhenToTurnAngle() && turn<5)
01646     {
01647       turn++;
01648       WM->predictStateAfterTurn( WM->getAngleForTurn( ang,velMe.getMagnitude() ),
01649                    &posMe, &velMe, &angBody, &angNeck, &sta             );
01650       ang      = (posBall - posPred).getDirection();
01651       ang      = VecPosition::normalizeAngle( ang - angBody );
01652     }
01653 
01654     if( turn > 1 )
01655     {
01656       Log.log( 502, "nr of turns needed: %d", turn );
01657     }
01658 
01659     // for cycles that are left over after turn(s), execute dash with full power
01660     for( ; turn < i; turn++ )
01661       WM->predictStateAfterDash(SS->getMaxPower(),&posMe,&velMe,&sta,angBody);
01662 
01663     // if in kickable distance or passed ball, we can reach the ball!
01664     if (posMe.getDistanceTo( posBall ) < dMaxDist  ||
01665        (posMe.getDistanceTo( posPred ) > posBall.getDistanceTo( posPred ) +
01666                                          dMaxDist) )
01667     {
01668       *iCyclesBall = i;
01669       return posBall;
01670     }
01671   }
01672   *iCyclesBall = -1;
01673   return posBall;
01674 }
01675 
01687 VecPosition BasicPlayer::getShootPositionOnLine( VecPosition p1,
01688                                       VecPosition  p2, AngDeg *angLargest )
01689 {
01690   VecPosition posBall  = WM->getBallPos();
01691   Line   line          = Line::makeLineFromTwoPoints( p1, p2 );
01692   double dRadius       = min( PS->getClearBallOppMaxDist(),
01693                               posBall.getDistanceTo( p2 )  );
01694   AngDeg angMin        = (p1 - posBall ).getDirection();
01695   AngDeg angMax        = (p2 - posBall ).getDirection();                  
01696   // not right when line crosses -180 boundary, but will never happenk        
01697   AngDeg angShoot      = WM->getDirectionOfWidestAngle(
01698                              posBall, min(angMin, angMax), 
01699                                  max(angMin,angMax), angLargest, dRadius );
01700   Line   line2         = Line::makeLineFromPositionAndAngle( posBall,
01701                                                              angShoot );
01702   return line.getIntersection( line2 );
01703 }
01704 
01718 double BasicPlayer::getEndSpeedForPass( ObjectT o, VecPosition posPass )
01719 {
01720   // we want that the ball arrives at that point after length nr of cycles
01721   // where length is the nr of cycles it takes the player to get there.
01722   VecPosition posBall = WM->getBallPos();
01723   double      dDist   = posBall.getDistanceTo( posPass );
01724   double      dLength = WM->predictNrCyclesToPoint( o, posPass,
01725                                         PS->getPlayerWhenToTurnAngle() );
01726   double      dFirst  = WM->getFirstSpeedFromDist( dDist, dLength );
01727   if( dFirst > SS->getBallSpeedMax() )
01728     dFirst = SS->getBallSpeedMax();
01729   double dEnd         = WM->getEndSpeedFromFirstSpeed( dFirst, dLength );
01730   if( dEnd > PS->getPassEndSpeed() )
01731     dEnd = PS->getPassEndSpeed();
01732   else if( dEnd < 0.5 )
01733     dEnd = 0.5;
01734   else if( dLength > 10.0 )
01735     dEnd = 0.5;
01736 
01737   return dEnd;
01738 }
01739 
01762 VecPosition BasicPlayer::getMarkingPosition( ObjectT o, double dDist, MarkT mark)
01763 {
01764   VecPosition posBall  = WM->predictPosAfterNrCycles( OBJECT_BALL, 3 );
01765   VecPosition posGoal  = WM->getPosOwnGoal( );
01766   VecPosition pos      = WM->getGlobalPosition( o ) - VecPosition( 1.0, 0.0 );
01767   VecPosition posMark;
01768   AngDeg      ang, angToGoal, angToBall;
01769 
01770   if( mark == MARK_GOAL )                       // position in direction goal
01771   {
01772     angToGoal = (posGoal-pos).getDirection( );
01773     posMark   = pos + VecPosition( dDist, angToGoal, POLAR );
01774   }
01775   else if( mark == MARK_BALL )                  // position in direction ball
01776   {
01777     angToBall = (posBall-pos).getDirection( );
01778     posMark   = pos + VecPosition( dDist, angToBall, POLAR );
01779   }
01780   else if( mark == MARK_BISECTOR )             // position between ball and goal
01781   {
01782     angToBall = (posBall - pos).getDirection( );
01783     angToGoal = (posGoal - pos).getDirection( );
01784     ang       = getBisectorTwoAngles( angToBall, angToGoal );
01785     posMark   = pos + VecPosition( dDist, ang ,POLAR );
01786   }
01787   return posMark;
01788 }

Generated on Thu Mar 7 00:37:42 2002 for UvA Trilearn 2001 by doxygen1.2.12 written by Dimitri van Heesch, © 1997-2001