SurfMover { double checkDanger(RobotState myRobotState, MoveEnemy duelEnemy, RobotState startState, SurfOption surfOption, boolean previouslyMovingClockwise, int surfWaveIndex, int numWavesToSurf, double cutoffDanger, RobotStateLog predictedStateLog) { Wave surfWave = duelEnemy.findSurfableWave(surfWaveIndex, myRobotState); if (surfWave == null) { return 0; } List<RobotState> dangerStates = new ArrayList<RobotState>(); WavePosition startWavePosition = surfWave.checkWavePosition(startState); if (surfWaveIndex > Wave.FIRST_WAVE && startWavePosition != WavePosition.MIDAIR) { dangerStates.addAll( replaySurfStates(surfWave, predictedStateLog, startState)); } if (startWavePosition == WavePosition.GONE && dangerStates.isEmpty()) { return 0; } boolean predictClockwise = predictClockwise(surfOption, previouslyMovingClockwise); RobotState predictedState = startState; RobotState passedState = startState; boolean wavePassed = false; boolean waveHit = false; double maxVelocity; SurfOption smoothingSurfOption; if (surfOption == SurfOption.STOP) { maxVelocity = 0; smoothingSurfOption = predictClockwise ? SurfOption.CLOCKWISE : SurfOption.COUNTER_CLOCKWISE; } else { maxVelocity = 8; smoothingSurfOption = surfOption; } Point2D.Double surfDestination; if (surfWaveIndex == Wave.FIRST_WAVE && surfOption == SurfOption.STOP && _stopDestination != null) { surfDestination = _stopDestination; } else { surfDestination = surfDestination( surfWave, surfWaveIndex, startState, smoothingSurfOption); } if (surfWaveIndex == Wave.FIRST_WAVE) { _surfOptionDestinations.put(surfOption, surfDestination); } do { if (!waveHit && surfWave.checkWavePosition( predictedState, WavePosition.BREAKING_FRONT) == WavePosition.BREAKING_FRONT) { RobotState dangerState = predictedState; do { dangerStates.add(dangerState); dangerState = predictSurfLocation( dangerState, surfDestination, 0, smoothingSurfOption); } while ( surfWave.checkWavePosition(dangerState, true) != WavePosition.GONE); waveHit = true; } WavePosition wavePosition = surfWave.checkWavePosition(predictedState, true); if (wavePosition == WavePosition.BREAKING_CENTER || wavePosition == WavePosition.GONE) { passedState = predictedState; wavePassed = true; } else { predictedStateLog.addState(predictedState); predictedState = predictSurfLocation( predictedState, surfDestination, maxVelocity, smoothingSurfOption); } } while (!wavePassed); Wave.Intersection intersection = surfWave.preciseIntersection(dangerStates); double baseDangerScore = normalizedEnemyHitRate(duelEnemy) * BASE_DANGER_FACTOR; double danger = baseDangerScore + getDangerScore( duelEnemy, surfWave, intersection, surfWaveIndex); danger *= surfWave.shadowFactor(intersection); danger *= Rules.getBulletDamage(surfWave.bulletPower()); double currentDistanceToWaveSource = myRobotState.location.distance(surfWave.sourceLocation); double currentDistanceToWave = currentDistanceToWaveSource - surfWave.distanceTraveled(_robot.getTime()); double timeToImpact = Math.max(1, currentDistanceToWave / surfWave.bulletSpeed()); danger /= timeToImpact; danger *= distancingDanger(startState.location, passedState.location, duelEnemy.lastScanState.location); if (surfWaveIndex + 1 < numWavesToSurf && danger < cutoffDanger) { double nextCounterClockwiseDanger = checkDanger(myRobotState, duelEnemy, passedState, SurfOption.COUNTER_CLOCKWISE, predictClockwise, surfWaveIndex + 1, numWavesToSurf, cutoffDanger, (RobotStateLog) predictedStateLog.clone()); double nextStopDanger = checkDanger(myRobotState, duelEnemy, passedState, SurfOption.STOP, predictClockwise, surfWaveIndex + 1, numWavesToSurf, cutoffDanger, (RobotStateLog) predictedStateLog.clone()); double nextClockwiseDanger = checkDanger(myRobotState, duelEnemy, passedState, SurfOption.CLOCKWISE, predictClockwise, surfWaveIndex + 1, numWavesToSurf, cutoffDanger, (RobotStateLog) predictedStateLog.clone()); danger += Math.min(nextCounterClockwiseDanger, Math.min(nextStopDanger, nextClockwiseDanger)); } return danger; } 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 testCheckDangerBulletHit() { SurfMover mover = newSurfMover(); MoveEnemy duelEnemy = newDuelEnemy(); setupHitWave(duelEnemy); Bullet hitBullet = _eventHelper.newBullet( Math.PI / 8, 559.8, 476.02, 3.0, "Shadow", "Diamond", true, 22); duelEnemy.processBullet(hitBullet, 1, 68L, false); setupSurfWave(duelEnemy); RobotState startState = RobotState.newBuilder() .setLocation(newLocation(410, 500)) .setHeading(Math.PI / 2) .setVelocity(8.0) .setTime(210L) .build(); when(diamond.getTime()).thenReturn(210L); double clockwiseDanger = mover.checkDanger(newRobotState(400, 500), duelEnemy, startState, SurfOption.CLOCKWISE, true, Wave.FIRST_WAVE, 1, Double.POSITIVE_INFINITY, new RobotStateLog()); double counterDanger = mover.checkDanger(newRobotState(400, 500), duelEnemy, startState, SurfOption.COUNTER_CLOCKWISE, true, Wave.FIRST_WAVE, 1, Double.POSITIVE_INFINITY, new RobotStateLog()); assertTrue(clockwiseDanger > counterDanger * 10); }
@Test public void testCheckDangerFlattenerVisit() { SurfMover mover = newSurfMover(); MoveEnemy duelEnemy = newDuelEnemy(); setupHitWave(duelEnemy); duelEnemy.execute1v1(1, 61L, newLocation(550, 500)); duelEnemy.execute1v1(1, 67L, newLocation(600, 500)); duelEnemy.execute1v1(1, 85L, newLocation(700, 480)); duelEnemy.execute1v1(1, 185L, newLocation(500, 520)); setupSurfWave(duelEnemy); RobotState startState = RobotState.newBuilder() .setLocation(newLocation(410, 500)) .setHeading(Math.PI / 2) .setVelocity(8.0) .setTime(210L) .build(); when(diamond.getTime()).thenReturn(210L); double clockwiseDanger = mover.checkDanger(newRobotState(400, 500), duelEnemy, startState, SurfOption.CLOCKWISE, true, Wave.FIRST_WAVE, 1, Double.POSITIVE_INFINITY, new RobotStateLog()); double counterDanger = mover.checkDanger(newRobotState(400, 500), duelEnemy, startState, SurfOption.COUNTER_CLOCKWISE, true, Wave.FIRST_WAVE, 1, Double.POSITIVE_INFINITY, new RobotStateLog()); assertTrue(clockwiseDanger > counterDanger * 10); }