mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2024-11-22 21:26: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.configuration.serialization.ConfigurationSerializable;
|
||||||
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
import com.github.intellectualsites.plotsquared.plot.config.Captions;
|
||||||
import com.github.intellectualsites.plotsquared.plot.config.Configuration;
|
import com.github.intellectualsites.plotsquared.plot.config.Configuration;
|
||||||
|
import com.github.intellectualsites.plotsquared.plot.object.collection.RandomCollection;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
@ -20,12 +21,15 @@ import java.util.Map.Entry;
|
|||||||
implements Iterable<PlotBlock>, ConfigurationSerializable {
|
implements Iterable<PlotBlock>, ConfigurationSerializable {
|
||||||
|
|
||||||
private final Random random = new Random();
|
private final Random random = new Random();
|
||||||
private final Map<Range, PlotBlock> ranges = new HashMap<>();
|
private final Map<PlotBlock, Double> blocks;
|
||||||
private final Map<PlotBlock, Integer> blocks;
|
|
||||||
private final BucketIterator bucketIterator = new BucketIterator();
|
private final BucketIterator bucketIterator = new BucketIterator();
|
||||||
private boolean compiled, singleItem;
|
private boolean compiled, singleItem;
|
||||||
private PlotBlock head;
|
private PlotBlock head;
|
||||||
|
|
||||||
|
private RandomCollection<PlotBlock> randomBlocks;
|
||||||
|
private PlotBlock single;
|
||||||
|
|
||||||
public BlockBucket() {
|
public BlockBucket() {
|
||||||
this.blocks = new HashMap<>();
|
this.blocks = new HashMap<>();
|
||||||
}
|
}
|
||||||
@ -48,6 +52,11 @@ import java.util.Map.Entry;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addBlock(@NonNull final PlotBlock block, final int chance) {
|
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.blocks.put(block, chance);
|
||||||
this.compiled = false;
|
this.compiled = false;
|
||||||
if (head == null) {
|
if (head == null) {
|
||||||
@ -56,9 +65,6 @@ import java.util.Map.Entry;
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
if (isCompiled()) {
|
|
||||||
return ranges.isEmpty();
|
|
||||||
}
|
|
||||||
return blocks.isEmpty();
|
return blocks.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +78,7 @@ import java.util.Map.Entry;
|
|||||||
if (!isCompiled()) {
|
if (!isCompiled()) {
|
||||||
this.compile();
|
this.compile();
|
||||||
}
|
}
|
||||||
return Collections.unmodifiableCollection(this.ranges.values());
|
return Collections.unmodifiableCollection(this.blocks.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,80 +118,21 @@ import java.util.Map.Entry;
|
|||||||
return;
|
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;
|
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() {
|
@Override public Iterator<PlotBlock> iterator() {
|
||||||
@ -205,19 +152,13 @@ import java.util.Map.Entry;
|
|||||||
if (!isCompiled()) {
|
if (!isCompiled()) {
|
||||||
this.compile();
|
this.compile();
|
||||||
}
|
}
|
||||||
if (this.isEmpty()) {
|
if (single != null) {
|
||||||
return StringPlotBlock.EVERYTHING;
|
return single;
|
||||||
} else if (this.hasSingleItem()) {
|
|
||||||
return this.head;
|
|
||||||
}
|
}
|
||||||
final int number = random.nextInt(101);
|
if (randomBlocks != null) {
|
||||||
for (final Map.Entry<Range, PlotBlock> entry : ranges.entrySet()) {
|
return randomBlocks.next();
|
||||||
if (entry.getKey().isInRange(number)) {
|
|
||||||
return entry.getValue();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Didn't find a block? Try again
|
return StringPlotBlock.EVERYTHING;
|
||||||
return getBlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
@ -225,14 +166,16 @@ import java.util.Map.Entry;
|
|||||||
compile();
|
compile();
|
||||||
}
|
}
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
final Iterator<Entry<Range, PlotBlock>> iterator = this.ranges.entrySet().iterator();
|
Iterator<Entry<PlotBlock, Double>> iter = blocks.entrySet().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
final Entry<Range, PlotBlock> entry = iterator.next();
|
Entry<PlotBlock, Double> entry = iter.next();
|
||||||
builder.append(entry.getValue().getRawId());
|
PlotBlock block = entry.getKey();
|
||||||
if (!entry.getKey().isAutomatic()) {
|
builder.append(block.getRawId());
|
||||||
builder.append(":").append(entry.getKey().getWeight());
|
Double weight = entry.getValue();
|
||||||
|
if (weight != 1) {
|
||||||
|
builder.append(":").append(weight.intValue());
|
||||||
}
|
}
|
||||||
if (iterator.hasNext()) {
|
if (iter.hasNext()) {
|
||||||
builder.append(",");
|
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) {
|
public static long pairInt(int x, int y) {
|
||||||
return (((long) x) << 32) | (y & 0xffffffffL);
|
return (((long) x) << 32) | (y & 0xffffffffL);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user