-
-
Save Chase-san/7edb0974df656bec12d8 to your computer and use it in GitHub Desktop.
It's a Bullet Shield
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package cs; | |
import java.awt.Color; | |
import java.awt.geom.Line2D; | |
import java.awt.geom.Point2D; | |
import java.util.ArrayDeque; | |
import robocode.AdvancedRobot; | |
import robocode.BulletHitEvent; | |
import robocode.HitByBulletEvent; | |
import robocode.Rules; | |
import robocode.ScannedRobotEvent; | |
import robocode.util.Utils; | |
public class BasicBulletShielder extends AdvancedRobot { | |
public void run() { | |
setAdjustGunForRobotTurn(true); | |
setAdjustRadarForGunTurn(true); | |
setAllColors(Color.WHITE); | |
/* Setup Radar */ | |
turnRadarRightRadians(Double.POSITIVE_INFINITY); | |
while(true) scan(); | |
} | |
ArrayDeque<Double> pastAngles = new ArrayDeque<Double>(); | |
static final double BULLET_START_POWER = 0.15; | |
Point2D lastPosition = null; | |
double lastEnemyEnergy = 100; | |
double lastMoveDistance = 0; | |
double aimAngle = 0; | |
double firePower = BULLET_START_POWER; | |
long fireOnTick = 0; | |
public void onScannedRobot(ScannedRobotEvent e) { | |
double angleToEnemy = getHeadingRadians() + e.getBearingRadians(); | |
Point2D enemyPosition = project(getPosition(),angleToEnemy,e.getDistance()); | |
pastAngles.addFirst(angleToEnemy); | |
if(pastAngles.size() > 3) | |
pastAngles.removeLast(); | |
long time = getTime(); | |
/* Radar */ | |
setTurnRadarRightRadians(1.9*Utils.normalRelativeAngle(angleToEnemy - getRadarHeadingRadians())); | |
double enemyEnergy = e.getEnergy(); | |
double deltaEnergy = lastEnemyEnergy - enemyEnergy; | |
lastEnemyEnergy = enemyEnergy; | |
if(deltaEnergy > 0 && deltaEnergy <= 3) { | |
double bulletAngle = pastAngles.getLast() + Math.PI; | |
double bulletSpeed = Rules.getBulletSpeed(deltaEnergy); | |
//how much time till the next time they can fire? | |
int minTimeTillNextFire = (int)(Rules.getGunHeat(deltaEnergy)/getGunCoolingRate()); | |
//we have to move there and back, so divide the time we have in half | |
int maxTestDistance = getMaxMoveDistanceForTime(minTimeTillNextFire/2); | |
double bestDeviation = Double.POSITIVE_INFINITY; | |
double myBulletSpeed = Rules.getBulletSpeed(BULLET_START_POWER); | |
for(int move = -maxTestDistance; move <= maxTestDistance; ++move) { | |
//calculate where we will be when we finish moving | |
Point2D myFirePosition = getMoveEnd(move); | |
//determine how long it will take to get there | |
long timeToMove = TIME_TO_MOVE[Math.abs(move)]; | |
//out.println(timeToMove); | |
//the bullet position at the time time we start | |
Point2D bulletStart = project(lastPosition,bulletAngle,bulletSpeed*(timeToMove+1)); | |
//calculate our target position | |
Point2D target = intercept(myFirePosition,myBulletSpeed,bulletStart,bulletAngle,bulletSpeed); | |
double eGoalTime = Math.ceil(bulletStart.distance(target) / bulletSpeed); | |
//Update our target | |
target = project(bulletStart, bulletAngle, (eGoalTime-0.5)*bulletSpeed); | |
double myGunAim = angleFromTo(myFirePosition,target); | |
//determine if they intersect | |
Line2D eLine = new Line2D.Double( | |
project(bulletStart,bulletAngle,bulletSpeed*(eGoalTime-1)), | |
project(bulletStart,bulletAngle,bulletSpeed*eGoalTime) | |
); | |
double myTargetTime = myFirePosition.distance(target) / myBulletSpeed; | |
double myGoalTime = Math.ceil(myTargetTime); | |
Line2D myLine = new Line2D.Double( | |
project(myFirePosition,myGunAim,myBulletSpeed*(myGoalTime-1)), | |
project(myFirePosition,myGunAim,myBulletSpeed*myGoalTime) | |
); | |
if(myLine.intersectsLine(eLine)) { | |
double dB = myTargetTime - (myGoalTime - 0.5); | |
double deviation = dB*dB; | |
if(deviation < bestDeviation) { | |
bestDeviation = deviation; | |
lastMoveDistance = move; | |
fireOnTick = time + timeToMove; | |
//tweak our power so that ours is more centered as well | |
double goalSpeed = myFirePosition.distance(target) / (myGoalTime-0.5); | |
firePower = (20-goalSpeed)/3; | |
aimAngle = myGunAim; | |
setTurnRightRadians(0); | |
setAhead(lastMoveDistance); | |
} | |
} | |
} /* for(int move ... */ | |
} /* if(deltaEnergy ... */ | |
if(time == fireOnTick) { | |
setFire(firePower); | |
} | |
if(time == fireOnTick + 1) { | |
setAhead(-lastMoveDistance); | |
} | |
if(time > fireOnTick && getDistanceRemaining() == 0) { | |
aimAngle = angleToEnemy; | |
setTurnRightRadians(Utils.normalRelativeAngle(angleToEnemy + Math.PI/2.0 - Math.PI/4.0 - getHeadingRadians())); | |
} | |
setTurnGunRightRadians(Utils.normalRelativeAngle(aimAngle - getGunHeadingRadians())); | |
lastPosition = enemyPosition; | |
} | |
public void onBulletHit(final BulletHitEvent e) { | |
lastEnemyEnergy -= Rules.getBulletDamage(e.getBullet().getPower()); | |
} | |
public void onHitByBullet(final HitByBulletEvent e) { | |
lastEnemyEnergy += Rules.getBulletHitBonus(e.getPower()); | |
} | |
static final int[] TIME_TO_MOVE = new int[] {0,1,2,2,3,3,4,4,4}; | |
static final int[] MAX_MOVE_DIST = new int[] {0,1,3,5,8}; | |
public int getMaxMoveDistanceForTime(int time) { | |
if(time >= MAX_MOVE_DIST.length) | |
return MAX_MOVE_DIST[MAX_MOVE_DIST.length-1]; | |
return MAX_MOVE_DIST[time]; | |
} | |
public Point2D getMoveEnd(double distance) { | |
return project(getPosition(),getHeadingRadians(),distance); | |
} | |
public Point2D getPosition() { | |
return new Point2D.Double(getX(),getY()); | |
} | |
public Point2D project(Point2D start, double angle, double length) { | |
return new Point2D.Double( | |
start.getX() + Math.sin(angle) * length, | |
start.getY() + Math.cos(angle) * length | |
); | |
} | |
public Point2D intercept(Point2D pos, double vel, Point2D tPos, double tHeading, double tVel) { | |
double tVelX = Math.sin(tHeading)*tVel; | |
double tVelY = Math.cos(tHeading)*tVel; | |
double relX = tPos.getX() - pos.getX(); | |
double relY = tPos.getY() - pos.getY(); | |
double b = relX * tVelX + relY * tVelY; | |
double a = vel * vel - tVel * tVel; | |
b = (b + Math.sqrt(b * b + a * (relX * relX + relY * relY))) / a; | |
return new Point2D.Double(tVelX*b+tPos.getX(),tVelY*b+tPos.getY()); | |
} | |
public double angleFromTo(Point2D a, Point2D b) { | |
return Math.atan2(b.getX() - a.getX(), b.getY() - a.getY()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment