1 /**
2 *   Copyright: © 2012-2014 Anton Gushcha
3 *   License: Subject to the terms of the MIT license, as written in the included LICENSE file.
4 *   Authors:  NCrashed <ncrashed@gmail.com>,
5 *             LeMarwin <lemarwin42@gmail.com>,
6 *             Nazgull09 <nazgull90@gmail.com>
7 */
8 module devol.std.random;
9 
10 import std.array;
11 import std.algorithm;
12 import std.random;
13 import std.stdio;
14 import std.math;
15 import std.conv;
16 
17 /// Вызов одной из функций с определенным шансом
18 /**
19  * Вызывает один из переданных делегатов в зависимости от распределения 
20  * вероятностей.
21  * @note Сумма вероятностей должна быть равна единице!
22  * @param range массив вероятностей выбора итого делегата
23  * @param funcs перечисление делегатов
24  */
25 void randomRange(T...)(double[] range, T funcs)
26 in
27 {
28 	double summ = 0;
29 	foreach( val; range )
30 	{
31 		summ += val;
32 	}
33 	assert(abs(summ-1) <= 0.001, text("Сумма вероятностей должна быть равна 1! А не ", summ));
34 	assert(range.length == funcs.length, "Размерности массивов вероятностей и делегатов не совпадают!");
35 }
36 body
37 {
38 	double chance = uniform!"[]"(0.,1.);
39 	double begin = 0, end = 0;
40 	
41 	foreach(int i, f; funcs )
42 	{
43 		end += range[i];
44 		
45 		if (  begin < chance && chance <= end )
46 		{
47 			return f();
48 		}
49 		begin = end;
50 	}
51 }
52 
53 /// Выбор одного из варианта по набору вероятностей
54 /**
55  * Вызывает функцию и передает ей номер выбранной вероятности.
56  * @note Сумма вероятностей должна быть равна единице!
57  * @param range массив вероятностей
58  * @param funcs перечисление делегатов
59  */
60 void randomRange(alias T)(double[] range)
61 	if(__traits(compiles, "T(0);"))
62 in
63 {
64 	double summ = 0;
65 	foreach( val; range )
66 	{
67 		summ += val;
68 	}
69 	assert(abs(summ-1) <= 0.001, text("Сумма вероятностей должна быть равна 1! А не ", summ));
70 }
71 body
72 {
73 	double chance = uniform!"[]"(0.,1.);
74 	double begin = 0, end = 0;
75 	
76 	foreach(int i, val; range )
77 	{
78 		end += val;
79 		
80 		if (begin < chance && chance <= end )
81 		{
82 			return T(i);
83 		}
84 		begin = end;
85 	}
86 }
87 
88 
89 /// Статистический тест randomRange
90 unittest
91 {
92 	int count = 500000;
93 	double a = 0;
94 	double b = 0;
95 	
96 	foreach(i; 1..count)
97 	{
98 		randomRange([0.5, 0.5],
99 			{
100 				a++;
101 			},
102 			{
103 				b++;
104 			}
105 		); 
106 	}
107 	a = a/count;
108 	b = b/count;
109 	assert(abs(a-0.5) <= 0.01, text("randomRange не прошла статистический тест da = ", abs(a-0.5)));
110 	assert(abs(b-0.5) <= 0.01, text("randomRange не прошла статистический тест db = ", abs(b-0.5)));
111 }