public class ConfigurationSpace { /* This class represents the configuration space. More precisely, it represents a set of functions that can be used to dynamically represent the configuration space as needed. In our project, we use a configuration space that changes over time, and to some extent changes unpredictably over time. This class allows us to generate not the entire configuration space, because this cannot be known, but a small window of the configuration space--a sequence of predicted snapshots of the field and goal in the immediate future. Within this window we grow an RRT tree to determine a path towards the goal that avoids (hopefully) the asteroids. */ protected final static int MAX_PATH_LENGTH = 16, MAX_TREE_SIZE = 60; protected final static double BIAS = 0.14; // probability that we extend towards the goal protected double[] thrust, changeInDirection; protected int pathLength; // length of the path left to follow public ConfigurationSpace() // allocate memory for the configuration space { thrust = new double[MAX_PATH_LENGTH]; changeInDirection = new double[MAX_PATH_LENGTH]; pathLength = 0; } // constructor public void generatePath(SpaceShip pursuer, SpaceShip goal, AsteroidField field) { /* This function generates a list of commands that, when followed, lead the pursuer ship along a path to the goal. We do this with our own special type of RRT. */ SpaceShip target; TreeNode node, child, root = new TreeNode(); root.ship = pursuer; // predict the future positions of the asteroid field AsteroidField [] fieldFrame = new AsteroidField [MAX_PATH_LENGTH]; fieldFrame[0] = field; for (int i = 1; i 0; node = node.previous) { changeInDirection[node.depth-1] = node.changeInDirection; thrust[node.depth-1] = node.thrust; } } // generatePath() public void followPath(SpaceShip pursuer) { // moves a space ship along a path, according to a list of commands previously generated if (pathLength > 0) { // the pursuer ship gets exact control over rotation and thrust pursuer.rotate(pursuer.center, changeInDirection[MAX_PATH_LENGTH - pathLength]); pursuer.rotation += changeInDirection[MAX_PATH_LENGTH - pathLength]; pursuer.fireThrusters(thrust[MAX_PATH_LENGTH - pathLength]); pathLength--; } } // followPath() public boolean pathNearlyCompleted() { // Returns true if we have followed most of the commands in the path. // It is a good idea to never follow a path to completion since an asteroid field can change. return pathLength < 5; } }