Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Вероятностный расчёт (http://www.flasher.ru/forum/showthread.php?t=215663)

Appleman 08.10.2018 10:20

Вероятностный расчёт
 
Друзья, у меня в разработке игры пришло время добавить чуточку рандома. По этому поводу хочу вас спросить, возможно у кого-нибудь есть готовое решение, которым можно поделиться и не изобретать велосипед. Задач две. Во-первых, зная вероятность наступления события, получать значение типа "истина-ложь". Во-вторых, имея несколько событий с разной вероятностью, определить то из них, которое произойдёт.

А если ничего подобного не найдётся, то буду признателен за рекомендации, как реализовать. Пока единственный способ, который мне приходит в голову, выглядит примерно так. Если у нас есть событие, которое должно произойти с вероятностью 0.7, то мы будем генерировать псевдослучайное число в интервале от 0 до 1 и возвращать true, если оно окажется больше 0.3, т.к. (1-0.7).

Примерно так же и с числами: генерировать случайные числа в диапазоне от 0 до значения вероятности каждого и выбирать событие с наибольшим значением.

Корректно?

Godwarlock 08.10.2018 23:25

Цитата:

public static Boolean getChance(float percent)
{
Boolean percent_result = Math.random()<(percent/100);

return percent_result;
}
Вот тебе расчет вероятности, но тут код Jav-ы. Думаю сможешь адаптировать по as3

Appleman 09.10.2018 09:57

Godwarlock, спасибо. Примерно то же, но лаконичнее.

Забавно, но мне почему-то казалось, что это какая-то такая сложная конструкция должна быть непременно.

Tails 09.10.2018 13:20

Цитата:

Сообщение от Appleman (Сообщение 1205976)
Зная вероятность наступления события, получать значение типа "истина-ложь".

Код AS3:

var chance:Number = 0.1; // 10%
var result:Boolean = Math.random() > chance;

Цитата:

Сообщение от Appleman (Сообщение 1205976)
Имея несколько событий с разной вероятностью, определить то из них, которое произойдёт.

Когда-то делал нечто подобное. Суть в том, чтоб сложить все id и их вероятность в список, а затем случайно выбирать их оттуда:
Код AS3:

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)); // Случайное событие.

Код AS3:

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;
}

Вроде всё прекрасно работало, но потести на всякий случай.

Appleman 09.10.2018 15:39

Цитата:

Сообщение от Tails (Сообщение 1205984)
Суть в том, чтоб сложить все id и их вероятность в список, а затем случайно выбирать их оттуда

Tails, большое спасибо. Будем посмотреть. Я как раз планировал нечто подобное для ИИ, чтобы при выборе действия на первом этапе рассчитывалась предпочтительность каждой из альтернатив, а затем формировался шорт-лист, например, топ-3. Из него будет выбираться вариант, но также с учётом вероятностей - тем более предпочтительное действие, тем больше вероятность, что оно выпадет.

Хотя всё это хозяйство ещё балансировать и балансировать. С одной стороны, не хочется жёстко детерминированного поведения от NPC, а с другой, как чуть отпустишь, какой-то шаляй-валяй получается с его стороны :)

Добавлено через 1 час 5 минут
Код AS3:

var chance:Number = 0.1; // 10%
var result:Boolean = Math.random() > chance;

Только не больше, а меньше :)

caseyryan 12.10.2018 18:53

Цитата:

Сообщение от Godwarlock (Сообщение 1205980)
Вот тебе расчет вероятности, но тут код Jav-ы. Думаю сможешь адаптировать по as3

В джаве есть random.nextInt() ты можешь сразу с ним сравнивать, зачем ты делишь на 100?

Appleman 17.10.2018 12:20

Реализовал вариант выбора одного из нескольких объектов, с учётом сравнительной вероятности каждого.
Вот кусочек кода (всякие проверки я оттуда повыкинул для компактности).

Код AS3:

        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);
                }

То есть для каждого объекта выбрасываем случайное число от 0 до полученной сравнительной вероятности и возвращаем тот, у которого данный "рейтинг" наибольший. Как считаете, корректно с т.з. математики использовать такой подход?


Часовой пояс GMT +4, время: 08:14.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.