Darkcanuck/VelocityTest

From Robowiki
< Darkcanuck
Revision as of 07:31, 15 July 2009 by Darkcanuck (talk | contribs) (uses right version now...)
Jump to navigation Jump to search

Some basic code to test 1.7.1.3's updated getNewVelocity() method.

The main class:

import robocode.Rules;


public class VelocityTest {
    
    private static Commands currentCommands = new Commands();
    
    public static void main(String[] args) {
        
        // init
        System.out.println("\nDarkcanuck's VelocityTest\n");
        
        if (!args[0].equals("all")) {
            testCase(Double.valueOf(args[0]), Double.valueOf(args[1]));
        } else {
            testCase(0, 6);
        }
    }
    
    public static void testCase(double velocity, double distance) {
        double newvel  = velocity;
        double newdist = distance;
        int tick = 0;
        
        System.out.println("Starting velocity=" + velocity + " distance=" + distance);
        while ((Math.abs(newvel)>0.00001) || (Math.abs(newdist)>0.00001)) {
            newvel = getNewVelocity(newvel, newdist);
            newdist -= newvel;
            tick++;
            System.out.println("  " + tick + " velocity=" + newvel + " remain=" + newdist);
        }
        System.out.println("\n");
    }
    
    
	private static double getNewVelocity(double velocity, double distance) {
		// If the distance is negative, then change it to be positive and change the sign of the input velocity and the result
		if (distance < 0) {
			return -getNewVelocity(-velocity, -distance);
		}

		double newVelocity;

		// Get the speed, which is always positive (because it is a scalar)
		final double speed = Math.abs(velocity); 

		// Check if we are decelerating, i.e. if the velocity is negative.
		// Note that if the speed is too high due to a new max. velocity, we must also decelerate.
		if (velocity < 0 || speed > currentCommands.getMaxVelocity()) {
			// If the velocity is negative, we are decelerating
			newVelocity = speed - Rules.DECELERATION;

			// Check if we are going from deceleration into acceleration
			if (newVelocity < 0) {
				// If we have decelerated to velocity = 0, then the remaining time must be used for acceleration
				double decelTime = speed / Rules.DECELERATION;
				double accelTime = (1 - decelTime);

				// New velocity (v) = d / t, where time = 1 (i.e. 1 turn). Hence, v = d / 1 => v = d
				// However, the new velocity must be limited by the max. velocity
				newVelocity = Math.min(currentCommands.getMaxVelocity(),
						Math.min(Rules.DECELERATION * decelTime * decelTime + Rules.ACCELERATION * accelTime * accelTime,
						distance));

				// Note: We change the sign here due to the sign check later when returning the result
				velocity *= -1;
			}
		} else {
			// Else, we are not decelerating, but might need to start doing so due to the remaining distance

			// Deceleration time (t) is calculated by: v = a * t => t = v / a
			final double decelTime = speed / Rules.DECELERATION;

			// Deceleration time (d) is calculated by: d = 1/2 a * t^2 + v0 * t + t
			// Adding the extra 't' (in the end) is special for Robocode, and v0 is the starting velocity = 0
			final double decelDist = 0.5 * Rules.DECELERATION * decelTime * decelTime + decelTime;

			// Check if we should start decelerating
			if (distance <= decelDist) {
				// If the distance < max. deceleration distance, we must decelerate so we hit a distance = 0

				// Calculate time left for deceleration to distance = 0
				double time = distance / (decelTime + 1); // 1 is added here due to the extra 't' for Robocode

				// New velocity (v) = a * t, i.e. deceleration * time, but not greater than the current speed

				if (time <= 1) {
					// When there is only one turn left (t <= 1), we set the speed to match the remaining distance
					newVelocity = Math.max(speed - Rules.DECELERATION, distance);
				} else {
					// New velocity (v) = a * t, i.e. deceleration * time
					newVelocity = time * Rules.DECELERATION;

					if (speed < newVelocity) {
						// If the speed is less that the new velocity we just calculated, then use the old speed instead
						newVelocity = speed;
					} else if (speed - newVelocity > Rules.DECELERATION) {
						// The deceleration must not exceed the max. deceleration.
						// Hence, we limit the velocity to the speed minus the max. deceleration.
						newVelocity = speed - Rules.DECELERATION;
					}
				}
			} else {
				// Else, we need to accelerate, but only to max. velocity
				newVelocity = Math.min(speed + Rules.ACCELERATION, currentCommands.getMaxVelocity());
			}
		}

		// Return the new velocity with the correct sign. We have been working with the speed, which is always positive
		return (velocity < 0) ? -newVelocity : newVelocity;
	}    
}

And a support class for setting the max velocity:

import robocode.Rules;

public class Commands {
    private static double maxVelocity = Rules.MAX_VELOCITY;

    public static double getMaxVelocity() { return maxVelocity; }
    public static void setMaxVelocity(double maxVel) { maxVelocity = maxVel; }
}