Можете ли вы объяснить, что означает этот код из robocode?

Я не понимаю, что именно делает этот метод. Может ли кто-нибудь объяснить мне этот триг?

public void onScannedRobot(ScannedRobotEvent e)
  {
    setTurnRadarLeftRadians(getRadarTurnRemaining());

    setTurnRight(e.getBearing() + 90.0D - dir / 33.0D);
    if (((Guppy.var = var - e.getEnergy()) <= 3) && (var > 0.0D))
    {
      setMaxVelocity(Math.random() * 9.0D + 3);
      setAhead(Guppy.dir = dir * type);
    }
    setTurnGunRightRadians(Math.sin((Guppy.var = e.getBearingRadians() + getHeadingRadians()) - getGunHeadingRadians() + Math.asin((vel * 0.4D + e.getVelocity() * 0.6D) / 14.0D * Math.sin(e.getHeadingRadians() - var))));
    if (getGunHeat() == 0.0D)
    {
      setFire(2.9D);
      vel = e.getVelocity();
    }
    var = e.getEnergy();
  }

2 ответа

Решение

Следует обратить внимание на тех, кто знаком с тригонометрией, но не с Robocode: угловые значения Robocode неотрицательны и увеличиваются по часовой стрелке, а не по центру и увеличиваются против часовой стрелки, как в тригонометрическом соглашении.

Святая корова, это шерсть. Тяжелый стиль, также присвоение переменной, а затем ее использование в том же выражении и случайное повторное использование static переменные для разных целей. (РЕДАКТИРОВАТЬ: у меня слишком долго не было Robocode; запутанные на вид беспорядки, вероятно, являются результатом ручной оптимизации для размера кода.) Давайте попробуем снять эту грязную строку, начиная здесь:

setTurnGunRightRadians(Math.sin((Guppy.var = e.getBearingRadians() + getHeadingRadians()) - getGunHeadingRadians() + Math.asin((vel * 0.4D + e.getVelocity() * 0.6D) / 14.0D * Math.sin(e.getHeadingRadians() - var))));

Похоже var используется для хранения результата подвыражения e.getBearingRadians() + getHeadingRadians(), поскольку e.getBearingRadians() возвращает направление цели относительно вашего курса, var является абсолютной целью цели. Refactored:

double targetBearing = e.getBearingRadians() + getHeadingRadians();
setTurnGunRightRadians(Math.sin(targetBearing - getGunHeadingRadians() + Math.asin((vel * 0.4D + e.getVelocity() * 0.6D) / 14.0D * Math.sin(e.getHeadingRadians() - targetBearing))));

Тьфу, все еще беспорядок. У нас также есть переменная vel не учитывается, но, исходя из остальной части кода, кажется, что это скорость цели при последнем сканировании (и при поспешном предположении, что будут сыграны только матчи один на один); оно объединено в средневзвешенное значение с текущей скоростью, чтобы дать приблизительную прогнозируемую скорость, поэтому здесь, вероятно, существует некоторая логика, ведущая к цели.

double targetBearing = e.getBearingRadians() + getHeadingRadians();
double predictedVelocity = vel * 0.4D + e.getVelocity() * 0.6D;
setTurnGunRightRadians(Math.sin(targetBearing - getGunHeadingRadians() + Math.asin(predictedVelocity / 14.0D * Math.sin(e.getHeadingRadians() - targetBearing))));

Поскольку Робокод, по-видимому, игнорирует разницу между курсом и курсом, самый внутренний синус Math.sin(e.getHeadingRadians() - targetBearing) дает знаковый коэффициент, указывающий, какая составляющая скорости цели перпендикулярна ее пеленгу и, следовательно, требует регулировки угла стрельбы.

double targetBearing = e.getBearingRadians() + getHeadingRadians();
double predictedVelocity = vel * 0.4D + e.getVelocity() * 0.6D;
double perpendicularMotionCoefficient = Math.sin(e.getHeadingRadians() - targetBearing);
setTurnGunRightRadians(Math.sin(targetBearing - getGunHeadingRadians() + Math.asin(predictedVelocity / 14.0D * perpendicularMotionCoefficient)));

