You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
6.6 KiB

package mock.model;
import shared.model.Bearing;
import shared.model.Wind;
import java.util.Random;
/**
* This class generates Wind objects for use in a MockRace.
* Bounds on bearing and speed can be specified.
* Wind can be completely random, or random incremental change.
*/
public class RandomWindGenerator implements WindGenerator {
/**
* The bearing the wind direction starts at.
*/
private Bearing windBaselineBearing;
/**
* The lower bearing angle that the wind may have.
*/
private Bearing windBearingLowerBound;
/**
* The upper bearing angle that the wind may have.
*/
private Bearing windBearingUpperBound;
/**
* The speed the wind starts at, in knots.
*/
private double windBaselineSpeed;
/**
* The lower speed that the wind may have, in knots.
*/
private double windSpeedLowerBound;
/**
* The upper speed that the wind may have, in knots.
*/
private double windSpeedUpperBound;
/**
* Creates a wind generator, with a baseline, lower bound, and upper bound, for the wind speed and direction.
* @param windBaselineBearing Baseline wind direction.
* @param windBearingLowerBound Lower bound for wind direction.
* @param windBearingUpperBound Upper bound for wind direction.
* @param windBaselineSpeed Baseline wind speed, in knots.
* @param windSpeedLowerBound Lower bound for wind speed, in knots.
* @param windSpeedUpperBound Upper bound for wind speed, in knots.
*/
public RandomWindGenerator(Bearing windBaselineBearing, Bearing windBearingLowerBound, Bearing windBearingUpperBound, double windBaselineSpeed, double windSpeedLowerBound, double windSpeedUpperBound) {
this.windBaselineBearing = windBaselineBearing;
this.windBearingLowerBound = windBearingLowerBound;
this.windBearingUpperBound = windBearingUpperBound;
this.windBaselineSpeed = windBaselineSpeed;
this.windSpeedLowerBound = windSpeedLowerBound;
this.windSpeedUpperBound = windSpeedUpperBound;
}
@Override
public Wind generateBaselineWind() {
return new Wind(windBaselineBearing, windBaselineSpeed);
}
/**
* Generates a random Wind object, that is within the provided bounds.
* @return Generated wind object.
*/
public Wind generateRandomWind() {
double windSpeed = generateRandomWindSpeed();
Bearing windBearing = generateRandomWindBearing();
return new Wind(windBearing, windSpeed);
}
/**
* Generates a random wind speed within the specified bounds. In knots.
* @return Wind speed, in knots.
*/
private double generateRandomWindSpeed() {
double randomSpeedKnots = generateRandomValueInBounds(windSpeedLowerBound, windSpeedUpperBound);
return randomSpeedKnots;
}
/**
* Generates a random wind bearing within the specified bounds.
* @return Wind bearing.
*/
private Bearing generateRandomWindBearing() {
double randomBearingDegrees = generateRandomValueInBounds(windBearingLowerBound.degrees(), windBearingUpperBound.degrees());
return Bearing.fromDegrees(randomBearingDegrees);
}
/**
* Generates a random value within a specified interval.
* @param lowerBound The lower bound of the interval.
* @param upperBound The upper bound of the interval.
* @return A random value within the interval.
*/
private static double generateRandomValueInBounds(double lowerBound, double upperBound) {
float proportion = new Random().nextFloat();
double delta = upperBound - lowerBound;
double amount = delta * proportion;
double finalAmount = amount + lowerBound;
return finalAmount;
}
/**
* Generates a new value within an interval, given a start value, chance to change, and change amount.
* @param lowerBound Lower bound of interval.
* @param upperBound Upper bound of interval.
* @param currentValue The current value to change.
* @param changeAmount The amount to change by.
* @param chanceToChange The change to actually change the value.
* @return The new value.
*/
private static double generateNextValueInBounds(double lowerBound, double upperBound, double currentValue, double changeAmount, double chanceToChange) {
float chance = new Random().nextFloat();
if (chance <= chanceToChange) {
currentValue += changeAmount;
} else if (chance <= (2 * chanceToChange)) {
currentValue -= changeAmount;
}
currentValue = clamp(lowerBound, upperBound, currentValue);
return currentValue;
}
@Override
public Wind generateNextWind(Wind currentWind) {
double windSpeed = generateNextWindSpeed(currentWind.getWindSpeed());
Bearing windBearing = generateNextWindBearing(currentWind.getWindDirection());
return new Wind(windBearing, windSpeed);
}
/**
* Generates the next wind speed to use.
* @param windSpeed Current wind speed, in knots.
* @return Next wind speed, in knots.
*/
private double generateNextWindSpeed(double windSpeed) {
double chanceToChange = 0.2;
double changeAmount = 0.1;
double nextWindSpeed = generateNextValueInBounds(
windSpeedLowerBound,
windSpeedUpperBound,
windSpeed,
changeAmount,
chanceToChange);
return nextWindSpeed;
}
/**
* Generates the next wind speed to use.
* @param windBearing Current wind bearing.
* @return Next wind speed.
*/
private Bearing generateNextWindBearing(Bearing windBearing) {
double chanceToChange = 0.2;
double changeAmount = 0.5;
double nextWindBearingDegrees = generateNextValueInBounds(
windBearingLowerBound.degrees(),
windBearingUpperBound.degrees(),
windBearing.degrees(),
changeAmount,
chanceToChange);
return Bearing.fromDegrees(nextWindBearingDegrees);
}
/**
* Clamps a value to be within an interval.
* @param lower Lower bound of the interval.
* @param upper Upper bound of the interval.
* @param value Value to clamp.
* @return The clamped value.
*/
private static double clamp(double lower, double upper, double value) {
if (value > upper) {
value = upper;
} else if (value < lower) {
value = lower;
}
return value;
}
}