- Хроники
- Prelude
- Исходники
- Присутствуют
- Сборка
- любая
Простой базовый класс для создания шансовых списков, элементы из которого можно получить соответственно их шансу, заданному при добавлении элемента в этот список.
За основу была взята идея из класса RndSelector в овере.
Работа с классом проще некуда - объявляем список с нужным типом элементов, заполняем его и после чего можем выбирать из него случайные элементы соответственно их шансам.
Подходит для любой сборки - максимум что придется по необходимости поправить - это импорт для класса Rnd (можно вообще без него обойтись, если задействовать какой нибудь стандартный класс получения рандомных значений).
В данной реализации достигается точность шанса до 6 знаков после запятой. Если необходимо увеличить/уменьшить точность, то необходимо поправить значение переменной MAX_CHANCE и значение SCALE для scaleByPowerOfTen в методе add(E value, String chance)
Пример использования
За основу была взята идея из класса RndSelector в овере.
Работа с классом проще некуда - объявляем список с нужным типом элементов, заполняем его и после чего можем выбирать из него случайные элементы соответственно их шансам.
Подходит для любой сборки - максимум что придется по необходимости поправить - это импорт для класса Rnd (можно вообще без него обойтись, если задействовать какой нибудь стандартный класс получения рандомных значений).
В данной реализации достигается точность шанса до 6 знаков после запятой. Если необходимо увеличить/уменьшить точность, то необходимо поправить значение переменной MAX_CHANCE и значение SCALE для scaleByPowerOfTen в методе add(E value, String chance)
Java:
package l2p.commons.collections.chance;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.math.BigDecimal;
import l2p.commons.util.Rnd;
/**
* @author Gaikotsu
*/
public class ChanceList<E> implements Iterable<E>
{
public static final int MAX_CHANCE = 100_000_000; // Значение, эквивалентное шансу в 100%
public static final int PER_FACTOR = MAX_CHANCE / 100; // Значение, эквивалентное шансу в 1%
public static final int SCALE = 6; // На 10 в какой степени умножать значение шанса в варианте с получением его из строки через тип BigDecimal
private final List<ChanceNode<E>> _nodes;
private int _totalChance = 0;
/**
* Создает пустой список с размером начального списка элементов по умолчанию
*/
public ChanceList()
{
_nodes = new ArrayList<>();
}
/**
* Создает пустой список с заданным начальным размером списка элементов
*
* @param capacity - размер
*/
public ChanceList(int capacity)
{
_nodes = new ArrayList<>(capacity);
}
/**
* Добавляет новый элемент в список с заданным шансом
*
* @param value - добавляемый элемент
* @param chance - шанс получения этого элемента
*/
public boolean add(E value, int chance)
{
if (value == null || chance <= 0)
return false;
_totalChance += chance;
return _nodes.add(new ChanceNode<>(value, chance));
}
/**
* Добавляет новый элемент в список с заданным шансом
*
* @param value - добавляемый элемент
* @param chance - шанс получения этого элемента в процентах
*/
public boolean add(E value, double chance)
{
return add(value, (int) (chance * PER_FACTOR));
}
/**
* Добавляет новый элемент в список с заданным шансом
*
* @param value - добавляемый элемент
* @param chance - шанс получения этого элемента в процентах
*/
public boolean add(E value, String chance)
{
return add(value, new BigDecimal(chance).scaleByPowerOfTen(SCALE).intValue());
}
/**
* Удаляет заданный элемент из списка
*
* @param value - удаляемый элемент
*/
public boolean remove(E value)
{
if (_nodes.removeIf(node -> node.getValue().equals(value)))
{
calcTotalChance();
return true;
}
return true;
}
/**
* Возвращает элемент из списка по его индексу
*/
public E get(int index)
{
return index >= 0 && index < _nodes.size() ? _nodes.get(index).getValue() : null;
}
/**
* Возвращает случайный элемент из списка (вероятность получения зависит от его шанса)
*/
public E get()
{
int chance = Rnd.get(1, _totalChance);
int current = 0;
for (ChanceNode<E> node : _nodes)
{
current += node.getChance();
if (current >= chance)
return node.getValue();
}
return null;
}
/**
* Возвращает все элементы из списка
*/
public List<E> getAll()
{
return _nodes.stream().map(node -> node.getValue()).collect(Collectors.toUnmodifiableList());
}
/**
* Возвращает суммарный шанс всех элементов из списка
*/
public int getTotalChance()
{
return _totalChance;
}
/**
* Подсчитывает суммарный шанс всех элементов в списке
*/
public void calcTotalChance()
{
_totalChance = _nodes.stream().mapToInt(node -> node.getChance()).sum();
}
/**
* Возвращает суммарный шанс всех элементов из списка в виде процента
*/
public double getCurrentChance()
{
return _totalChance / (double) PER_FACTOR;
}
/**
* Проверяет, равен ли суммарный шанс значению, эквивалентному шансу в 100%
*/
public boolean isValid()
{
return _totalChance == MAX_CHANCE;
}
public boolean isEmpty()
{
return _nodes.isEmpty();
}
public int size()
{
return _nodes.size();
}
public void clear()
{
_totalChance = 0;
_nodes.clear();
}
@Override
public Iterator<E> iterator()
{
return getAll().iterator();
}
}
Java:
package l2p.commons.collections.chance;
public class ChanceNode<T>
{
private final T _value;
private final int _chance;
public ChanceNode(T value, int chance)
{
_value = value;
_chance = chance;
}
public T getValue()
{
return _value;
}
public int getChance()
{
return _chance;
}
}
Пример использования
Java:
ChanceList<Integer> chances = new ChanceList<>(); // создаем список с элементами типа Integer
chances.add(1, 1_000_000); // добавляем значение 1 с шансом 1% (1000000 = 1%)
chances.add(2, 49.0); // добавляем значение 2 с шансом 49%
chances.add(3, "50.0"); // добавляем значение 3 с шансом 50%
int value = chances.get(); // получаем случайное значение из списка
Последнее редактирование: