Robocode好手的法门 – 因数避墙法(factored wall avoidance)
副标题#e#
我们只要对在 Tracking your opponents’ movement中做的呆板人加以增补 ,就能将因数避墙法添加到现有的或讨厌的移动算法中。这种要领将预想的偏向 和按照呆板人和墙之间间隔远近确定的安详偏向作为因数试图找到最大概的偏向 。
添加做常见数学计较的帮助要领
我们先要给呆板人添加常见数学算法利用的一些帮助要领。
calculateBearingToXYRadians() 要领利用 java.lang.Math 中的 atan2() 要领来计较从 sourceX,sourceY 到 targetX,targetY 的绝对方位,然后再把这 个值转化为相对付 sourceHeading 的相对方位。
我们还需要 normalizeAbsoluteAngleRadians() 要领和 normalizeRelativeAngleRadians() 要领。
清单 1. 数学帮助要领
private static final double DOUBLE_PI = (Math.PI *  2);
private static final double HALF_PI = (Math.PI / 2);
public double calculateBearingToXYRadians(double sourceX, double  sourceY,
   double sourceHeading, double targetX, double targetY)  {
     return normalizeRelativeAngleRadians(
       Math.atan2((targetX - sourceX), (targetY -  sourceY)) -
         sourceHeading);
   }
public double normalizeAbsoluteAngleRadians(double angle) {
   if (angle < 0) {
     return (DOUBLE_PI + (angle % DOUBLE_PI));
   } else {
     return (angle % DOUBLE_PI);
   }
}
public static double normalizeRelativeAngleRadians(double angle)  {
   double trimmedAngle = (angle % DOUBLE_PI);
   if (trimmedAngle > Math.PI) {
     return -(Math.PI - (trimmedAngle % Math.PI));
   } else if (trimmedAngle < -Math.PI) {
     return (Math.PI + (trimmedAngle % Math.PI));
   } else {
     return trimmedAngle;
   }
}
#p#副标题#e#
使 AdvancedRobot 扩展到有倒行成果
接着,为了以相反偏领导航,我们需要用一些帮助要领把 AdvancedRobot 类 的成果扩展到答允倒行操纵:
getRelativeHeading() 要领将应付正确计较相对付呆板人当前的偏向的相对 偏向发生的特别开销。
reverseDirection() 很是简朴。它认真 direction 实例变量的开关和使机 器人掉头。请留意,由于减速需要时间,依据呆板人的速度,在掉过甚来之前最 多会沿本来的偏向再走 4 格。
setAhead() 和 setBack() 要领将包围 AdvancedRobot 类中的同名要领。这 两个要了解配置呆板人对付今朝偏向的相对速度,须要的时候,还会调解 direction 实例变量。我们这么做的目标是要确保相对操纵都与呆板人当前的移 动偏向有关。
setTurnLeftRadiansOptimal() 和 setTurnRightRadiansOptimal() 要领使 呆板人的偏向转过的角度高出 (Math.PI / 2) 。您会但愿这个要领和 adjustHeadingForWalls 要领(我们将在后头接头)一起利用。
注:我没有利用 getter 和 setter 要领,而是直接存取 direction 实例变 量。尽量凡是这并非精采的编程习惯,但为了加速数据存取,在我的呆板人代码 中我一直都是直接存取的。
清单 2. 呆板人帮助要领
public double getRelativeHeadingRadians() {
   double relativeHeading = getHeadingRadians();
   if (direction < 1) {
     relativeHeading =
         normalizeAbsoluteAngleRadians(relativeHeading +  Math.PI);
   }
   return relativeHeading;
}
public void reverseDirection() {
   double distance = (getDistanceRemaining() *  direction);
   direction *= -1;
   setAhead(distance);
}
public void setAhead(double distance) {
   double relativeDistance = (distance * direction);
   super.setAhead(relativeDistance);
   if (distance < 0) {
     direction *= -1;
   }
}
public void setBack(double distance) {
   double relativeDistance = (distance * direction);
   super.setBack(relativeDistance);
   if (distance > 0) {
     direction *= -1;
   }
}
public void setTurnLeftRadiansOptimal(double angle) {
   double turn = normalizeRelativeAngleRadians(angle);
   if (Math.abs(turn) > HALF_PI) {
     reverseDirection();
     if (turn < 0) {
       turn = (HALF_PI + (turn % HALF_PI));
     } else if (turn > 0) {
       turn = -(HALF_PI - (turn % HALF_PI));
     }
   }
   setTurnLeftRadians(turn);
}
public void setTurnRightRadiansOptimal(double angle) {
   double turn = normalizeRelativeAngleRadians(angle);
   if (Math.abs(turn) > HALF_PI) {
     reverseDirection();
     if (turn < 0) {
       turn = (HALF_PI + (turn % HALF_PI));
     } else if (turn > 0) {
       turn = -(HALF_PI - (turn % HALF_PI));
     }
   }
     setTurnRightRadians(turn);
}
添加因数避墙法
我们需要添加的最后一个要领是 adjustHeadingForWalls() 要领。
#p#分页标题#e#
这个要领的前面一半按照呆板人和墙的接近水平选择 安详的 x 和 y 的位置 (呆板人当前的 x 或 y 位置,可能假如呆板人接近墙,则就是中心点)。要领 的后头一半则计较间隔“安详点”的方位,并把这个方位和依呆板人离墙远近得 到的预想偏向都作为因数思量在内。
可以利用 WALL_AVOID_INTERVAL 和 WALL_AVOID_FACTORS 常量来调解呆板人 对墙的担心水平。
清单 3. 避墙法要领
private static final double  WALL_AVOID_INTERVAL = 10;
private static final double WALL_AVOID_FACTORS = 20;
private static final double WALL_AVOID_DISTANCE =
     (WALL_AVOID_INTERVAL * WALL_AVOID_FACTORS);
