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 }