ProgrammierMethodik 2002 - RoboCup

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

RCBrain.java

Go to the documentation of this file.
00001 /*
00002  * $Id: RCBrain_8java-source.html,v 1.2 2002/07/07 20:59:52 stork Exp $
00003  *
00004  * $Log: RCBrain_8java-source.html,v $
00004  * Revision 1.2  2002/07/07 20:59:52  stork
00004  * update dokumenation
00004  *
00005  * Revision 1.35  2002/07/07 19:26:18  transier
00006  * getAngleToGoal removed
00007  *
00008  * Revision 1.34  2002/07/07 18:13:31  transier
00009  * improved getPassPartner function
00010  *
00011  * Revision 1.33  2002/07/07 15:20:05  transier
00012  * changed some parameters, private -> protected
00013  *
00014  * Revision 1.32  2002/07/07 14:10:39  ritter
00015  * changed some private functions to public
00016  *
00017  * Revision 1.31  2002/07/06 11:08:49  transier
00018  * remove NewData support from dash command
00019  * changed some paramteres
00020  *
00021  * Revision 1.30  2002/07/05 09:32:57  ritter
00022  * variation of some finals
00023  *
00024  * Revision 1.29  2002/07/04 21:45:03  ritter
00025  * variation of some finals
00026  *
00027  * Revision 1.28  2002/07/04 20:53:34  ritter
00028  * debugging THE bug
00029  *
00030  * Revision 1.27  2002/07/04 16:25:48  stork
00031  * reactivate log comments 2
00032  *
00033  * Revision 1.26  2002/07/04 16:19:13  stork
00034  * reactivate log comments
00035  *
00036  * Revision 1.22  2002/07/04 14:00:47  transier
00037  * debugging messages
00038  *
00039  * Revision 1.21  2002/07/03 20:55:16  transier
00040  * remove use of NewData, has to be added again
00041  *
00042  * Revision 1.20  2002/07/03 18:30:02  transier
00043  * changed logging
00044  *
00045  * Revision 1.19  2002/07/03 16:29:41  transier
00046  * debug output in logfile, update is called to often!
00047  *
00048  * Revision 1.18  2002/07/02 22:30:43  transier
00049  * debugging
00050  *
00051  * Revision 1.17  2002/07/02 15:06:02  transier
00052  * debugging
00053  *
00054  * Revision 1.16  2002/06/24 22:16:04  transier
00055  * debugging
00056  *
00057  * Revision 1.15  2002/06/24 21:31:54  transier
00058  * debugging
00059  *
00060  * Revision 1.14  2002/06/23 12:44:01  transier
00061  * debugging
00062  *
00063  * Revision 1.13  2002/06/21 16:53:42  transier
00064  * new structure of update function
00065  *
00066  * Revision 1.12  2002/06/16 18:40:13  transier
00067  * some debugging
00068  *
00069  * Revision 1.11  2002/06/15 17:31:30  ritter
00070  * debugging
00071  *
00072  * Revision 1.10  2002/06/14 21:43:57  transier
00073  * some debugging
00074  *
00075  * Revision 1.9  2002/06/11 20:24:38  transier
00076  * some debugging
00077  *
00078  * Revision 1.8  2002/06/09 23:29:58  transier
00079  * some debugging
00080  *
00081  * Revision 1.7  2002/06/06 18:15:19  transier
00082  * new function added:
00083  *   getGoalShootAngle
00084  * very first verions of:
00085  *   dribbleToPoint
00086  * some changes in update
00087  * arc to degrees
00088  *
00089  * Revision 1.6  2002/06/05 21:17:45  transier
00090  * new function added:
00091  *   getPassPartner
00092  *   getAngleToPoint
00093  *   gauss
00094  *
00095  * Revision 1.5  2002/06/04 20:31:09  transier
00096  * new function added:
00097  *   isBetween
00098  * some changes in update:
00099  *   the player is now restricted in its field
00100  *
00101  * Revision 1.4  2002/06/04 19:26:06  transier
00102  * new function added
00103  *   rotateToPoint
00104  * very first working versions of
00105  *   catchBall
00106  *   run
00107  *   rotate
00108  *   shout
00109  * some changes in update
00110  *
00111  * Revision 1.3  2002/05/30 20:01:01  transier
00112  * new function added
00113  *   calcDist
00114  * first working versions of
00115  *   enemiesHaveBall
00116  *   friendsHaveBall
00117  *   distanceToBall
00118  *   HasBall
00119  * very first working versions of
00120  *   searchBall
00121  *
00122  * Revision 1.2  2002/05/28 13:47:24  ritter
00123  * first version of rcbrain
00124  *
00125  * Revision 1.1.1.1  2002/05/21 20:32:04  stork
00126  * empty project
00127  *
00128  */
00129 
00130 import java.util.LinkedList;
00131 
00132 
00133 public class RCBrain
00134 {
00136   protected RCWorld World;
00137   protected RCCommunicator Communicator;
00138   protected double myX, myY;
00139 
00140   protected final double NEAR_BALL = 4.5;       // defines threshold for "the ball is near"
00141   protected final double MAX_KICK_DIST = .7;    // defines threshold for the range in which player can kick the ball
00142   protected final double NEAR_BORDER = 2.;      // defines threshold for player is near his boarder
00143   protected final double NEAR_GOAL = 53.;       // defines threshold for player is near the goal
00144   protected final double MAX_PASS_DIST = 70.;   // defines threshold for maximum pass distance
00145   protected final double MIN_PASS_DIST = 4.;    // defines threshold for minimum pass distance
00146   protected final double BEST_PASS_DIST = 15.;  // defines threshold for best pass distance
00147   protected final double BARRIER_ANGLE = 2.5;   // defines threshold for angle that has to be added to get the barriers size
00148   protected final double MIN_LIKELIHOOD_PASS = 0.25;    // defines threshold for minimum pass likelihood
00149   protected final double MIN_LIKELIHOOD_GOAL = 0.2;     // defines threshold for minimum goal likelihood
00150   protected final double POWER_COEFF_DASH = 30.;        // defines relation between distance and power for dash command
00151   protected final double MIN_POWER_DASH = 80;   // defines threshold for the minimum power a dash command is submitted
00152   protected final double POWER_COEFF_KICK = 120.;       // defines relation between distance and power for kick command
00153   protected final double MIN_RUN_DIST = 1.5;    // defines minimum distance to make a run
00154   protected final double HALF_OF_GOALWIDTH = 7.;        // defines the half width of the goal
00155   protected final double MAX_ANGLE = 7.;        // defines threshold for the maximunm angle differece between the player and his target point
00156   protected final double SEARCH_ANGLE = 40.;    // defines the angle value for players turn while searching the ball
00157   protected final double PRECISION = 0.001;
00158   protected final double GOAL_X = 52.5;
00159   protected final double GOAL_Y = 0.;
00160   protected final double KICK_POWER_DIRBBLE = 20.;
00161   protected final double DASH_POWER_DRIBBLE = 55.;
00162   protected final double MAX_POWER_KICK = 100.;
00163   protected final int MAX_TIME = 10;    // defines threshold in which position information of objects are valid
00164 
00165 
00173   protected double gauss (double x, double m, double sigma)
00174   {
00175 
00176     return Math.exp (-Math.pow (x - m, 2) / Math.pow (sigma, 2));
00177 
00178   }
00179  
00180  
00186   protected double dashPower (double distance)
00187   {
00188   
00189         double power = POWER_COEFF_DASH * Math.pow(distance,2)/(distance+1)+1;
00190         if (power > MAX_POWER_KICK)
00191                 power = MAX_POWER_KICK;
00192         return power;
00193         
00194   }
00195   
00196   
00202   protected double kickPower (double distance)
00203   {
00204         double power = POWER_COEFF_KICK * Math.atan(distance/50.);
00205         if (power > MAX_POWER_KICK)
00206                 power = MAX_POWER_KICK;
00207         return power;
00208         //return POWER_COEFF_KICK * distance/(distance+1);
00209   }
00210 
00211 
00222   protected double calcDist (double x1, double y1, double x2, double y2)
00223   {
00224 
00225     double sqrDist = Math.pow (x1 - x2, 2) + Math.pow (y1 - y2, 2);
00226 
00227     return Math.sqrt (sqrDist);
00228 
00229   }
00230 
00231 
00237   protected boolean isBetween (double value, double bound1, double bound2)
00238   {
00239 
00240     if (Math.abs (value - (bound1 + bound2) / 2.) + PRECISION <
00241         Math.abs ((bound1 - bound2) / 2.))
00242       return true;
00243     else
00244       return false;
00245   }
00246 
00247 
00253   public double getAngleToPoint (double x, double y)
00254   {
00255 
00256     double X = x - myX;
00257     double Y = y - myY;
00258 
00259     double angle;
00260     if (X != 0)
00261       angle = Math.atan (Math.abs (Y) / Math.abs (X));
00262     else
00263       angle = Math.PI / 2.;
00264 
00265     angle = angle * 180. / Math.PI;     // angle in degrees
00266 
00267     if (X < 0 && Y > 0)         // II.
00268       angle = 180 - angle;
00269     else if (X < 0 && Y < 0)    // III.
00270       angle = 180 + angle;
00271     else if (X >= 0 && Y < 0)   // IV.
00272       angle = 360 - angle;
00273 
00274 
00275     if (World.angle < 0)
00276       angle -= (360 + World.angle);     // rel. angle
00277     else
00278       angle -= World.angle;     // ...
00279 
00280     if (angle < -180)
00281       angle += 360;
00282     else if (angle > 180)
00283       angle -= 360;
00284 
00285     return angle;
00286   }
00287 
00288 
00294   protected RCPartner getPassPartner ()
00295   {
00296 
00297     int i, k;
00298     double distance, angle, likelihood, x, y;
00299     double offsidePos = -GOAL_X, goaliePos = -GOAL_X;
00300     LinkedList Barriers = new LinkedList ();
00301     RCPartner Partner = new RCPartner ();
00302     Partner.likelihood = 0;
00303     RCPartner Barrier;
00304 
00305     // sort the enemies into a list
00306     for (i = 0; i < 11; i++)
00307       {
00308 
00309                 x = World.Enemies[i].X (0);
00310                 y = World.Enemies[i].Y (0);
00311 
00312                 // where are the two least players? (offside)
00313                 if (x > offsidePos) {
00314                   if (x > goaliePos)
00315                     {
00316                       offsidePos = goaliePos;
00317                       goaliePos = x;
00318                     }
00319                   else
00320                     offsidePos = x;
00321                 }
00322 
00323                 distance = calcDist (myX, myY, x, y);
00324                 if (distance > MAX_PASS_DIST)
00325                   continue;
00326 
00327                 angle = getAngleToPoint (x, y);
00328 
00329                 Barriers.add (new RCPartner (World.Enemies[i], angle, distance));
00330 
00331       }
00332 
00333     for (i = 0; i < 11; i++)
00334       {
00335 
00336                 // myself?
00337                 if (i == (World.PlayerNumber - 1))
00338                   continue;
00339                   
00340                 // start value for likelihood
00341                 likelihood = 1;
00342 
00343                 // get the position of a possible pass partner
00344                 x = World.Friends[i].X (0);
00345                 y = World.Friends[i].Y (0);
00346 
00347                 // friend is offside -> continue
00348                 if (offsidePos < x && myX < offsidePos)
00349                   continue;
00350 
00351                 // calculate the pass distance
00352                 distance = calcDist (x, y, myX, myY);
00353                 if (distance > MAX_PASS_DIST || distance < MIN_PASS_DIST)
00354                   continue;
00355 
00356                 // claculate the angle
00357                 angle = getAngleToPoint (x, y);
00358 
00359                 // remove very bad pass partners
00360                 // 1.) friend is near an enemy
00361                 for (k = 0; k < Barriers.size (); k++)
00362                   {
00363                     Barrier = (RCPartner) Barriers.get (k);
00364                     if (distance < Barrier.distance)
00365                       continue;
00366                     if (Math.abs (angle - Barrier.angle) > BARRIER_ANGLE)
00367                       continue;
00368                     likelihood = 0;
00369                     break;
00370                   }
00371                 if (likelihood == 0)
00372                         continue; // partner is bad
00373                 // 2,) friend is near our goal
00374                 if (Math.pow(x+GOAL_X,2)+Math.pow(y,2)<=400) {
00375                         likelihood = 0;
00376                         continue; // partner is bad
00377                 }
00378                   
00379                 // set likelihood according to the distance
00380                 likelihood = gauss (distance, BEST_PASS_DIST, BEST_PASS_DIST / 2.);
00381 
00382                 // the friend which is nearer to goal is preferred
00383                 likelihood = 3./9.*likelihood + 4./9. * (x + 52.5) / 105. + 2./9. * gauss(x,40.,27.) * gauss(y,0.,22.);
00384                 
00385                 // is the likelihood better than the old one? -> we've got a better partner
00386                 if (likelihood > Partner.likelihood)
00387                   {
00388                     Partner.angle = angle;
00389                     Partner.distance = distance;
00390                     Partner.Player = World.Friends[i];
00391                     Partner.likelihood = likelihood;
00392                   }
00393       }
00394 
00395     return Partner;
00396   }
00397 
00398 
00403   protected boolean shoot ()
00404   {
00405 
00406     RCObject me = World.getOurself ();
00407     myX = me.X (0);
00408     myY = me.Y (0);
00409 
00410     double ballX = World.Ball.X (0);
00411     double ballY = World.Ball.Y (0);
00412 
00413     double ballDist = calcDist (myX, myY, ballX, ballY);
00414     double goalDist = calcDist (myX, myY, GOAL_X, GOAL_Y);
00415 
00416         // is the player able to kick?
00417     if (ballDist > MAX_KICK_DIST)
00418       return false;
00419 
00420     if (goalDist <= NEAR_GOAL)
00421       {
00422                 // player is near the goal -> try a goal shoot          
00423                 double angle = getAngleToPoint(GOAL_X, GOAL_Y);
00424                 double likelihood = 500/(angle*goalDist);
00425                 
00426                 if (likelihood > MIN_LIKELIHOOD_GOAL)
00427                   {                     
00428                     Communicator.kick(MAX_POWER_KICK, angle);
00429                     return true;
00430                   }
00431       }
00432 
00433     // try to pass
00434     RCPartner Partner = getPassPartner ();
00435     if (Partner.likelihood >= MIN_LIKELIHOOD_PASS)
00436       {
00437                 Communicator.kick (kickPower(Partner.distance), Partner.angle);
00438                 return true;
00439       }
00440 
00441     // no shoot was possible
00442     return false;
00443   }
00444 
00449   protected int dribbleToGoal ()
00450   {
00451 
00452     double ballX = World.Ball.X (0);
00453     double ballY = World.Ball.Y (0);
00454 
00455     double ballDist = calcDist (myX, myY, ballX, ballY);
00456     double goalDist = calcDist (myX, myY, GOAL_X, GOAL_Y);
00457 
00458     double goalAngle = getAngleToPoint (GOAL_X, GOAL_Y);
00459     double ballAngle = getAngleToPoint (ballX, ballY);
00460 
00461 
00462     if (ballDist > MAX_KICK_DIST)
00463       {
00464                 if (Math.abs (ballAngle) >= MAX_ANGLE && !World.NewData)
00465                   {
00466                     Communicator.turn (ballAngle);
00467                     return 0;
00468                   }
00469 
00470                  Communicator.dash (dashPower(ballDist));
00471       }
00472     else
00473       {
00474                  Communicator.kick (KICK_POWER_DIRBBLE, goalAngle);
00475       }
00476 
00477     return 0;
00478   }
00479 
00480 
00485   public boolean searchBall ()
00486   {
00487 
00488     if (World.Ball.Time (0) + MAX_TIME > World.CurrentTimeStamp)
00489       return true;
00490     return false;
00491   }
00492 
00493 
00498   public boolean inField (double x, double y)
00499   {
00500 
00501     if (isBetween (x, World.X1, World.X2) && isBetween (y, World.Y1, World.Y2))
00502       return true;
00503     return false;
00504   }
00505 
00506 
00511   public int update ()
00512   {
00513 
00514     RCObject me = World.getOurself ();
00515     myX = me.X (0);
00516     myY = me.Y (0);
00517 
00518     double ballX = World.Ball.X (0);
00519     double ballY = World.Ball.Y (0);
00520 
00521     double ballDist = calcDist (myX, myY, ballX, ballY);
00522     double goalDist = calcDist (myX, myY, GOAL_X, GOAL_Y);
00523 
00524     if (searchBall ())
00525       {
00526                 // found ball
00527                 if (ballDist <= NEAR_BALL)
00528                   {
00529                     // try to shoot
00530                     if (!shoot ())
00531                       {
00532                                 // no shoot possible
00533                                 dribbleToGoal ();
00534                                 return 0;
00535                       }
00536                     else
00537                       return 0;
00538                   }
00539                 else
00540                   {
00541                     // ball is far far away
00542                     if (inField (myX, myY))
00543                       {
00544                                 // the player is in its field
00545                                 if (inField (ballX, ballY))
00546                                   {
00547                                     // and the ball too -> go to ball
00548                                     double angle = getAngleToPoint (ballX, ballY);
00549                                     if (Math.abs (angle) >= MAX_ANGLE && !World.NewData)
00550                                       {
00551                                                 Communicator.turn (angle);
00552                                                 return 0;
00553                                       }
00554                                         Communicator.dash (dashPower(ballDist));
00555                                     return 0;
00556                                   }
00557                                 else
00558                                   {
00559                                     // ball is not in players field
00560                                     double targetX, targetY;
00561                                     double X = (World.X1 + World.X2) / 2.;      // instead of myX
00562                                     double Y = (World.Y1 + World.Y2) / 2.;      // ...        myY
00563 
00564                                     while (true)
00565                                       {
00566 
00567                                                 if (isBetween (World.X1, X, ballX))
00568                                                   {
00569                                                     // intersection between the border and the ball-player-line
00570                                                     targetY = (Y - ballY) / (X - ballX) * (World.X1 - ballX) + ballY;
00571                                                     if (isBetween (targetY, World.Y1, World.Y2))
00572                                                       {
00573                                                                 targetX = World.X1;
00574                                                                 break;
00575                                                       }
00576                                                   }
00577                                                 if (isBetween (World.X2, X, ballX))
00578                                                   {
00579                                                     // intersection between the border and the ball-player-line
00580                                                     targetY = (Y - ballY) / (X - ballX) * (World.X2 - ballX) + ballY;
00581                                                     if (isBetween (targetY, World.Y1, World.Y2))
00582                                                       {
00583                                                                 targetX = World.X2;
00584                                                                 break;
00585                                                       }
00586                                                   }
00587                                                 if (isBetween (World.Y1, Y, ballY))
00588                                                   {
00589                                                     // intersection between the border and the ball-player-line
00590                                                     targetX = (X - ballX) / (Y - ballY) * (World.Y1 - ballY) + ballX;
00591                                                     if (isBetween (targetX, World.X1, World.X2))
00592                                                       {
00593                                                                 targetY = World.Y1;
00594                                                                 break;
00595                                                       }
00596                                                   }
00597                                                 if (isBetween (World.Y2, Y, ballY))
00598                                                   {
00599                                                     // intersection between the border and the ball-player-line
00600                                                     targetX = (X - ballX) / (Y - ballY) * (World.Y2 - ballY) + ballX;
00601                                                     if (isBetween (targetX, World.X1, World.X2))
00602                                                       {
00603                                                                 targetY = World.Y2;
00604                                                                 break;
00605                                                       }
00606                                                   }
00607                         
00608                                                 targetX = (World.X1 + World.X2) / 2.;
00609                                                 targetY = (World.Y1 + World.Y2) / 2.;
00610                                                 break;
00611                                       }
00612                         
00613                                     double distance = calcDist (myX, myY, targetX, targetY);
00614 
00615                                     if (distance > MIN_RUN_DIST)
00616                                       {
00617                                                 double angle = getAngleToPoint (targetX, targetY);
00618                                                 if (Math.abs (angle) > MAX_ANGLE && !World.NewData)
00619                                                   {
00620                                                     Communicator.turn (angle);
00621                                                     return 0;
00622                                                   }
00623                                                 double power = dashPower(distance);
00624                                                 if (power >= MIN_POWER_DASH)
00625                                                   {
00626                                                     Communicator.dash (power);
00627                                                     return 0;
00628                                                   }
00629                                       }
00630                                   }
00631                       }
00632                     else
00633                       {
00634                                 // player not in its field (and the ball is far far away, as you know) -> go home
00635                                 double targetX = (World.X1 + World.X2) / 2.;
00636                                 double targetY = (World.Y1 + World.Y2) / 2.;
00637                 
00638                                 double angle = getAngleToPoint (targetX, targetY);
00639                                 if (Math.abs (angle) >= MAX_ANGLE && !World.NewData)
00640                                   {
00641                                     Communicator.turn (angle);
00642                                     return 0;
00643                                   }
00644                 
00645                                 double distance = calcDist (myX, myY, targetX, targetY);
00646                                 Communicator.dash (dashPower(distance));
00647                                 return 0;
00648                       }
00649                   }
00650       }
00651     else
00652       {
00653         // ball not found
00654                 if (!inField (myX, myY))
00655                   {
00656                     //player not in its field go home
00657                     double targetX = (World.X1 + World.X2) / 2.;
00658                     double targetY = (World.Y1 + World.Y2) / 2.;
00659         
00660                     double angle = getAngleToPoint (targetX, targetY);
00661                     if (Math.abs (angle) >= MAX_ANGLE && !World.NewData)
00662                       {
00663                                 Communicator.turn (angle);
00664                                 return 0;
00665                       }
00666 
00667                     double distance = calcDist (myX, myY, targetX, targetY);
00668                         Communicator.dash (dashPower(distance));
00669                     return 0;
00670                   }
00671                 else
00672                   {
00673                     // turn to see the ball
00674                     if (!World.NewData)
00675                       Communicator.turn (SEARCH_ANGLE);
00676                     return 0;
00677                   }
00678       }
00679 
00680     return 1;
00681   }
00682 
00683 
00690   public RCBrain (RCWorld World, RCCommunicator Communicator)
00691   {
00692     this.World = World;
00693     this.Communicator = Communicator;
00694   }
00695 }

(c) Copyright by Gruppe 1 :
  • Frederik Transier
  • Motitz Ritter
  • Oliver Strassburger
  • Sven Stork