private double adjustHeadingForWalls(double heading) {
   double fieldHeight = getBattleFieldHeight();
   double fieldWidth = getBattleFieldWidth();
   double centerX = (fieldWidth / 2);
   double centerY = (fieldHeight / 2);
   double currentHeading = getRelativeHeadingRadians();
   double x = getX();
   double y = getY();
   boolean nearWall = false;
   double desiredX;
   double desiredY;
   // If we are too close to a wall, calculate a course  toward
   // the center of the battlefield.
   if ((y < WALL_AVOID_DISTANCE) ||
       ((fieldHeight - y) < WALL_AVOID_DISTANCE))  {
     desiredY = centerY;
     nearWall = true;
   } else {
     desiredY = y;
   }
   if ((x < WALL_AVOID_DISTANCE) ||
       ((fieldWidth - x) < WALL_AVOID_DISTANCE)) {
     desiredX = centerX;
     nearWall = true;
   } else {
     desiredX = x;
   }
   // Determine the safe heading and factor it in with  the desired
   // heading if the bot is near a wall 
   if (nearWall) {
     double desiredBearing =
       calculateBearingToXYRadians(x,
                     y,
                     currentHeading,
                     desiredX,
                     desiredY);
     double distanceToWall = Math.min(
         Math.min(x, (fieldWidth - x)),
         Math.min(y, (fieldHeight - y)));
     int wallFactor =
         (int)Math.min((distanceToWall /  WALL_AVOID_INTERVAL),
                WALL_AVOID_FACTORS);
     return ((((WALL_AVOID_FACTORS - wallFactor) *  desiredBearing) +
          (wallFactor * heading)) /  WALL_AVOID_FACTORS);
   } else {
     return heading;
   }
} 
汇总
其余的事情很容易。我们可以利用今朝的导航算法,将得出的功效送入 adjustHeadingForWalls() 要领来避开墙。
为了保持简朴,示例呆板人要求偏向改变为零,从而试着沿直线移动。
清单 4. 避墙法要领
public void run() {
   while(true) {
     setTurnRightRadiansOptimal(adjustHeadingForWalls(0));
     setAhead(100);
     execute();
   }
}
关于它就是这样了。简朴,但有效。