Last active
October 10, 2017 12:10
-
-
Save bnorm/f27a288148877c7b79347dd731266bb6 to your computer and use it in GitHub Desktop.
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
import java.util.LinkedHashMap; | |
import java.util.LinkedList; | |
import java.util.Map; | |
import org.apache.commons.math3.geometry.euclidean.twod.Line; | |
import org.apache.commons.math3.geometry.euclidean.twod.Vector2D; | |
import com.ibm.coderally.agent.CRSFileLog; | |
import com.ibm.coderally.agent.DefaultCarAIAgent; | |
import com.ibm.coderally.api.agent.AIUtils; | |
import com.ibm.coderally.entity.cars.agent.Car; | |
import com.ibm.coderally.entity.cars.agent.RaceCarAgentAI; | |
import com.ibm.coderally.entity.obstacle.agent.Obstacle; | |
import com.ibm.coderally.geo.agent.CheckPoint; | |
import com.ibm.coderally.geo.agent.Point; | |
import com.ibm.coderally.geo.agent.Vector; | |
import com.ibm.coderally.track.agent.Track; | |
public class Tron extends DefaultCarAIAgent { | |
public static class TrackLane { | |
final CheckPoint checkPoint; | |
final Line checkLine; | |
final Point startLimit; | |
final Point endLimit; | |
TrackLane prev; | |
TrackLane next; | |
Point target; | |
Vector2D vec2d; | |
double angle; | |
public TrackLane(CheckPoint checkPoint) { | |
this.checkPoint = checkPoint; | |
this.checkLine = new Line(new Vector2D(checkPoint.getStart().getX(), checkPoint.getStart().getY()), | |
new Vector2D(checkPoint.getEnd().getX(), checkPoint.getEnd().getY())); | |
Point start = checkPoint.getStart(); | |
Point end = checkPoint.getEnd(); | |
double factor = 0.85; | |
this.startLimit = new Point((1 - factor) * end.getX() + factor * start.getX(), | |
(1 - factor) * end.getY() + factor * start.getY()); | |
this.endLimit = new Point(factor * end.getX() + (1 - factor) * start.getX(), | |
factor * end.getY() + (1 - factor) * start.getY()); | |
this.target = checkPoint.getCenter(); | |
this.vec2d = new Vector2D(target.getX(), target.getY()); | |
} | |
public void target(Point target) { | |
this.target = target; | |
this.vec2d = new Vector2D(target.getX(), target.getY()); | |
} | |
public void smooth() { | |
Vector2D intersection = new Line(prev.vec2d, next.vec2d).intersection(checkLine); | |
Point newTarget = calcTarget(intersection, this, 2.0 - angle); | |
Vector enter = vector(intersection, prev.target); | |
Line enterLine = getLine(vec2d, enter); | |
Vector2D enterIntersection = enterLine.intersection(prev.checkLine); | |
Point enterTarget = calcTarget(enterIntersection, prev, 4.0 - 2 * angle); | |
prev.target(enterTarget); | |
Vector exit = vector(intersection, next.target); | |
Line exitLine = getLine(vec2d, exit); | |
Vector2D exitIntersection = exitLine.intersection(next.checkLine); | |
Point exitTarget = calcTarget(exitIntersection, next, 4.7 - 2 * angle); | |
next.target(exitTarget); | |
target(newTarget); | |
} | |
public Line getLine(Vector2D intersection, Vector vector) { | |
return new Line(vec2d, | |
new Vector2D(intersection.getX() + vector.getX(), intersection.getY() + vector.getY())); | |
} | |
public void calc() { | |
Vector enter = vector(prev.target, target); | |
Vector exit = vector(target, next.target); | |
this.angle = enter.angleBetween(exit); | |
} | |
} | |
public static Point calcTarget(Vector2D intersection, TrackLane trackLane, double factor) { | |
double x = ((factor - 1) * trackLane.target.getX() + intersection.getX()) / factor; | |
double y = ((factor - 1) * trackLane.target.getY() + intersection.getY()) / factor; | |
Point target = new Point(limit(trackLane.startLimit.getIntX(), x, trackLane.endLimit.getIntX()), | |
limit(trackLane.startLimit.getIntY(), y, trackLane.endLimit.getIntY())); | |
return target; | |
} | |
private static double limit(double min, double v, double max) { | |
if (min < max) { | |
return Math.max(min, Math.min(v, max)); | |
} else { | |
return Math.max(max, Math.min(v, min)); | |
} | |
} | |
public static Vector vector(Point start, Point end) { | |
return new Vector(end.getX() - start.getX(), end.getY() - start.getY()); | |
} | |
public static Vector vector(Vector2D start, Point end) { | |
return new Vector(end.getX() - start.getX(), end.getY() - start.getY()); | |
} | |
private Car car; | |
private Track track; | |
private LinkedList<TrackLane> lanes; | |
private Map<CheckPoint, TrackLane> checkPointLanes; | |
@Override | |
public void init(Car car, Track track) { | |
this.car = car; | |
this.track = track; | |
this.lanes = new LinkedList<>(); | |
this.checkPointLanes = new LinkedHashMap<>(); | |
// create backward link | |
for (CheckPoint checkPoint : this.track.getCheckpoints()) { | |
TrackLane previous = lanes.peekLast(); | |
TrackLane next = new TrackLane(checkPoint); | |
if (previous != null) { | |
next.prev = previous; | |
} | |
lanes.add(next); | |
} | |
lanes.getFirst().prev = lanes.getLast(); | |
// create forward link | |
for (TrackLane lane : lanes) { | |
lane.prev.next = lane; | |
} | |
lanes.getLast().next = lanes.getFirst(); | |
// init angles | |
for (TrackLane lane : lanes) { | |
lane.calc(); | |
} | |
// smooth x times | |
for (int i = 0; i < 25; i++) { | |
for (TrackLane lane : lanes) { | |
lane.smooth(); | |
} | |
} | |
// map checkpoints to lanes | |
for (TrackLane lane : lanes) { | |
checkPointLanes.put(lane.checkPoint, lane); | |
} | |
} | |
@Override | |
public void onRaceStart() { | |
car.setBrakePercent(0); | |
car.setAccelerationPercent(100); | |
car.setTarget(checkPointLanes.get(car.getCheckpoint()).next.target); | |
} | |
@Override | |
public void onTimeStep() { | |
Point target = car.getTarget(); | |
//Predicts how far the car can turn in 1 second | |
double turn = Math.abs(car.calculateHeading(target)); | |
double degreesPerSecond = car.getAttributes().getTurningDegrees(); | |
//Predicts how many seconds to reach the checkpoint | |
double distance = car.getPosition().getDistance(target); | |
double predictedVelocity = Math.pow(Math.sqrt(AIUtils.magnitude(car.getVelocity())) + Math.sqrt(AIUtils.magnitude(car.getAcceleration())), 2.4F) / 7; | |
double seconds = distance / (predictedVelocity * 5280 / 3600); | |
//Predicts how many degrees the car can turn in the time to reach the checkpoint | |
double predictedTurn = degreesPerSecond * seconds; | |
if (predictedTurn * 11 < turn) { | |
car.setBrakePercent(100); | |
car.setAccelerationPercent(0); | |
} else if (predictedTurn * 9.5 < turn) { | |
car.setBrakePercent(80); | |
car.setAccelerationPercent(0); | |
} else if (predictedTurn * 8 < turn) { | |
car.setBrakePercent(60); | |
} else if (predictedTurn * 6.5 < turn) { | |
car.setBrakePercent(40); | |
car.setAccelerationPercent(0); | |
} else if (predictedTurn * 5 < turn) { | |
car.setBrakePercent(20); | |
car.setAccelerationPercent(0); | |
} else if (predictedTurn * 4 < turn) { | |
car.setAccelerationPercent(35); | |
car.setBrakePercent(0); | |
} else if (predictedTurn * 3 < turn) { | |
car.setAccelerationPercent(60); | |
car.setBrakePercent(0); | |
} else if (predictedTurn * 2 < turn) { | |
car.setAccelerationPercent(80); | |
car.setBrakePercent(0); | |
} else { | |
car.setAccelerationPercent(100); | |
car.setBrakePercent(0); | |
} | |
} | |
@Override | |
public void onCheckpointUpdated(CheckPoint oldCheckpoint) { | |
car.setBrakePercent(0); | |
car.setAccelerationPercent(100); | |
car.setTarget(checkPointLanes.get(car.getCheckpoint()).target); | |
} | |
@Override | |
public void onCarCollision(Car other) { | |
} | |
@Override | |
public void onObstacleInProximity(Obstacle obstacle) { | |
} | |
@Override | |
public void onOffTrack() { | |
} | |
@Override | |
public void onOpponentInProximity(Car car) { | |
} | |
@Override | |
public void onObstacleCollision(Obstacle obstacle) { | |
} | |
@Override | |
public void onStalled() { | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment