SurfMover { List<RobotState> replaySurfStates(final Wave surfWave, RobotStateLog predictedStateLog, RobotState startState) { final List<RobotState> dangerStates = new ArrayList<RobotState>(); predictedStateLog.forAllStates(new AllStateListener() { @Override public void onRobotState(RobotState state) { WavePosition pastWavePosition = surfWave.checkWavePosition(state); if (pastWavePosition.isBreaking()) { dangerStates.add(state); } } }); return dangerStates; } SurfMover(AdvancedRobot robot, BattleField battleField,
      Collection<RoboGraphic> renderables, OutputStream out); void initRound(); void move(RobotState myRobotState, MoveEnemy duelEnemy,
      int wavesToSurf, boolean painting); void roundOver(MoveEnemy duelEnemy);  }
@Test public void testReplaySurfStates() { SurfMover mover = newSurfMover(); MoveEnemy duelEnemy = newDuelEnemy(); Point2D.Double sourceLocation = newLocation(150, 300); Point2D.Double targetLocation = newLocation(600, 359); Wave surfWave = duelEnemy.newMoveWave(sourceLocation, targetLocation, DiaUtils.absoluteBearing(sourceLocation, targetLocation), 1, 100L, 2.0, 100.0, 0, -8.0, -1, 0, 60, 150, 220, 15L, 5L); RobotState startState = RobotState.newBuilder() .setLocation(newLocation(580, 200)) .setHeading(Math.PI * .03) .setVelocity(-8) .setTime(140L) .build(); RobotStateLog stateLog = new RobotStateLog(); for (long time = 139L; time > 126L; time--) { RobotState oldState = RobotState.newBuilder() .setLocation(DiaUtils.project(startState.location, startState.heading + Math.PI, -startState.velocity * (140L - time))) .setHeading(startState.heading) .setVelocity(startState.velocity) .setTime(time) .build(); stateLog.addState(oldState); } List<RobotState> dangerStates = mover.replaySurfStates(surfWave, stateLog, startState); assertFalse(dangerStates.isEmpty()); assertTrue(dangerStates.size() <= 4); }