Форум 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=156420)

Lyso 21.05.2011 13:39

Процентый шанс ответа.
 
Как сделать систему шансов. Например у меня есть 10 чисел. При нажатии на кнопку выбирается одно из чисел. Если оно выбралось, оно будет выпадать чаще других. То есть шанса выпада этого числа повысится.
Я думал делать так:
Создать массив с вариантами (1,2,3,4,5,6,7,8,9,0)
Создать массив с шансами (10,10,10,10,10,10,10,10,10,10)

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

Подскажите как такое можно осуществить?

Добавлено через 2 минуты
И как вообще осуществить процентный шанс? Как сделать при увеличении одного параметра ,равномерное сниженое других, но учитывая, что все равно в общем должно выходить 100%..?

i.o. 21.05.2011 14:33

после выбора, добавить это число в исходный массив еще раз (или несколько раз). Теперь, в исходном массивет его будет 2 (или более), когда остальных по-прежнему останется по-одному. Шансы получить выбранное число повысятся.

Lyso 21.05.2011 14:42

Спасибо, попробую.

Добавлено через 6 минут
Получилось. Спасибо, оказалось проще, чем думал.

Добавлено через 4 часа 45 минут
Мне требуется другое решение. Так как иногда некоторые варианты могут отпадать. Например в процессе отключить цифру 5. А как сделать при вашем коде? Делать цикл по удалению всех полей с 5? Но тогда будет значение null, а это мне не подходит.

NAO111 21.05.2011 20:14

так удаляйте со смешением, чтобы не было пустых null

mikhailk 21.05.2011 21:35

http://help.adobe.com/ru_RU/AS3LCR/F...l#splice%28%29

Crazy 21.05.2011 23:20

Цитата:

Сообщение от i.o. (Сообщение 997675)
после выбора, добавить это число в исходный массив еще раз (или несколько раз). Теперь, в исходном массивет его будет 2 (или более), когда остальных по-прежнему останется по-одному. Шансы получить выбранное число повысятся.


В общем случае проще оставить числа как есть, но добавить веса. Изначально вес каждого равен 1. Ели число выбрано -- его вес увеличиваем (до 2, 10, 1000 -- как нужно).

Далее формируем случайное число, причем в качестве диапазона берем сумму всех весов. Как потом найти выпавшее число, полагаю, достаточно очевидно.

Цитата:

Например в процессе отключить цифру 5.
Поставить ей вес 0.

GBee 22.05.2011 00:31

Цитата:

Как потом найти выпавшее число, полагаю, достаточно очевидно.
Я не понял, если честно? Поясните как? Пока вариант ИО элегантней :о))

ShadowsInRain 22.05.2011 00:49

Алгоритм древний и проверенный, но непосредственно АС3-класс написан на коленке (NP++) за 5 минут (в АС3 не использовал ибо), так что, возможно, придётся внести фикссы, чтобы компилировалось. Без оптимизации работает не самым быстрым способом. Помимо того, возможно накопление ошибок при сложении чисел с плавающей точкой. При таком раскладе первая зарегистрированная грань будет выпадать гипотетически чаще. Чтобы этого избежать, шансы граней должны быть одного или близких порядков. Грубо говоря, самый маленький шанс и самый большой не должны отличаться более чем на три-четыре порядка. Но в большинстве задач можно забить на эту ошибку, она реально ничтожна.

Код AS3:

package
{
        public class VirtualDice // виртуальная кость (ваш К.О.)
        {
                protected var _chances:Vector.<Number> = new Vector.<Number>; // стороны кости
                protected var _faces:Vector.<Number> = new Vector.<Number>; // абсолютные шансы для каждой стороны
                protected var _range:Number = 0; // кеш суммы всех шансов, используется при кидании кости
 
                public function getFaceChance(face:Number):Number // текущий вес для грани кости
                {
                        var index:uint = _faces.lastIndexOf(face); // найти грань в наборе
                        return (index == -1) ? 0 : _chances[index]; // вернуть шанс найденной грани, либо нуль, если не найдена
                }
 
                public function setFaceChance(face:Number, chance:Number = 1):void // установить вес грани
                {
                        if(chance < 0) // отрицательные шансы невозможны
                                chance = 0; // особо дотошные пишут throw new Error("Dice face chance negative value assigned");
 
                        var index:uint = _faces.lastIndexOf(face); // найти грань в наборе
 
                        if (index == -1) // а нету такой грани в наборе, придётся добавить
                        {
                                if(chance == 0) // её и так нет, нет смысла ставить нулевой шанс
                                        return;
 
                                _faces.push(face);
                                _chances.push(chance);
                                index = _faces.lenght - 1;
                        }
                        else
                        if(chance == 0) // грань с занулённым шансом удалим для экономии памяти
                        {
                                _faces.splice(index,1);
                                _chances.splice(index,1);
                        }
 
                        _range = 0; // нужно обновить кеш
                        for each (var intermediate:Number in _chances)
                                result += intermediate;
                }
 
                public function roll():Number
                {
                        if(!_faces.lenght) // опа, граней то нету!
                                rhrow new Error("Rolling dice without faces"); // сферическая кость в ваккууме никогда бы не остановилась
 
                        var fortune_charge:Number = _range * Math.random; // Holy Random is True God and only
                        var lucker:Number = _faces.lenght - 1;
 
                        while(lucker)
                        {
                                fortune_charge -= _chances[lucker];
 
                                if(fortune_charge <= 0.0001)
                                        break;
 
                                lucker--;
                        }
 
                        return _faces[lucker];
                }
        }
}

