|
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Вероятностный расчёт
Друзья, у меня в разработке игры пришло время добавить чуточку рандома. По этому поводу хочу вас спросить, возможно у кого-нибудь есть готовое решение, которым можно поделиться и не изобретать велосипед. Задач две. Во-первых, зная вероятность наступления события, получать значение типа "истина-ложь". Во-вторых, имея несколько событий с разной вероятностью, определить то из них, которое произойдёт.
А если ничего подобного не найдётся, то буду признателен за рекомендации, как реализовать. Пока единственный способ, который мне приходит в голову, выглядит примерно так. Если у нас есть событие, которое должно произойти с вероятностью 0.7, то мы будем генерировать псевдослучайное число в интервале от 0 до 1 и возвращать true, если оно окажется больше 0.3, т.к. (1-0.7). Примерно так же и с числами: генерировать случайные числа в диапазоне от 0 до значения вероятности каждого и выбирать событие с наибольшим значением. Корректно?
__________________
Не сломано - не чини! |
|
|||||
Регистрация: Jan 2012
Сообщений: 836
|
Цитата:
|
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Godwarlock, спасибо. Примерно то же, но лаконичнее.
Забавно, но мне почему-то казалось, что это какая-то такая сложная конструкция должна быть непременно.
__________________
Не сломано - не чини! |
|
|||||
Цитата:
Цитата:
var events:RangeArray = new RangeArray(); events.setRange(1, 10); // Событие 1, шанс 10 events.setRange(2, 50); // Событие 2, шанс 50 events.setRange(3, 80); // Событие 3, шанс 80 trace(events.getItemByRangeIndex(Math.random() * events.summ)); // Случайное событие. package volkov.collection { /** * Массив с доступов по диапазону значений. * Позволяет обращаться к элементам массива по диапазону индексов. * @author Roman A.V. */ public class RangeArray { // Приват private var _vec:Vector.<RangeArrayItem>; private var _hash:Object; private var _summ:uint; private var _length:uint; private var _updated:Boolean; /** * Создать массив. */ public function RangeArray() { _vec = new Vector.<RangeArrayItem>; _hash = new Object; } // ПАБЛИК /** * Получить элемент списка. * Возвращает элемент списка как из обычного массива, где index должен быть от 0 до length - 1. * @param index Индекс элемента в списке. * @return Возвращает элемент списка как из обычного массива, где index должен быть от 0 до length - 1. */ public function at(index:uint):uint { return _vec[index].id; } /** * Получить элемент спика по его индексу диапазона. * Возвращает элемент списка диапазон которого содержит переданный индекс или 0, если такого элемента нет в списке. * @param index Индекс диапазона от 0 до summ - 1 включительно. * @return Возвращает элемент списка диапазон которого содержит переданный индекс или 0, если такого элемента нет в списке. */ public function getItemByRangeIndex(index:uint):uint { if (_updated) update(); // Бинарный поиск. // Взято с вики и адаптировано: https://ru.wikipedia.org/wiki/%D0%94...B8%D1%81%D0%BA (C#) if (_length === 0 || index > _vec[_length - 1].lastIndex) return 0; var first:uint; var last:uint = _length; while (first < last) { var mid:uint = first + (last - first) / 2; var item:RangeArrayItem = _vec[mid]; if (index < item.firstIndex) last = mid; else if (index > item.lastIndex) first = mid + 1; else return item.id; } return _vec[last].id; } /** * Установить/добавить диапазон индексов элементу списка. * Если указанного id нет в списке - он добавляется. * Если указанный id уже имеется в списке, обновляется значение его диапазона. * Если диапазон передан как 0 - указанный id удаляется из списка. (Если есть) * @param id ID Объекта. * @param range Диапазон индексов. */ public function setRange(id:uint, range:uint):void { var item:RangeArrayItem = _hash[id]; if (range === 0) { if (item === null) return; _vec.removeAt(_vec.indexOf(item)); _length--; delete _hash[id]; } else { if (item === null) { item = new RangeArrayItem; item.id = id; item.range = range; _vec[_length++] = item; _hash[id] = item; } else { item.range = range; } } _updated = true; } /** * Очистить весь список. */ public function clear():void { _vec = new Vector.<RangeArrayItem>; _hash = new Object; _length = 0; _summ = 0; _updated = false; } // ПРИВАТ private function update():void { _updated = false; _summ = 0; var i:uint; var item:RangeArrayItem; while (i < _length) { item = _vec[i++]; item.firstIndex = _summ; item.lastIndex = _summ + item.range - 1; _summ += item.range; } } // ГЕТТЕРЫ /** * Количество элементов в списке. */ public function get length():uint { return _length; } /** * Сумма всех диапазонов. */ public function get summ():uint { if (_updated) update(); return _summ; } } } class RangeArrayItem { public var id:uint; public var range:uint; public var firstIndex:uint; public var lastIndex:uint; }
__________________
Дети не должны знать о своих родителях |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Цитата:
Хотя всё это хозяйство ещё балансировать и балансировать. С одной стороны, не хочется жёстко детерминированного поведения от NPC, а с другой, как чуть отпустишь, какой-то шаляй-валяй получается с его стороны Добавлено через 1 час 5 минут Только не больше, а меньше
__________________
Не сломано - не чини! |
|
|||||
В джаве есть random.nextInt() ты можешь сразу с ним сравнивать, зачем ты делишь на 100?
__________________
Ко мне можно и нужно обращаться на ты) |
|
|||||
Регистрация: Dec 2014
Адрес: Санкт-Петербург
Сообщений: 479
|
Реализовал вариант выбора одного из нескольких объектов, с учётом сравнительной вероятности каждого.
Вот кусочек кода (всякие проверки я оттуда повыкинул для компактности). public class ProbableOneOf { private var _objArray: Array = []; // Массив объектов, выбираемых с определённой вероятностью private var _chances: Vector.<Number> = new Vector.<Number>; // Массив сравнительных вероятностей private var _ratings: Vector.<Number> = new Vector.<Number>; // Массив рейтингов выпадания, которые будут непосредственно сравниваться друг с другом public function ProbableOneOf() {} public function addObjChancePair(obj: * , chance: Number) : void { var rating: Number = Math.random() * chance; _objArray.push (obj); _chances.push (chance); _ratings.push (rating); } public function getProbableObj() : * { while (_objArray.length > 1) { compareAndRemove(); } return _objArray[0]; } private function compareAndRemove() : void { if (_ratings[0] > _ratings[1]) { removeAtIndex(1); return; } if (_ratings[0] < _ratings[1]) { removeAtIndex(0); return; } removeAtIndex (Math.round(Math.random())); } private function removeAtIndex(index: uint) : void { _objArray.removeAt(index); _chances.removeAt(index); _ratings.removeAt(index); }
__________________
Не сломано - не чини! |
Часовой пояс GMT +4, время: 08:53. |
|
« Предыдущая тема | Следующая тема » |
Опции темы | |
Опции просмотра | |
|
|