Ключевые слова: генератор, случайный, чисел, число, алгоритм, random, randomize, распределение, равномерное, лотерея
insider:
Вот не думал, что в 1С пригодится, а вот на Вам.. клиенты решили акцию провести, типа "собери крышечки", только собирать нужно слова, кто правильное слово из своего набора букв соберет - тот и выиграл. Задача вообщем казалось бы простая: имеется алфавит, имеется некое слово, которое нужно собрать, например "коньяк", в нем 6 букв, как видите.
Нужно: сгенерить некоторое кол-во случайных шестибуквенных сочетаний из любых букв алфвита, к этому примешать некоторые кол-во вариантов, при которых слово все-таки можно сложить, например "ньккоя" - слово складывается, а "кавпры" - явно не подходит.
Дополнительное условие: все эти варианты (правильные и нет) нужно пронумеровать, чтобы при получении "призовой" карточки можно было бы сверить номер (а был ли такой).
Казалось бы, причем здесь 1С? Так вот учет этих карточек и призов желают добавить в учетную прогу, ну и заодно попросили нагенерить случайных комбинаций (ну не вручную же их сочинять).
Для каждой акции комбинации генерятся один раз, потом по ним изготавливают карточки, т.е. в следующий раз слово будет другое и т.д.
В общем задача сводится к следующему:
1. Генерить случайные числа, желательно с большим разбросом.
2. По числу вычислять комбинацию букв (т.е. найти какое-то соответствие между возможныи комбинациями и их номерами).
3. Пункт обратный предыдущему - по слову проверять номер комбинации.
Учитывая, что на форуме периодически задаются вопросы по генераторам случайных чисел и т.п. - решил поделиться. К моему стыду, эта занимательная арифметика занимала меня последние три часа.
Решение:
1. т.к. генератор от avb и NS давал маленький разброс случайных чисел, пришлось поюзать немного другой алгоритм:
function Random()
if emptyvalue(randSeed) = 1 then
randSeed = _getperformancecounter();
endif;
randSeed=(a*randSeed+c)%m;
return randSeed;
endfunction
Функция Степень(Знач а,Знач б, Рез=1)
Если б>0 Тогда
Рез=Рез*а;
б=б-1;
Степень(а,б,Рез);
Возврат Рез;
Иначе
Возврат Рез;
КонецЕсли;
КонецФункции
Функция ПолучитьСимволы(Поз,ТекСимв=1,СимСтр="")
Если ТекСимв<к Тогда
Делитель=Степень(СтрДлина(Буквы),к-ТекСимв);
ТекОст=Поз%Делитель;
СимСтр=Строка(СимСтр)+Сред(Буквы,Цел(Поз/Делитель+?(ТекОст>0,1,0)),1);
ПолучитьСимволы(ТекОст,ТекСимв+1,СимСтр);
Возврат СимСтр;
Иначе
СимСтр=СимСтр+Сред(Буквы,(?(Поз=0,СтрДлина(Буквы),Поз)),1);
Возврат СимСтр;
КонецЕсли;
КонецФункции
Функция ПолучитьКомбинацию(Слово,ТекСимв=0,Поз=0)
НомСимв=Найти(Буквы,Сред(Слово,к-ТекСимв,1));
Если ТекСимв>0 Тогда
Если ТекСимв<к Тогда
Поз=Поз+(НомСимв-1)*Степень(СтрДлина(Буквы),ТекСимв);
ПолучитьКомбинацию(Слово,ТекСимв+1,Поз);
Иначе
Возврат Поз;
КонецЕсли;
Иначе
Поз=?(НомСимв=СтрДлина(Буквы),0,НомСимв);
ПолучитьКомбинацию(Слово,ТекСимв+1,Поз);
Возврат Поз;
КонецЕсли;
КонецФункции
Для а=1 по N цикл
массив[а]=а;
Конеццикла;
Для а=1 по N-1 цикл
Сл=Случ(а,N);// Целое случайное число в интервале [а..N]
К=массив[а];
массив[а]=массив[Сл];
массив[Сл]=К;
КонецЦикла;
Sc = CreateObject("MSScriptControl.ScriptControl");
Sc.language = "VBscript";
sc.executeStatement("randomize");
оноВотТутаБудет=Sc.eval("rnd");
Ранд=_GetPerformanceCounter()%(100+1);
//только для целых чисел
Функция ПолучитьСлучайноеЧисло(Мин,Макс)
//вместо Randomize
Для н = 1 По 100 Цикл
Уник = Новый УникальныйИдентификатор;
КонецЦикла;
//генерируем GUID
Уник = СокрЛП(Новый УникальныйИдентификатор);
//оставляем только цифры
Уник = СтрЗаменить(Уник,"-","");
Уник = СтрЗаменить(Уник,"a","");
Уник = СтрЗаменить(Уник,"b","");
Уник = СтрЗаменить(Уник,"c","");
Уник = СтрЗаменить(Уник,"d","");
Уник = СтрЗаменить(Уник,"e","");
Уник = СтрЗаменить(Уник,"f","");
//знаменатель должен иметь такое же количество нулей + 1
Знаменатель = 10;
Для н = 2 По (СтрДлина(СтрЗаменить(Уник,Символы.НПП,""))) Цикл
Знаменатель = Знаменатель * 10;
КонецЦикла;
Случ = Число(Уник) / Знаменатель; //здесь получается дробное случайное число от 0 до 1
//преобразуем его в случайное число из заданного интервала, округляем до целого
ЧислоИзИнтервала = Мин(Макс(Окр(Мин + (Макс-Мин)*Случ),Мин),Макс);
Возврат ЧислоИзИнтервала;
КонецФункции
Ранд=_GetPerformanceCounter()%(100+1);
Ще б знати, що було по цьому посиланню http://pro1c.org.ua/redirect.php?http://www.sinor.ru/~my1c/knowhow/rand.html.
mister-x, где логика? Узнать не знаю что, но узнать что было там?
Украинский 1С форум: всё про 1С 8.3, 1С 8.2, 1С 8.1, 1С 8.0, 1С 7.7
https://pro1c.org.ua