Support ratio attribute for structures.

This commit is contained in:
Anton Gushcha 2015-11-02 14:32:23 +03:00
parent dec5671af3
commit 44e95ab1cc
2 changed files with 64 additions and 21 deletions

View file

@ -64,7 +64,7 @@ public class Asteroid extends Orb {
@Override
public boolean generate(World world, Random rand, int x, int y, int z) {
int randRadius = MIN_RADIUS + rand.nextInt(Math.max(1, getRadius() - MIN_RADIUS));
int numberCoreBlocks = minCoreSize + rand.nextInt(maxCoreSize - minCoreSize);
int numberCoreBlocks = minCoreSize + rand.nextInt(Math.max(1, maxCoreSize - minCoreSize));
WarpDrive.logger.info("Asteroid generation: radius=" + randRadius + ", numCoreBlocks=" + numberCoreBlocks + ", coreRad=" + coreRad);

View file

@ -147,30 +147,63 @@ public class StructureManager {
* @param <E>
*/
private static class RandomCollection<E extends XmlRepresentable> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private final NavigableMap<Double, E> weightMap = new TreeMap<Double, E>();
private double totalWeight = 0;
private final NavigableMap<Double, E> ratioMap = new TreeMap<Double, E>();
private double totalRatio = 0;
private final ArrayList<E> list = new ArrayList<E>();
private double total = 0;
/**
* Add new object and its weight.
* @param weight Used for random pick. The higher the value is relatively to others, the higher odds of choosing the object.
* @param obj Object to add
*/
public void add(double weight, E obj) {
if (weight <= 0) return;
total += weight;
map.put(total, obj);
if (weight <= 0) {
WarpDrive.logger.warn("Structure weight is negative or zero, skipping");
return;
}
totalWeight += weight;
weightMap.put(totalWeight, obj);
list.add(obj);
}
/**
* Add new object and its ratio.
* Warning: if total ratio goes higher than 1.0, element won't be added to collection.
* @param ratio Chance of random pick in range (0, 1.0]. In contrast to weights, ratio is fixed and chances don't change if you add more elements.
* @param obj Object to add
*/
public void addRatio(double ratio, E obj) {
if (ratio <= 0 || ratio >= 1.0) {
WarpDrive.logger.warn("Structure ratio isn't in (0, 1.0] bounds, skipping");
return;
}
if (totalRatio + ratio > 1.0) {
WarpDrive.logger.warn("Structures total ratio is greater than 1.0, skipping");
return;
}
totalRatio += ratio;
ratioMap.put(totalRatio, obj);
list.add(obj);
}
/**
* Pick random object according their weights
* @param random
* @return Random object
* @return Random object or null if there is no objects to pick.
*/
public E next(Random random) {
double value = random.nextDouble() * total;
return map.ceilingEntry(value).getValue();
double value = random.nextDouble();
if (value < totalRatio) { // hit ratio part of values
return ratioMap.ceilingEntry(value).getValue();
} else { // hit dynamic part of values, weighted ones
double weight = (value - totalRatio)*totalWeight;
return weightMap.ceilingEntry(weight).getValue();
}
}
/**
@ -189,17 +222,27 @@ public class StructureManager {
public void loadFromXML(E obj, Element struct) throws InvalidXmlException {
obj.loadFromXmlElement(struct);
try {
int weight = 1;
String weightStr = struct.getAttribute("weight");
if(!weightStr.isEmpty()) {
weight = Integer.parseInt(struct.getAttribute("weight"));
weight = Math.max(1, weight);
}
this.add(weight, obj);
} catch (NumberFormatException gdbg) {
throw new InvalidXmlException("Weight must be int!");
try {
String ratioStr = struct.getAttribute("ratio");
if(!ratioStr.isEmpty()) {
double ratio = Double.parseDouble(ratioStr);
this.addRatio(ratio, obj);
} else { // try weight
try {
int weight = 1;
String weightStr = struct.getAttribute("weight");
if(!weightStr.isEmpty()) {
weight = Integer.parseInt(weightStr);
weight = Math.max(1, weight);
}
this.add(weight, obj);
} catch (NumberFormatException gdbg) {
throw new InvalidXmlException("Weight must be int!");
}
}
} catch (NumberFormatException gdbg) {
throw new InvalidXmlException("Ratio must be double!");
}
}
}