Skip to content

Instantly share code, notes, and snippets.

@bnorm
Last active October 10, 2017 12:10
Show Gist options
  • Save bnorm/f27a288148877c7b79347dd731266bb6 to your computer and use it in GitHub Desktop.
Save bnorm/f27a288148877c7b79347dd731266bb6 to your computer and use it in GitHub Desktop.
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