Difference between revisions of "Quantum/Source (Java)"

From Robowiki
Jump to navigation Jump to search
m (Fix syntax highlighting)
(Update to v1.0.0)
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
The following code is functionally equivalent to [[Quantum/Source (Assembly)]] but when compiled with OpenJDK 17 it will be 265 bytes.
 +
 
<syntaxhighlight lang="java">
 
<syntaxhighlight lang="java">
// -------------------------------------------------------------------------------------------------
 
// ==============
 
// Quantum (Nano)
 
// ==============
 
// Author: David414
 
// License: RWPCL (https://robowiki.net/wiki/RWPCL)
 
// -------------------------------------------------------------------------------------------------
 
 
// -------------------------------------------------------------------------------------------------
 
// Credits
 
// -------------------------------------------------------------------------------------------------
 
// Quantum started out life as a tweaked version of Mike Dorgan's DustBunny before being heavily
 
// shrunk to make room for improved target tracking (inspired by Infinity, also by Mike).
 
 
// -------------------------------------------------------------------------------------------------
 
// Version History
 
// -------------------------------------------------------------------------------------------------
 
// ================================================================================
 
// v0.2.2 (2024-04-06) Codesize: 249  | Colors: Yes | 1v1 capable: No
 
// ================================================================================
 
// - Antigravity movement based on DustBunny, but with forces calculated based on
 
//  where we would aim to hit the enemy, rather than where they currently are
 
// - Aim like DustBunny but with different energy management based only on how
 
//  many enemies are still alive. Fire more agressively early on and much less
 
//  agressively in 1v1
 
// - Quite a bit of code shrinking to make room for Infinity style target tracking
 
//
 
// Nano melee:    2nd APS (64.81),  1st Survival (25.36)
 
// Micro melee:    9th APS (64.17),  3rd Survival (25.20)
 
// Mini melee:    18th APS (63.52),  8th Survival (24.63)
 
// General melee: 67th APS (60.56), 55th Survival (21.60)
 
//
 
// Knocked DustBunny off of the top of the table for a few days before settling in to second place.
 
// Only 0.2 APS behind but significantly ahead on survival.
 
// Currently assumes a 1000x1000 battlefield. There would be space to remove this restriction but
 
// that would mean giving up on my colours :(
 
//
 
// ================================================================================
 
// v0.2.2a (2024-04-11) Codesize: 249  | Colors: Yes | 1v1 capable: No
 
// ================================================================================
 
// - No functional changes, added credits, version history and commented the code
 
 
// -------------------------------------------------------------------------------------------------
 
// TODO
 
// -------------------------------------------------------------------------------------------------
 
// - Measure the APS/Survival impact of moving setTurnRadarRight from run() to onRobotDeath()
 
// - Experiment with other guns and energy management
 
// - Find a way to avoid doing a circle of death in the corner, mainly an issue in the final 1v1
 
// - Thorough testing of different settings for the tuning knobs
 
 
 
package d414.nano;
 
package d414.nano;
  
Line 61: Line 13:
 
     // Tuning Knobs
 
     // Tuning Knobs
 
     // ---------------------------------------------------------------------------------------------
 
     // ---------------------------------------------------------------------------------------------
     static final double WALL_FORCE = 1;
+
     static final double WALL_FORCE = 1.0;
 
     static final double AGRAV_DECAY = 0.9;
 
     static final double AGRAV_DECAY = 0.9;
     static final double AHEAD_AMOUNT = 120;
+
     static final double AHEAD_AMOUNT = 120.0;
  
     static final double AIM_START = 10;
+
     static final double AIM_START = 10.0;
 
     static final double AIM_FACTOR = 1.008;
 
     static final double AIM_FACTOR = 1.008;
     static final double RADAR_LOCK_THRESHOLD = 1;
+
    static final double AIM_TOLERANCE = 18.0;
     static final int    POWER_FACTOR = 2;
+
    static final double BULLET_POWER = 2.49999;
 +
    static final double ENERGY_FACTOR = 7.0;
 +
     static final double RADAR_LOCK_THRESHOLD = 1.0;
 +
 
 +
    // ---------------------------------------------------------------------------------------------
 +
    // Constants
 +
    // ---------------------------------------------------------------------------------------------
 +
     static final double BATTLEFIELD_SIZE = 1000.0;
  
 
     // ---------------------------------------------------------------------------------------------
 
     // ---------------------------------------------------------------------------------------------
