mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-25 22:56:45 +01:00
Add random collection
This commit is contained in:
parent
533edc5f40
commit
6cea26f436
@ -3,6 +3,7 @@ package com.github.intellectualsites.plotsquared.plot.object;
|
||||
import com.github.intellectualsites.plotsquared.configuration.serialization.ConfigurationSerializable;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
||||
import com.github.intellectualsites.plotsquared.plot.config.Configuration;
|
||||
import com.github.intellectualsites.plotsquared.plot.object.collection.RandomCollection;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
@ -20,12 +21,15 @@ import java.util.Map.Entry;
|
||||
implements Iterable<PlotBlock>, ConfigurationSerializable {
|
||||
|
||||
private final Random random = new Random();
|
||||
private final Map<Range, PlotBlock> ranges = new HashMap<>();
|
||||
private final Map<PlotBlock, Integer> blocks;
|
||||
private final Map<PlotBlock, Double> blocks;
|
||||
|
||||
private final BucketIterator bucketIterator = new BucketIterator();
|
||||
private boolean compiled, singleItem;
|
||||
private PlotBlock head;
|
||||
|
||||
private RandomCollection<PlotBlock> randomBlocks;
|
||||
private PlotBlock single;
|
||||
|
||||
public BlockBucket() {
|
||||
this.blocks = new HashMap<>();
|
||||
}
|
||||
@ -48,6 +52,11 @@ import java.util.Map.Entry;
|
||||
}
|
||||
|
||||
public void addBlock(@NonNull final PlotBlock block, final int chance) {
|
||||
addBlock(block, (double) chance);
|
||||
}
|
||||
|
||||
private void addBlock(@NonNull final PlotBlock block, double chance) {
|
||||
if (chance == -1) chance = 1;
|
||||
this.blocks.put(block, chance);
|
||||
this.compiled = false;
|
||||
if (head == null) {
|
||||
@ -56,9 +65,6 @@ import java.util.Map.Entry;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
if (isCompiled()) {
|
||||
return ranges.isEmpty();
|
||||
}
|
||||
return blocks.isEmpty();
|
||||
}
|
||||
|
||||
@ -72,7 +78,7 @@ import java.util.Map.Entry;
|
||||
if (!isCompiled()) {
|
||||
this.compile();
|
||||
}
|
||||
return Collections.unmodifiableCollection(this.ranges.values());
|
||||
return Collections.unmodifiableCollection(this.blocks.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,80 +118,21 @@ import java.util.Map.Entry;
|
||||
return;
|
||||
}
|
||||
|
||||
if (blocks.size() == 0) {
|
||||
this.compiled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (blocks.size() == 1) {
|
||||
this.ranges.put(new Range(0, 100, true), blocks.keySet().toArray(new PlotBlock[1])[0]);
|
||||
this.compiled = true;
|
||||
this.singleItem = true;
|
||||
return;
|
||||
}
|
||||
|
||||
final Map<PlotBlock, Integer> temp = new HashMap<>(blocks.size());
|
||||
final List<PlotBlock> unassigned = new ArrayList<>(blocks.size());
|
||||
|
||||
int sum = 0;
|
||||
for (final Map.Entry<PlotBlock, Integer> entry : blocks.entrySet()) {
|
||||
if (entry.getValue() == -1) {
|
||||
unassigned.add(entry.getKey());
|
||||
} else {
|
||||
sum += entry.getValue();
|
||||
temp.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
//
|
||||
// If this doesn't amount to 100 add it up to exactly 100.
|
||||
//
|
||||
if (sum < 100) {
|
||||
final int remaining = 100 - sum;
|
||||
if (unassigned.isEmpty()) {
|
||||
// If there are no unassigned values, we just add it to the first value
|
||||
final Entry<PlotBlock, Integer> entry = temp.entrySet().iterator().next();
|
||||
temp.put(entry.getKey(), (entry.getValue() + 1 + remaining));
|
||||
} else {
|
||||
final int perUnassigned = remaining / unassigned.size();
|
||||
for (final PlotBlock block : unassigned) {
|
||||
temp.put(block, perUnassigned);
|
||||
sum += perUnassigned;
|
||||
}
|
||||
// Make sure there isn't a tiny difference remaining
|
||||
if (sum < 100) {
|
||||
final int difference = 100 - sum;
|
||||
temp.put(unassigned.get(0), perUnassigned + difference);
|
||||
sum = 100;
|
||||
}
|
||||
}
|
||||
} else if (!unassigned.isEmpty()) {
|
||||
Captions.BUCKET_ENTRIES_IGNORED.send(ConsolePlayer.getConsole());
|
||||
}
|
||||
//
|
||||
// If the sum adds up to more than 100, divide all values
|
||||
//
|
||||
if (sum > 100) {
|
||||
final double ratio = 100D / sum;
|
||||
for (final Map.Entry<PlotBlock, Integer> entry : blocks.entrySet()) {
|
||||
if (entry.getValue() == -1) {
|
||||
continue;
|
||||
}
|
||||
temp.put(entry.getKey(), (int) (entry.getValue() * ratio));
|
||||
}
|
||||
} else {
|
||||
temp.forEach(temp::put);
|
||||
}
|
||||
int start = 0;
|
||||
for (final Map.Entry<PlotBlock, Integer> entry : temp.entrySet()) {
|
||||
final int rangeStart = start;
|
||||
final int rangeEnd = rangeStart + entry.getValue();
|
||||
start = rangeEnd + 1;
|
||||
final Range range =
|
||||
new Range(rangeStart, rangeEnd, unassigned.contains(entry.getKey()));
|
||||
this.ranges.put(range, entry.getKey());
|
||||
}
|
||||
this.blocks.clear();
|
||||
this.compiled = true;
|
||||
switch (blocks.size()) {
|
||||
case 0:
|
||||
single = null;
|
||||
this.randomBlocks = null;
|
||||
break;
|
||||
case 1:
|
||||
single = blocks.keySet().iterator().next();
|
||||
this.randomBlocks = null;
|
||||
break;
|
||||
default:
|
||||
single = null;
|
||||
this.randomBlocks = RandomCollection.of(blocks, random);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Iterator<PlotBlock> iterator() {
|
||||
@ -205,19 +152,13 @@ import java.util.Map.Entry;
|
||||
if (!isCompiled()) {
|
||||
this.compile();
|
||||
}
|
||||
if (this.isEmpty()) {
|
||||
return StringPlotBlock.EVERYTHING;
|
||||
} else if (this.hasSingleItem()) {
|
||||
return this.head;
|
||||
if (single != null) {
|
||||
return single;
|
||||
}
|
||||
final int number = random.nextInt(101);
|
||||
for (final Map.Entry<Range, PlotBlock> entry : ranges.entrySet()) {
|
||||
if (entry.getKey().isInRange(number)) {
|
||||
return entry.getValue();
|
||||
}
|
||||
if (randomBlocks != null) {
|
||||
return randomBlocks.next();
|
||||
}
|
||||
// Didn't find a block? Try again
|
||||
return getBlock();
|
||||
return StringPlotBlock.EVERYTHING;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
@ -225,14 +166,16 @@ import java.util.Map.Entry;
|
||||
compile();
|
||||
}
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
final Iterator<Entry<Range, PlotBlock>> iterator = this.ranges.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
final Entry<Range, PlotBlock> entry = iterator.next();
|
||||
builder.append(entry.getValue().getRawId());
|
||||
if (!entry.getKey().isAutomatic()) {
|
||||
builder.append(":").append(entry.getKey().getWeight());
|
||||
Iterator<Entry<PlotBlock, Double>> iter = blocks.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<PlotBlock, Double> entry = iter.next();
|
||||
PlotBlock block = entry.getKey();
|
||||
builder.append(block.getRawId());
|
||||
Double weight = entry.getValue();
|
||||
if (weight != 1) {
|
||||
builder.append(":").append(weight.intValue());
|
||||
}
|
||||
if (iterator.hasNext()) {
|
||||
if (iter.hasNext()) {
|
||||
builder.append(",");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package com.github.intellectualsites.plotsquared.plot.object.collection;
|
||||
|
||||
import com.github.intellectualsites.plotsquared.plot.util.MathMan;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
public class FlatRandomCollection<T> extends RandomCollection<T> {
|
||||
private T[] values;
|
||||
|
||||
public FlatRandomCollection(Map<T, Double> weights, Random random) {
|
||||
super(weights, random);
|
||||
int max = 0;
|
||||
int[] counts = new int[weights.size()];
|
||||
Double[] weightDoubles = weights.values().toArray(new Double[weights.size()]);
|
||||
for (int i = 0; i < weightDoubles.length; i++) {
|
||||
int weight = (int) (weightDoubles[i] * 100);
|
||||
counts[i] = weight;
|
||||
if (weight != (weightDoubles[i] * 100)) {
|
||||
throw new IllegalArgumentException("Too small");
|
||||
}
|
||||
if (weight > max) {
|
||||
max = weight;
|
||||
}
|
||||
}
|
||||
int gcd = MathMan.gcd(counts);
|
||||
if (max / gcd > 100000) {
|
||||
throw new IllegalArgumentException("Too large");
|
||||
}
|
||||
ArrayList<T> parsed = new ArrayList<>();
|
||||
for (Map.Entry<T, Double> entry : weights.entrySet()) {
|
||||
int num = (int) (100 * entry.getValue());
|
||||
for (int j = 0; j < num / gcd; j++) {
|
||||
parsed.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
this.values = (T[]) parsed.toArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T next() {
|
||||
return values[random.nextInt(values.length)];
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.github.intellectualsites.plotsquared.plot.object.collection;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public abstract class RandomCollection<T> {
|
||||
protected Random random;
|
||||
|
||||
public RandomCollection(Map<T, Double> weights, Random random) {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
public static <T> RandomCollection<T> of(Map<T, Double> weights, Random random) {
|
||||
try {
|
||||
return new FlatRandomCollection<>(weights, random);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
return new SimpleRandomCollection<>(weights, random);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRandom(Random random) {
|
||||
checkNotNull(random);
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
public Random getRandom() {
|
||||
return random;
|
||||
}
|
||||
|
||||
public abstract T next();
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.github.intellectualsites.plotsquared.plot.object.collection;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class SimpleRandomCollection<E> extends RandomCollection<E> {
|
||||
|
||||
private final NavigableMap<Double, E> map = new TreeMap<>();
|
||||
private double total = 0;
|
||||
|
||||
public SimpleRandomCollection(Map<E, Double> weights, Random random) {
|
||||
super(weights, random);
|
||||
for (Map.Entry<E, Double> entry : weights.entrySet()) {
|
||||
add(entry.getValue(), entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
public void add(double weight, E result) {
|
||||
if (weight <= 0) return;
|
||||
total += weight;
|
||||
map.put(total, result);
|
||||
}
|
||||
|
||||
public E next() {
|
||||
return map.ceilingEntry(random.nextDouble()).getValue();
|
||||
}
|
||||
}
|
@ -37,6 +37,21 @@ public class MathMan {
|
||||
}
|
||||
}
|
||||
|
||||
public static final int gcd(int a, int b) {
|
||||
if (b == 0) {
|
||||
return a;
|
||||
}
|
||||
return gcd(b, a % b);
|
||||
}
|
||||
|
||||
public static final int gcd(int[] a) {
|
||||
int result = a[0];
|
||||
for (int i = 1; i < a.length; i++) {
|
||||
result = gcd(result, a[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long pairInt(int x, int y) {
|
||||
return (((long) x) << 32) | (y & 0xffffffffL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user