Если нужно работать только с целочисленными гранями, достаточно заменить только тип для _face и faces.
Так же легко работать и с целочисленными шансами, но я не думаю, что это удобно.

mikhailk 22.05.2011 00:51

Цитата:

Я не понял, если честно? Поясните как? Пока вариант ИО элегантней :о))
Вариант с весами используется в общем виде достаточно часто.
Например, у нас есть три значения с весами 5, 3 и 2.
Получаем случайное число в промежутке 0-1, далее:
- если до 0.5 - выпало первое значение
- больше 0.5 и меньше 0.8 - второе
- больше 0.8 - третье

wvxvw 22.05.2011 00:58

Собственно, решил сделать эксперимент интереса ради :)
Код AS3:

package tests 
{
        import flash.display.Sprite;
 
        /**
        * ...
        * @author wvxvw
        */

        public class ProbablityTester extends Sprite
        {
                private const _variants:Vector.<uint> =
                        new <uint>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
 
                private const _weights:Vector.<uint> =
                        new <uint>[1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
 
                public function ProbablityTester()
                {
                        super();
                        // position: 0 total: 99435
                        // position: 1 total: 100361
                        // position: 2 total: 99991
                        // position: 3 total: 99921
                        // position: 4 total: 99452
                        // position: 5 total: 100059
                        // position: 6 total: 100715
                        // position: 7 total: 100259
                        // position: 8 total: 99848
                        // position: 9 total: 99959
                        this.testDistribution();
                        // exclude 5 from the pool completely
                        this.setChance(5, 0);
                        // position: 0 total: 111148
                        // position: 1 total: 111645
                        // position: 2 total: 111153
                        // position: 3 total: 111161
                        // position: 4 total: 111147
                        // position: 5 total: 0
                        // position: 6 total: 111019
                        // position: 7 total: 110609
                        // position: 8 total: 110869
                        // position: 9 total: 111249
                        this.testDistribution();
                        // double the chances for 6
                        this.setChance(6, 2);
                        // position: 0 total: 100195
                        // position: 1 total: 99949
                        // position: 2 total: 99909
                        // position: 3 total: 99673
                        // position: 4 total: 100513
                        // position: 5 total: 0
                        // position: 6 total: 200260
                        // position: 7 total: 99795
                        // position: 8 total: 99600
                        // position: 9 total: 100106
                        this.testDistribution();
                }
 
                public function setChance(of:uint, to:uint):void
                {
                        of = of % 10;
                        this._weights[of] = to;
                }
 
                private function testDistribution():void
                {
                        var results:Vector.<uint> = new Vector.<uint>(10);
                        var i:int;
 
                        for (i = 0; i < 1e6; i++)
                        {
                                results[this.selectRandom()]++;
                        }
                        for (i = 0; i < 10; i++)
                        {
                                trace("position:", i, "total:", results[i]);
                        }
                }
 
                private function selectRandom():uint
                {
                        var result:uint;
                        var weight:uint;
                        var random:uint = this.sum() * Math.random();
 
                        for (var i:int; i < 10; i++)
                        {
                                weight = this._weights[i];
                                if (random < weight)
                                {
                                        result = i;
                                        break;
                                }
                                else random -= weight;
                        }
                        return result;
                }
 
                private function sum():uint
                {
                        var result:uint;
                        for each (var i:uint in this._weights) result += i;
                        return result;
                }
        }
}

EDIT: перемудрил в первый раз


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

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