Line 80: Line 39:
 
     @Override
 
     @Override
 
     public void run() {
 
     public void run() {
         setAllColors(Color.cyan);
+
         //setAllColors(Color.cyan);
         setAdjustGunForRobotTurn(true);
+
         setTurnRadarRight(targetDistance = Double.POSITIVE_INFINITY);
        onRobotDeath(null);
 
 
     }
 
     }
  
    // Moving setTurnRadarRight here, instead of in run(), saves 1 byte
 
 
     @Override
 
     @Override
     public void onRobotDeath(RobotDeathEvent e) {
+
     public void onRobotDeath(RobotDeathEvent r1e) {
         setTurnRadarRight(targetDistance = Double.POSITIVE_INFINITY);
+
         targetDistance = Double.POSITIVE_INFINITY;
 
     }
 
     }
  
 
     @Override
 
     @Override
     public void onScannedRobot(ScannedRobotEvent e) {
+
     public void onScannedRobot(ScannedRobotEvent r1e) {
         double distance; // Keep this first to save 2 bytes
+
         double r1d;
         double absoluteBearing;
+
         double r3d;
        double aimAngle;
 
  
         // 1. Calculate the angle DustBunny 3.8's gun would aim at
+
         setAdjustGunForRobotTurn(true);
        // 2. Update rolling averages of antigravity forces, using the aim angle of DustBunny 3.8's
+
         setTurnLeftRadians(Utils.normalRelativeAngle(
        //    gun instead of the absoluteBearing
+
                     (r3d = getHeadingRadians())
        // 3. Move based on angtigravity forces
+
                    - Math.atan2(
         setTurnRightRadians(Utils.normalRelativeAngle(
 
                     Math.atan2(
 
 
                         (xForce = xForce * AGRAV_DECAY
 
                         (xForce = xForce * AGRAV_DECAY
                         - Math.sin(
+
                         - Math.sin(r3d = (r3d += r1e.getBearingRadians())
                            aimAngle = (absoluteBearing = e.getBearingRadians() + getHeadingRadians())
+
                            + (Math.sin(r1e.getHeadingRadians() - r3d)
                            + (e.getVelocity()
+
                                * r1e.getVelocity()
                                 / (AIM_START + Math.pow(AIM_FACTOR, distance = e.getDistance()))
+
                                 / (AIM_START + Math.pow(AIM_FACTOR, r1d = r1e.getDistance()))
 
                               )
 
                               )
                            * Math.sin(e.getHeadingRadians() - absoluteBearing)
+
                             ) / r1d
                             ) / distance
 
 
                         )
 
                         )
 
                         + calcWallForce(getX())
 
                         + calcWallForce(getX())
                        //+ calcWallForce(getX(), getBattleFieldWidth())
 
 
                         ,  
 
                         ,  
                         (yForce = yForce * AGRAV_DECAY - Math.cos(aimAngle) / distance)
+
                         (yForce = yForce * AGRAV_DECAY - Math.cos(r3d) / r1d)
 
                         + calcWallForce(getY())
 
                         + calcWallForce(getY())
                        //+ calcWallForce(getY(), getBattleFieldHeight())
 
 
                         )
 
                         )
                    - getHeadingRadians()
 
 
                     ));
 
                     ));
         setAhead(AHEAD_AMOUNT - Math.abs(getTurnRemaining()));
+
         setBack(Math.abs(getTurnRemaining()) - AHEAD_AMOUNT);
       
 
        // Use Infinity style target tracking
 
        if (distance < targetDistance || e.getName() == targetName) {
 
            targetName = e.getName();
 
            targetDistance = distance;
 
  
            if (getGunHeat() < RADAR_LOCK_THRESHOLD) {
+
        if (r1e.getName() == targetName || r1d < targetDistance) {
                setTurnRadarLeft(getRadarTurnRemaining());
+
            targetName = r1e.getName();
             }
+
             targetDistance = r1d;
  
             // Fire more agressively when there are more enemies.
+
             setTurnRadarRight((getGunHeat() - RADAR_LOCK_THRESHOLD) * getRadarTurnRemaining());
            // With POWER_FACTOR = 2
+
             setTurnGunLeftRadians(Utils.normalRelativeAngle(getGunHeadingRadians() - r3d));
            // 6-9 enemies: setFire(3)
 
            // 4-5 enemies: setFire(2)
 
            // 2-3 enemies: setFire(1)
 
             // 1v1:        setFire(0.1)
 
            setFire(getOthers() / POWER_FACTOR);
 
  
             setTurnGunRightRadians(Utils.normalRelativeAngle(aimAngle - getGunHeadingRadians()));
+
             if (Math.abs(getGunTurnRemainingRadians()) < (AIM_TOLERANCE / r1d)) {
 +
                setFire(Math.min(getEnergy() / ENERGY_FACTOR, BULLET_POWER));
 +
            }
 
         }
 
         }
 
     }
 
     }
  
    // Factoring out the code for wall forces saves 8 bytes