Дугосинусное выражение, похоже, предназначено для превращения перпендикулярной составляющей движения цели обратно в угловую регулировку. Этот бит математики совершенно неверен, потому что арксинус не работает таким образом: он превращает коэффициент в интервале [-1, 1] обратно в угол в интервале [-pi/2, pi/2], и деление предсказанной скорости на 14, вероятно, является просто попыткой связать аргумент с арксинусом внутри его области. Опять же, ни расстояние до цели, ни скорость снаряда не влияют на вычисление, поэтому лучшее, что я могу сказать об этой настройке, это то, что она неопределенно в правильном направлении.

double targetBearing = e.getBearingRadians() + getHeadingRadians();
double predictedVelocity = vel * 0.4D + e.getVelocity() * 0.6D;
double perpendicularMotionCoefficient = Math.sin(e.getHeadingRadians() - targetBearing);
double firingAngleAdjustment = Math.asin(predictedVelocity / 14.0D * perpendicularMotionCoefficient);
setTurnGunRightRadians(Math.sin(targetBearing - getGunHeadingRadians() + firingAngleAdjustment));

Этот последний синус не имеет никакого смысла для меня вообще. Аргумент - это уже угол в радианах, на который должно перемещаться оружие: абсолютная ось цели минус текущий курс пистолета (то есть, насколько далеко нужно повернуть оружие, чтобы точно указать цель), плюс регулировка угла стрельбы для движение цели. Я просто полностью уберу функцию синуса.

double targetBearing = e.getBearingRadians() + getHeadingRadians();
double predictedVelocity = vel * 0.4D + e.getVelocity() * 0.6D;
double perpendicularMotionCoefficient = Math.sin(e.getHeadingRadians() - targetBearing);
double firingAngleAdjustment = Math.asin(predictedVelocity / 14.0D * perpendicularMotionCoefficient);
setTurnGunRightRadians(targetBearing - getGunHeadingRadians() + firingAngleAdjustment);

Конечно, это также зависит от того, автоматически ли понимается установка пистолета на поворот больше, чем на пол-оборота (пи радианы), чтобы вместо этого повернуть его на пол-оборота в другом направлении... вы можете в конечном итоге делать много бессмысленных в противном случае.

    public void onScannedRobot(ScannedRobotEvent e) // for every robots that your robot see {
setTurnRadarLeftRadians(getRadarTurnRemaining()); // Sets the robot's radar to turn left by radians 
setTurnRight(e.getBearing() + 90.0D - dir / 33.0D); //   Sets the robot's body to turn right by degrees, basically you are depending it in your enemy
if (((Guppy.var = var - e.getEnergy()) <= 3) && (var > 0.0D))
{
  setMaxVelocity(Math.random() * 9.0D + 3); //Sets the maximum velocity of the robot measured in pixels/turn if the robot should move slower than Rules.MAX_VELOCITY (8 pixels/turn).
  setAhead(Guppy.dir = dir * type);
}
setTurnGunRightRadians(Math.sin((Guppy.var = e.getBearingRadians() + getHeadingRadians()) - getGunHeadingRadians() + Math.asin((vel * 0.4D + e.getVelocity() * 0.6D) / 14.0D * Math.sin(e.getHeadingRadians() - var))));
if (getGunHeat() == 0.0D)
{
  setFire(2.9D); // how big is the damage of the bullet. The bigger the damage= bigger energy consumed
  vel = e.getVelocity(); //get the enemy velocity
}
var = e.getEnergy(); // get the enemy energy

}