+
     public static double calcWallForce(double r0d) {
     public static double calcWallForce(double d) {
+
         return (WALL_FORCE / r0d) - (WALL_FORCE / (BATTLEFIELD_SIZE - r0d));
        return (WALL_FORCE / d) - (WALL_FORCE / (1000 - d));
 
    }
 
 
 
    // Use this version of calcWallForce to remove the assumption that the battlefield is 1000x1000
 
    // This would cost us 6 bytes
 
    /*
 
    public static double calcWallForce(double d, double len) {
 
         return (WALL_FORCE / d) - (WALL_FORCE / (len - d));
 
 
     }
 
     }
    */
 
 
}
 
}
 
</syntaxhighlight>
 
</syntaxhighlight>

Latest revision as of 03:28, 30 May 2024

The following code is functionally equivalent to Quantum/Source (Assembly) but when compiled with OpenJDK 17 it will be 265 bytes.

package d414.nano;

import robocode.*;
import robocode.util.Utils;

import java.awt.Color;

public class Quantum extends AdvancedRobot {
    // ---------------------------------------------------------------------------------------------
    // Tuning Knobs
    // ---------------------------------------------------------------------------------------------
    static final double WALL_FORCE = 1.0;
    static final double AGRAV_DECAY = 0.9;
    static final double AHEAD_AMOUNT = 120.0;

    static final double AIM_START = 10.0;
    static final double AIM_FACTOR = 1.008;
    static final double AIM_TOLERANCE = 18.0;
    static final double BULLET_POWER = 2.49999;
    static final double ENERGY_FACTOR = 7.0;
    static final double RADAR_LOCK_THRESHOLD = 1.0;

    // ---------------------------------------------------------------------------------------------
    // Constants
    // ---------------------------------------------------------------------------------------------
    static final double BATTLEFIELD_SIZE = 1000.0;

    // ---------------------------------------------------------------------------------------------
    // Globals
    // ---------------------------------------------------------------------------------------------
    static String targetName;
    static double targetDistance;
    static double xForce;
    static double yForce;

    @Override
    public void run() {
        //setAllColors(Color.cyan);
        setTurnRadarRight(targetDistance = Double.POSITIVE_INFINITY);
    }

    @Override
    public void onRobotDeath(RobotDeathEvent r1e) {
        targetDistance = Double.POSITIVE_INFINITY;
    }

    @Override
    public void onScannedRobot(ScannedRobotEvent r1e) {
        double r1d;
        double r3d;

        setAdjustGunForRobotTurn(true);
        setTurnLeftRadians(Utils.normalRelativeAngle(
                    (r3d = getHeadingRadians())
                    - Math.atan2(
                        (xForce = xForce * AGRAV_DECAY
                         - Math.sin(r3d = (r3d += r1e.getBearingRadians())
                             + (Math.sin(r1e.getHeadingRadians() - r3d)
                                 * r1e.getVelocity()
                                 / (AIM_START + Math.pow(AIM_FACTOR, r1d = r1e.getDistance()))
                               )
                             ) / r1d
                        )
                        + calcWallForce(getX())
                        , 
                        (yForce = yForce * AGRAV_DECAY - Math.cos(r3d) / r1d)
                        + calcWallForce(getY())
                        )
                    ));
        setBack(Math.abs(getTurnRemaining()) - AHEAD_AMOUNT);

        if (r1e.getName() == targetName || r1d < targetDistance) {
            targetName = r1e.getName();
            targetDistance = r1d;

            setTurnRadarRight((getGunHeat() - RADAR_LOCK_THRESHOLD) * getRadarTurnRemaining());
            setTurnGunLeftRadians(Utils.normalRelativeAngle(getGunHeadingRadians() - r3d));

            if (Math.abs(getGunTurnRemainingRadians()) < (AIM_TOLERANCE / r1d)) {
                setFire(Math.min(getEnergy() / ENERGY_FACTOR, BULLET_POWER));
            }
        }
    }

    public static double calcWallForce(double r0d) {
        return (WALL_FORCE / r0d) - (WALL_FORCE / (BATTLEFIELD_SIZE - r0d));
    }
}