Если вы хотите, вы можете поиграть с этим моим мини-проектом:

                    package sample;
                import robocode.*;
                import java.awt.Color;
                import java.awt.geom.*;
                import java.lang.*;         // for Double and Integer objects
                import java.util.*; // for collection of waves
                import robocode.util.Utils;

                import robocode.RobotDeathEvent;
                import robocode.Rules;
                import robocode.ScannedRobotEvent;
                import robocode.util.Utils;

                /*
            A Robocode that implements the smart targeting(always attack on the nearest opponent) and circles around them
                */

                public class Tutorial extends AdvancedRobot
                {   boolean movingForward;
                    boolean peek; // Don't turn if there's a robot there
                    double moveAmount; // How much to move
                    byte moveDirection= 1;
                    int tooCloseToWall = 0;
                    int wallMargin = 60;

                    static final double GUN_FACTOR = 30;
                    static final double AIM_FACTOR = 25;
                    static final int AIM_START = 10;
                    static final int FIRE_FACTOR = 100;
                    private long    currTime;               
                    static final long RADARTIMEOUT  = 20;
                    static double xForce;
                    static double yForce;
                    static double lastDistance;

                    private boolean radarScan;              
                    private long    lastscan;               

                    public void run(){

                        setAdjustRadarForGunTurn(true);
                        setAdjustGunForRobotTurn(true);

                        // Sets these colors (robot parts): body, gun, radar, bullet, scan_arc
                        setBodyColor(new Color(255, 255, 255));
                        setGunColor(new Color(255, 255, 255));
                        setRadarColor(new Color(255, 255, 255));
                        setBulletColor(new Color(0, 0, 0));
                        setScanColor(new Color(255, 255, 255));

                        while(true) {
                            currTime = getTime();
                            turnRadarRightRadians(Double.POSITIVE_INFINITY);
                            turnRadarLeftRadians(Double.POSITIVE_INFINITY);
                            radarScan = true;
                        }
                    }

                    public void onScannedRobot(ScannedRobotEvent e) {

                        double absoluteBearing = e.getBearingRadians()+ getHeadingRadians();
                        double  distance = e.getDistance();
                        double  bulletPower ;
                        double headingRadians = getHeadingRadians();
                        boolean fired = false;

                        if(getOthers() >= 2){

                            xForce = xForce *.80- Math.sin(absoluteBearing) / distance;
                            yForce = yForce *.80 - Math.cos(absoluteBearing) / distance;

                        setTurnRightRadians(Utils.normalRelativeAngle(
                            Math.atan2(xForce + 1/getX() - 1/(getBattleFieldWidth() - getX()), 
                                       yForce + 1/getY() - 1/(getBattleFieldHeight() - getY()))
                                        - getHeadingRadians()) );
                        setAhead(150- Math.abs(getTurnRemaining()));//speed
                        bulletPower = ( distance > 850 ? 0.1 : (distance > 700 ? 0.49 : (distance > 250 ? 1.9 : 3.0)));
                                bulletPower = Math.min( getEnergy()/5, Math.min( (e.getEnergy()/4) + 0.2, bulletPower));

                        if ((getGunHeat() <= 3.0) && (getGunTurnRemaining() == 0.0) && (bulletPower > 0.0) && (getEnergy() > 9.1)) {
                        // Only fire the gun when it is locked and loaded, do a radarsweep afterwards.
                        bulletPower=3;
                        setFire( bulletPower);
                        fired = true;
                        }
                        if ((fired == true) || (currTime >= (lastscan + RADARTIMEOUT))) {
                            setTurnRadarRightRadians( Double.NEGATIVE_INFINITY * Utils.normalRelativeAngle( absoluteBearing- getRadarHeadingRadians()));
                            lastscan = currTime;
                            radarScan = true;
                        }

                        // when not firing, lock on target.
                        //setTurnRadarRightRadians( 2.2 * Utils.normalRelativeAngle( absoluteBearing - getRadarHeadingRadians()));
                        //radarScan = false;

                        lastDistance = Double.POSITIVE_INFINITY;
                        setTurnRadarLeft(getRadarTurnRemaining());
                        setTurnRadarRight(getRadarTurnRemaining());

                        if(lastDistance+20 > distance){
                            lastDistance = distance;
                            if(getGunHeat() < .1){
                                setTurnRadarLeft(getRadarTurnRemaining());
                                setTurnRadarRight(getRadarTurnRemaining());
                                clearAllEvents();
                            }
                            setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians() + Math.max(1 - distance / (40), 0) * (e.getVelocity() / (AIM_START + Math.pow(AIM_FACTOR, distance))) * Math.sin(e.getHeadingRadians() - absoluteBearing) ));       
                            }
                    }

                        if(getOthers() == 1){

                            setBodyColor(new Color(255, 0, 0));
                            setGunColor(new Color(255,  0, 0));
                            setRadarColor(new Color(255, 0, 0));
                            setBulletColor(new Color(255, 0, 0));
                            setScanColor(new Color(255, 0, 0));

                            double bulletPower1 = 3;
                            if(distance >= 700){
                                lastDistance = Double.POSITIVE_INFINITY;
                            }

                            else if (distance < 700 && distance > 500){
                                bulletPower = 3 - (( 24.5- getEnergy()) / 6);
                                if (getEnergy() >= 3.1 ) {
                                    setFire(bulletPower);
                                    lastDistance = Double.POSITIVE_INFINITY;
                                }
                                else{
                                    lastDistance = Double.POSITIVE_INFINITY;
                                }
                            }

                        else if (distance <=500 && distance >=350){
                            bulletPower = 3 - (( 17.5- getEnergy()) / 6);
                            if (getEnergy() >= 3.1 ) {
                                setFire(bulletPower);
                                lastDistance = Double.POSITIVE_INFINITY;
                            }
                            else{
                                lastDistance = Double.POSITIVE_INFINITY;
                            }
                        }

                        else if (distance < 350 ){
                            bulletPower = 3 - (( 5- getEnergy()) / 6);
                            if (getEnergy() >= 3.1 ) {
                                setFire(bulletPower);
                                lastDistance = Double.POSITIVE_INFINITY;
                            }
                            else{
                                lastDistance = Double.POSITIVE_INFINITY;
                            }
                        }

                    if(lastDistance+25 > distance){
                        lastDistance = distance;
                        if(getGunHeat() < .1){
                                setTurnRadarLeft(getRadarTurnRemaining());
                                setTurnRadarRight(getRadarTurnRemaining());
                                clearAllEvents();
                        clearAllEvents();
                    }
                setTurnGunRightRadians(robocode.util.Utils.normalRelativeAngle(absoluteBearing - getGunHeadingRadians() + Math.max(1 - distance / (400), 0) * (e.getVelocity() / (AIM_START + Math.pow(AIM_FACTOR, distance))) * Math.sin(e.getHeadingRadians() - absoluteBearing) ));      
                }
                    wall();
                    // always square off against our enemy, turning slightly toward him
                    setTurnRight(e.getBearing() + 90 - (10 * moveDirection));
                    // if we're close to the wall, eventually, we'll move away
                    if (tooCloseToWall > 0) tooCloseToWall--;
                    // normal movement: switch directions if we've stopped
                    if (getVelocity() == 0) {
                        setMaxVelocity(8);
                        moveDirection *= -1;
                        setAhead(500 * moveDirection);
                    }
            }
    }   

                    public void onHitByBullet(HitByBulletEvent e) {
                        setTurnRadarLeft(getRadarTurnRemaining());
                        setTurnRadarRight(getRadarTurnRemaining());
                        clearAllEvents();
                    }

                    public void onBulletMissed(BulletMissedEvent e) {
                        setTurnRadarLeft(getRadarTurnRemaining());
                        setTurnRadarRight(getRadarTurnRemaining());
                        clearAllEvents();
                    }

                    public void onHitRobot(HitRobotEvent e) {
                        setTurnRadarLeft(getRadarTurnRemaining());
                        setTurnRadarRight(getRadarTurnRemaining());
                        clearAllEvents();
                    }

                    public void wall(){
                    //close to left, right, bottom, top wall
                    if(getX() <= wallMargin || getX() >= getBattleFieldWidth() - wallMargin || getY() <= wallMargin || getY() >= getBattleFieldHeight() - wallMargin){
                    if(tooCloseToWall <= 0){
                    // coming near the wall
                        tooCloseToWall += wallMargin;
                        setMaxVelocity(0); // stop!!!
                    }
            }
    }   

}

Другие вопросы по тегам