Страницы

Поиск по вопросам

Показаны сообщения с ярлыком генерация-случайных-данных. Показать все сообщения
Показаны сообщения с ярлыком генерация-случайных-данных. Показать все сообщения

воскресенье, 8 марта 2020 г.

Можно ли рассчитывать идентичные последовательности на основе srand?

#c #случайные_числа #генерация_случайных_данных


Вопрос чисто философского характера:

Можно ли полагаться на базу рандомизации при генерации идентичных последовательностей
на разных устройствах?

Например, задав некоторую базу(srand) и cгенерировав 100 чисел, можно ли быть уверенным
в том, что именно эти самые числа будут сгенерированы с той же базой на более быстром/медленном
по частоте процессора компьютере/телефоне etc..?

P.S В основе вопроса - функция srand из стандартной библиотеки C.
P.P.S В разных компиляторах получаются разные последовательности.
    


Ответы

Ответ 1



Нет, нельзя. Реализация srand зависит от используемой стандартной библиотеки языка C - а она на разных компьютерах может отличаться. И даже на одном и том же компьютере она может отличаться. Даже если собирать одним и тем же компилятором. Если вам требуется переносимый детерминированный генератор псевдослучайных чисел - его лучше написать самостоятельно.

Ответ 2



В случае одного и того же компилятора на разных машинах, например - да. В случае разных компиляторов - нет.

понедельник, 24 февраля 2020 г.

Как сгенерировать случайное 64-разрядное целое число

#c_sharp #случайные_числа #генерация_случайных_данных


Как сгенерировать случайное 64-разрядное число (типа long, он же Int64) на C#? 
    


Ответы

Ответ 1



из social.msdn.microsoft.com Можно так: private readonly Random rnd = new Random(); // create it just once and reuse private ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes. // As an option, you could also use the cryptography namespace stuff to generate a random byte[8] byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer); return BitConverter.ToUInt64(buffer, 0) % (maxValue - minValue + 1) + minValue; } или так: public static ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer); if (minValue == ulong.MinValue && maxValue == ulong.MaxValue) return BitConverter.ToUInt64(buffer, 0); ulong modValue = maxValue - minValue + 1; return (BitConverter.ToUInt64(buffer, 0) % modValue) + minValue; }

воскресенье, 16 февраля 2020 г.

Как сгенерировать случайное 64-разрядное целое число

#c_sharp #случайные_числа #генерация_случайных_данных


Как сгенерировать случайное 64-разрядное число (типа long, он же Int64) на C#? 
    


Ответы

Ответ 1



из social.msdn.microsoft.com Можно так: private readonly Random rnd = new Random(); // create it just once and reuse private ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes. // As an option, you could also use the cryptography namespace stuff to generate a random byte[8] byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer); return BitConverter.ToUInt64(buffer, 0) % (maxValue - minValue + 1) + minValue; } или так: public static ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer); if (minValue == ulong.MinValue && maxValue == ulong.MaxValue) return BitConverter.ToUInt64(buffer, 0); ulong modValue = maxValue - minValue + 1; return (BitConverter.ToUInt64(buffer, 0) % modValue) + minValue; }

среда, 5 февраля 2020 г.

Как сгенерировать набор чисел, от мин до макс с указанной суммой? [дубликат]

#алгоритм #генерация_случайных_данных


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            Генерация случайных дробных чисел
                                
                                    (5 ответов)
                                
                        
                                Закрыт 2 года назад.
            
                    
Нужно сгенерировать массив чисел, чтобы потом использовать их. Условия:  


Задается общая сумма sum
Задается минимальное значение min
Задается максимальное значение max
Задается количество чисел count так, что сумма минимальных значений не превышала
суммы min * count < sum и сумма максимальных была не меньше суммы max * count > sum
Суммарное время всех чисел должно быть равно заданному numbers.Sum() == sum
Числа должны быть случайными в интервале от min до max


Сигнатура функции:

int GenerateNumbers(int min, int max, int count, int sum)




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

Подскажите, как составить алгоритм?
    


Ответы

Ответ 1



Пусть общее время T, количество пауз N, минимальная пауза t. Выделим на каждую паузу по t, останется F=T-Nt. Теперь сгенерируем N случайных чисел R[i] Посчитаем их сумму S Нормализуем, чтобы общая сумма была F R[i] = R[i] * F / S И добавим минимальные паузы R[i] = R[i] + t С учётом максимума из моего ответа на EnSO (там не сумма, а среднее, легко модифицировать. Есть код на Python и ссылка на C#). Замечу, что чем больше ограничений, тем менее равномерное распределение будет, но для многих практических целей это не страшно. Сгенерировать случайные значения в диапазоне 0..1 Найти их среднее Применить линейное преобразование R[i] = NeededAverage - average + (r[i] - average) * Math.Min((NeededMax - NeededAverage) / (1 - average), (NeededAverage - NeededMin) / (average))

вторник, 28 января 2020 г.

перебор ключей словаря в случайном порядке без повторений

#python #python_3x #генерация_случайных_данных


Есть ли возможность перебрать рандомно ключи словаря без повторений? 

У меня есть словарь с английскими словами и их переводом на русский, т.е 1 ключ:
1 значение. Надо их каждый раз, при запуске программы выводить рандомно эти ключи,
но без повторения

Пробовал применить метод shuffle из random но вылезает ошибка


    


Ответы

Ответ 1



Пример: import random d = { 'one':'один', 'two':'два', 'three':'три', 'four':'четыре', 'five':'пять' } In [39]: random.sample(d.keys(), len(d)) Out[39]: ['one', 'four', 'three', 'two', 'five'] In [40]: random.sample(d.keys(), len(d)) Out[40]: ['five', 'three', 'one', 'four', 'two'] In [41]: random.sample(d.keys(), len(d)) Out[41]: ['one', 'three', 'two', 'four', 'five'] In [42]: random.sample(d.keys(), len(d)) Out[42]: ['two', 'one', 'five', 'four', 'three'] UPDATE: from collections import OrderedDict In [64]: OrderedDict([(k,d[k]) for k in random.sample(d.keys(), len(d))]) Out[64]: OrderedDict([('two', 'два'), ('one', 'один'), ('three', 'три'), ('five', 'пять'), ('four', 'четыре')]) In [65]: OrderedDict([(k,d[k]) for k in random.sample(d.keys(), len(d))]) Out[65]: OrderedDict([('five', 'пять'), ('three', 'три'), ('four', 'четыре'), ('one', 'один'), ('two', 'два')]) или: import random from collections import OrderedDict def shuffle_dict(d): keys = list(d.keys()) random.shuffle(keys) return OrderedDict([(k, d[k]) for k in keys]) Использование: In [89]: shuffle_dict(d) Out[89]: OrderedDict([('three', 'три'), ('four', 'четыре'), ('five', 'пять'), ('one', 'один'), ('two', 'два')]) In [90]: shuffle_dict(d) Out[90]: OrderedDict([('one', 'один'), ('three', 'три'), ('two', 'два'), ('five', 'пять'), ('four', 'четыре')]) In [91]: shuffle_dict(d) Out[91]: OrderedDict([('three', 'три'), ('four', 'четыре'), ('two', 'два'), ('one', 'один'), ('five', 'пять')])

Ответ 2



Словарь — это неупорядоченная структура данных в Питоне (до Python 3.7). Порядок обхода может поменяться даже внутри одного и того же процесса (для разных словарей или для одного и того же словаря при вставке/удалении ключей). С другой стороны, в зависимости от реализации и настроек порядок ключей может повторяться и между запусками программы (в CPython 3.6 реализации словарь вообще упорядоченным является). Можно отдельный список ключей использовать и вручную его перемешать, чтобы не полагаться на PYTHONHASHSEED и другие особенности реализации словарей: import random keys = list(your_dict) random.shuffle(keys) Если хотите использовать словарь, который гарантированно сохраняет порядок вставки ключей: from collections import OrderedDict your_dict = OrderedDict(zip(keys, map(your_dict.get, keys))) Просто для обхода ключей не нужно OrderedDict создавать.

четверг, 9 января 2020 г.

Насколько неравномерно распределение случайных чисел при делении по модулю?

#cpp #случайные_числа #генерация_случайных_данных


В соседнем вопросе зашла речь о неравномерности распределения чисел при использовании
ГСЧ и деления по модулю. То же упоминается и в доках (rand):


  Notice though that this modulo operation does not generate uniformly distributed
random numbers in the span (since in most cases this operation makes lower numbers
slightly more likely).


Возьмем пример ГСЧ от 0 до 1000 с шагом 25:

return 25 * (rand() % 41); // Неравномерное распределение 

return int((40.0 * rand()) / (RAND_MAX + 1.0)) * 25; // Равномерное распределение


Так вот вопросы:
 - насколько неравномернее первый подход, чем второй?
 - насколько этот эффект проявляется в практических задачах?
 - стоит ли об этом беспокоиться?
 - если стоит, то начиная с какого момента?
 - какие есть варианты обхода неравномерности (кроме приведенного примера)?
    


Ответы

Ответ 1



Для реализаций, где RAND_MAX равно 32767, это может быть заметно. Например если нам нужно получить число от 0 до 9999, при использовании rand() % 10000 для значений до 2767 будет больше на 25% вероятности выпадения, т.к. они попадают в диапазоны rand: 0..2767, 10000..12767, 20000..22767, 30000..32767 в то время как для значений 2768..9999 диапазоны rand: 2768..9999, 12768..19999, 22768..29999 Если результат используется для выбора выигрышного билета в серии, то рекомендовал бы покупать билеты с младшими номерами. Соответственно чем больше RAND_MAX и меньше делитель, тем равномернее распределение при подходе с модулем.

Ответ 2



-насколько неравномернее первый подход, чем второй? Неравномерность этих подходов проистекает из двух источников: Мы проецируем дискретный диапазон одного размера на дискретный диапазон другого размера, и размер первого в общем случае не кратен размеру второго. В такой проекции всегда неизбежно будет возникать одна и та же "неравномерность" вероятности выбора одних целевых значений перед другими. В этих двух вариантах более вероятные значения будут по-разному размазаны по целевому диапазону, но это не принципиальное отличие. Как вы ни пытайтесь рассадить 7 голубей по 5 гнездам, неравномерность во всех вариантах рассадки будет одна и та же. То есть с этой точки зрения оба варианта совершенно одинаково неравномерны. Как вы ни крутитесь со способами выполнения такой проекции, ничего нового достичь не удастся - все проекции будут одинаково неравномерны. В первом случае мы извлекаем "случайность" из младших битов результата rand(), а во втором - из старших. Простейшие реализации rand() как раз страдают тем, что предоставляют неравномерное или недостаточно "случайное" распределение либо в младших, либо в старших битах rand(). Поэтому с этой точки зрения при выборе способа выполнения проекции следует учитывать характеристики вашей реализации rand(). Упоминание "в доках" того, что вариант с модулем якобы "хуже" - отсылка именно к этому фактору, а совсем не к тому, что описано выше (пункт 1). Однако это не более чем исторический курьез, элемент программистского фольклора, опирающийся на одну из первых, плохо продуманных реализаций rand() с очень предсказуемым распределением младших битов (см. самый первый здесь). В реальности же, не зная характеристик конкретного rand(), невозможно сделать вывод о том, какой способ лучше в этом отношении. Процитированное вами замечание "в доках" относится именно ко второму пункту, а ваш вопрос, похоже, посвящен именно первому. Это существенно разные темы. -насколько этот эффект проявляется в практических задачах? -стоит ли об этом беспокоиться? -если стоит, то начиная с какого момента? Зависит от практической задачи. Ясно, что качество rand() недостаточно для, скажем, криптографических задач. В то же время его более чем достаточно, например, для генерации случайных чисел для вероятностной структуры данных, вроде SkipList и т.п. В этом случае ни о чем беспокоиться не нужно вообще. какие есть варианты обхода неравномерности (кроме приведенного примера)? Сразу: ваш "приведенный пример" никак не обходит неравномерность, как сказано выше. Совершенно одинаковая по своей сути неравномерность при всех способах проекции диапазонов возникает потому, что проекция является "фиксированной", stateless: большую вероятность выбора всегда получают одни и те же значения целевого диапазона. Тут приходит в голову естественная мысль наделить сам процесс проекции состоянием, которое будет некоторым образом "двигать" проекцию по целевому диапазону от вызова к вызову, т.е. дополнительно "размазывать" неравномерность проекции по целевому диапазону. В самом простейшем случае можно было бы поступить так // Вместо return rand() % 41; // делаем static unsigned shift = 0; shift = (shift + 1) % 41; return (rand() % 41 + shift) % 41; Но на самом деле практически того же эффекта "подавления неравномерности" достигнет простое расширения диапазона rand() (например, путем конкатенации результатов двух последовательных вызовов rand()).

четверг, 2 января 2020 г.

Как разделить карту на заданное количество областей?

#алгоритм #разработка_игр #генерация_случайных_данных


пишу игру Dice War, но застрял в самом начале - на генерации карты.

Необходимо игровое поле разделить на области, площадь которых будет одинаковой. Для
поля 10х10 и 10 областей это должно выглядеть как-то так:

1 1 2 2 3 3 3 3 3 3
1 1 1 2 2 3 3 4 4 4
1 1 1 1 2 3 3 5 5 4
8 8 8 8 2 2 2 5 5 4
8 8 8 7 7 2 2 5 5 4
0 0 8 8 7 7 5 5 5 4
0 0 0 8 9 7 5 4 4 4
9 0 0 0 9 7 7 7 6 6
9 0 0 0 9 6 7 7 6 6
9 9 9 9 9 6 6 6 6 6

    


Ответы

Ответ 1



Можно сделать следующим образом. Сначала кидаем случайно центры областей с равномерным распределением, потом все элементы связываем с ближайшими центрами областей. В прошлом делал генератор текстур на этом алгоритме, получаются такие пазлы: В конце нужно проверять площадь каждой области, переносить элементы из слишком больших в слишком маленькие. Если Вы всерьёз взялись за написание игры, то запрограммировать эти действия должно быть не сложно. Update. Усреднять размеры областей можно разными времени написания и времени выполнения способами: Глобальный подход. Ищем пары ближайших областей с избытком и недостатком клеток, переносим элементы между ними. Пример: 1 1 1 2 2 3 => 1 1 2 2 3 3. Методы тыка. Все области с площадью больше средней отдают клетки другим областям без переизбытка площади, а все со слишком малой площадью забирают клетки у областей без недостатка. Затратно по времени, но если карты генерируются редко, то может подойти. Эвристический подход. Любые идеи, средние по сложности и качеству между двумя предыдущими. Например, те же случайные перемещения клеток, но только в те области, в которых перемещений ещё не было.

Ответ 2



Построение одной области можно сделать так: занять случайную пустую клетку; из соседних 4 клеток выбрать одну случайно, с учётом весов. Вес клетки расчитывается как сумма числа занятых соседей или стен. Пустая клетка посреди поля имеет нулевой вес. Клетка со всеми 4 соседями, или 3 соседями и у стены, или 2 соседями и в углу имеет макс. вес 4. Напр. при наличие двух свободных клеток рядом, у одной вес 1, у другой 4, берётся случайное от 0 до 1, и если оно попадает в диапазон 0 .. 0.2, то выбирается первая клетка, если 0.2 .. 1 – вторая. далее аналогично выбирается новая клетка, только из вариантов всей «колонии», а не только одной последней клетки. Алгоритм тот же. Демо – построение одной области: Так строится одна область. Для последующих брать опять случайную точку где угодно, или только на границе уже существующих областей. Upd. Оказалось, просто бросать случайные точки и растить область от каждой – не очень эффективно. Даже если начинать с чертырёх углов, чаще всего остаются «дыры». Стало лучше, когда при наличие среди вариантов глухой дыры с весом 4 (клетка уже закрыта со всех сторон), однозначно выбирается она, без случайностей. Даже иногда получаются 100% варианты заполнения: Гарантии от мёртвых зон, отрезанных у стены, нет – есть только вероятностный механизм. Надо внести коррективы. Случайно отбирать только в начале построения области, а чем ближе к концу, тем «строже» следовать макс. весу в ущерб случайности. Либо добавлять клетки в каждую из областей по очереди. Всем по 1-й клетке, затем всем по 2-й, и т.д. до N-й?.. Чувствую, задача сводится к моделированию поведения жидкостей : ) "use strict"; // пришлось добавить ради ссылки на jsFiddle

Ответ 3



Самое простое при маленьком поле нарисовать штук 100 карт или на сколько хватит терпения, поворотами, отражениями получить еще кучу. При большом поле вариант генерации: реализовать разрезание фигуры по клеточкам на две части в определенном соотношении по площади (1:1, 2:3, 1:2). Выбираем рандомно точку на границе фигуры. В каждой точке сетки мы можем двигаться в нескольких направлениях. Направлений может быть от нуля до трех (ноль - разрез закончен). Выбираем рандомно направление. 3.1. Проверяем можем ли резать в данном направлении. Главное, чтобы дойдя до границы получили нужную площадь. 3.2. Если поле большое, можно резать не по одной клетке, а больше, тоже рандомно. 3.3. Направление можно попытаться скорректировать, продлив разрез до границы и проверить площадь полученных фигур. Направление, в котором отклонение от необходимой площади минимально, можно выбирать с некоторым большим весом, тогда разрезы будут более ровными. Если веса распределять по-другому могут быть довольно причудливые формы. Разрезав фигуру до конца, получим две фигуры, для каждой из них, если надо повторяем с п.1. Сложно, но реализуемо...

пятница, 27 декабря 2019 г.

Генерация случайной строки со сбалансированными скобками

#c #алгоритм #генерация_случайных_данных


Возникла тут проблемка генерить случайную строку со сбалансированными скобками.
Т.е. строка abc(def(g)h)i - сбалансирована, а abc(def(g)hi и abc)(def)g - нет. Код
есть, и он работает нормально но есть одна проблемка: почти все строки заканчиваются
закрывающими скодками. Где я вижу проблему, и собственно вопрос - под кодом.

char * create_balanced_cstring(const char *alphabet, // строка нейтральных символов
(напр abcdefg...)
                               char obr, char cbr, // открывающая и закрывающая скобки
                               unsigned lmin, unsigned lmax) // мин и макс длина строки
{
    if (strchr(alphabet, obr) || strchr(alphabet, cbr))
        return 0;
    if (lmin > lmax || lmin == 0)
        return 0;

    int lenalph = strlen(alphabet); // длина "алфавита" нейтральных символов
    int length = rand() % (lmax - lmin + 1) + lmin; // длина генерирующейся строки
    char *s = (char*) malloc(length + 1);
    if (!s)
        return s;

    int opened = 0; // кол-во открытых скобок
    int just_opened = 0; // флаг для избегания фрагментов '()'
    char curchar; // текущий символ в строке
    for (int i = 0; i < length; ++i) {
        if (opened == length - i)
            curchar = cbr;
        else {
            if (opened + i + 2 >= length)
                curchar = alphabet[rand() % lenalph];
            else {
                int r = rand() % length;
                if (r < opened * 3 && !just_opened)
                    curchar = cbr;
                else if (r > 2 * length / 3 - opened)
                    curchar = obr;
                else
                    curchar = alphabet[rand() % lenalph];
            }
        }

        if (curchar == obr) {
            ++opened;
            just_opened = 1;
        } else {
            just_opened = 0;
            if (curchar == cbr) --opened;
        }

        s[i] = curchar;
    }
    s[length] = '\0';

    return s;
}


Проблема, ИМХО, тут:

        int r = rand() % length;
        if (r < opened * 3 && !just_opened)
            curchar = cbr;
        else if (r > length - opened)
            curchar = obr;
        else
            curchar = alphabet[rand() % lenalph];


т.е. с выбором в (условно) начале строки - открывать скобку, закрывать, или ставить
случайный символ. Хочется, чтобы вероятность открыть скобку увеличивалась, если их
открыто мало и наоборот, закрыть - увеличивалась если открыто много и наоборот. Просто
поиграться с коэффициэнтами? Текущие *3 и 2/3 - эмпирические, так вроде еще более-менее.

Т.е. в итоге нужно по 3-м параметрам (длина строки l, текущая позиция i и количество
незакрытых в этой позиции скобок o) сделать распределение вероятности выбора открывающей/закрывающей
скобки или "нейтрального" символа (не скобки) в данной позиции
    


Ответы

Ответ 1



Посмотрите Кнута, "Искусство программирования", т. 4А, стр. 511 русского издания, алгоритм W - равномерно распределенные случайные строки вложенных скобок. Алгоритм генерирует случайную строку корректно вложенных скобок для заданного их количества. Растыкать случайным образом 2n мест для скобок в строке, сгенерировать строку скобок и вставить на подготовленные места - не подойдет?

четверг, 26 декабря 2019 г.

Проверка гипотезы о равновероятности распределения ГПСЧ: смысл эксперементального значения Хи-квадрат

#python_3x #статистика #генерация_случайных_данных #статический_анализ


Есть гпсч на основе линейного конгруэнтного метода. Нужно проверить гипотезу о равновероятности
распределения полученных с помощью генератора значений выборок. Написал такую функцию:

def xi_check(num_array):
    intervals = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    for i in range(len(num_array)):
        intervals[num_array[i]//10] += 1
    xi_2_theor = [0, 3.33, 5.9, 8.34, 11.4, 16.9, 100] # квантили Хи-квадрат
    xi_2_inter = [1, 0.95, 0.75, 0.50, 0.25, 0.05, 0]  # уровень значимости
    xi_2_exp = 0
    for i in range(len(intervals)):
        xi_2_exp = xi_2_exp + ((float(intervals[i]) / float(len(num_array))
        - 0.1) ** 2) / 0.1
    for i in range(6):
        if xi_2_theor[i] <= xi_2_exp <= xi_2_theor[i+1]:
            return f"{xi_2_inter[i]} - {xi_2_inter[i+1]}", xi_2_exp
        else:
            return "Error", xi_2_exp


Если на выходе я получаю эксперементальное значение Хи-квадрат в промежутке между
11.4 и 16.9, то что это означает для меня? Можно ли полагаться на то, что ГПСЧ пораждает
равновероятные значения последовательности?

Иными словами, я не могу понять, как можно трактовать уровень значимости. Как из
него получить вероятность достоверности?
1 - (уровень значимости)?
    


Ответы

Ответ 1



Проверка, которую вы задумали провести, в общем случае называется «проверка выборки на соответствии теоретическому закону распределения». Может выполняться множеством разных методов - Колмогорова-Смирнова, Крамера-фон Мизеса, Джинни ….. и в том числе с помощью использования ХИ-квадрат критерия согласия Пирсона. Суть ее в том, что вы высчитываете некую статистику и сравниваете с тем значением, которое она (статистика) бы имела, если бы ваша выборка соответствовала бы теоретическому закону. В случае использование ХИ-квадрат критерия в качестве такой статистики используется ХИкв.практ= СУММА по количеству квантилей ((Ni-Ei)**2)/Ei) (обратите внимание, это несколько отлично от формулы, которую вы используете в программе). Затем происходит сравнение ХИкв.практ со значением, взятым из таблицыХИкв.крит. при выбранном значении уровня значимости и заданном значением степени свободы. Если полученное значение , меньше значения ХИкв.крит (альфа, df), то считается, что со степенью значимости («уверенности») альфа ваша выборка не отличается от теоретического (в данном случае - равномерного) распределения. Замечание 1. Иметь таблицу распределений сегодня уже не является обязательным – практически все инструменты – от Python до EXCEL – содержат функции, которые эти значения определяют самостоятельно. По той же причине и нет необходимости огород городить с самостоятельным Монте-Карло-моделированием. Замечание 2. Для анализа соответствие именно равномерному закону распределения есть и специальные критерии, например – Шермана, Неймана-Бартона и др. Вот как-то так.

суббота, 21 декабря 2019 г.

Алгоритм генерации случайных координат в двумерной плоскости

#алгоритм #случайные_числа #генерация_случайных_данных


Какой можно придумать алгоритм генерации случайных неповторяющихся координат на сетке
width и height размера, с range - расстоянием между ними и count количеством?
То есть чтобы результат был примерно следующим:
height = 10, width = 9 count = 3 range = 2

           или
.........      .........
.........      .........
....C....      .........
.........      .........
.........      .........
.C.......      .........
.........      .......C.
.......C.      ....C....
.........      .........
.........      ......C..

    


Ответы

Ответ 1



Двумерную сетку можно вытянуть в одномерный массив: x = i * width + j и соответственно вернуться к двумерной сетке: i = floor(x / width) j = x - width * i То есть задача сводится к генерации не повторяющихся индексов от 0 до width*height-1: Создаем массив x длиной N = width*height, заполняем его числами от 0 до width*height-1. Берем случайное число n в диапазоне от 0 до N-1 x[n] превращаем в пару (i,j) Ставим x[n] в конец массива (меняем его местами с x[N-1]) Уменьшаем N на 1. Повторяем начиная с шага 2.

Ответ 2



Думал, думал и наконец придумал и отладил алгоритм. У меня проверяется расстояние по ромбовидному принципу range = 3 ....o.... ...ooo... ..ooooo.. .oooXooo. ..ooooo.. ...ooo... ....o.... Создаем одномерный boolean массив. Забиваем массив значениями true (Если true - то место свободно) Создаем случайную координату в пределах поля (Для координат я использовал свой класс Coordinate. В нем я определил лишь два поля. X и Y) Проверяем, доступна ли координата. (Я использовал функцию GetAddress) Если доступна (true), генерируем координаты вокруг этой точки (Тут я пользовался функцией GetDiamondAreaCoordinates, но можно и любую другую вашу. Например квадратная область или круглая) и проверяем итератором валидны ли точки. Если не доступна возвращаемся к пункту 3. Если каждая точка области не за пределами поля, в boolean массив через функцию GetAddress забиваем false. Если за пределами, то продолжаем цикл. public Coordinate[] GetDiamondAreaCoordinates(Coordinate coordinate, int range) { ArrayList coordinates = new ArrayList<>(); int offsetHeight = 0, offsetWidth = range; int currentX = coordinate.getLeft(); int currentY = coordinate.getTop(); int localIterator = 0; for (int i = currentX-range; i < currentX+range+1; i++) { for (int j = currentY-offsetHeight; j < currentY+offsetHeight+1; j++) { coordinates.add(new Coordinate(i, j)); } offsetWidth --; offsetHeight += (currentX-offsetWidth <= currentX)? 1 : -1; } Coordinate[] resultCoords = coordinates.toArray(new Coordinate[coordinates.size()]); return resultCoords; } private int getAddress(int top, int left) { int index = top*width+left; if (index >= 0 && index < width*height) return index; return -1; }

суббота, 14 декабря 2019 г.

Как рекурсию переделать в итеративный метод.(Diamond-Square)

#c_sharp #алгоритм #unity3d #генерация_случайных_данных


Вот тут человек говорит:


  переделал все в итеративный метод, чтобы корректно считалось по слоям 


У меня такая-же ситуация есть методы, только не знаю как их вызывать послойно?
Я не могу зарегистрироваться на этом форуме, что бы спросить его.
Там же на форуме он кратко объясняет принцип работы алгоритма.


  Попытаюсь объяснить. Метод Square на вход получает два угла, левый нижний и правый
верхний и считает центральную точку заданного таким образом квадрата. Diamond принимает
на вход только координаты точки, которую надо посчитать (т.е. середины квадрата из
предыдущего шага) и половинную сторону этого квадрата, считает координаты четырех точек
справа, слева, сверху и снизу от принятой точки и также, как и в Square, усредняет
их и прибавляет случайное число, пропорциональное стороне. Если любая из координат
этих четырех точек выходит за границы карты, то он берет значение точки, лежащей с
другой стороны, т.е. как бы сворачивает плоскость. Метод DiamondSquare комбинирует
эти два метода, принимая те же параметры, что и Square. Сначала он вызывает Square
для входного квадрата, потом Diamond для всех четырех середин своих сторон, а потом
рекурсивно вызывает сам себя для четырех под-квадратов до тех пор, пока не посчитает
все пиксели. 


Сама рекурсивная функция:

public void diamondSquare(Vec2int L, Vec2int R, int l)
{
    if (l > 0) {
        Vec2int[] points = GetPoints(L, R, l);
        foreach (Vec2int elem in points) {
            diamond (elem, l);
        }
        square (L, new Vec2int (points [3].x, points [2].y), l);
        square (new Vec2int (points [3].x, points [2].y), R, l);
        square (points [0], points [1], l);
        square (points [3], points [2], l);

        diamondSquare (L, new Vec2int (points [3].x, points [2].y), l / 2);
        diamondSquare (new Vec2int (points [3].x, points [2].y), R, l / 2);
        diamondSquare (points [0], points [1], l / 2);
        diamondSquare (points [3], points [2], l / 2);
    }
}


Остальной код:

public int size = 32;
[Range(0,1f)]
public float Roughnees = 0.5f;
private float[,] map;

public void square(Vec2int L, Vec2int R, int l)
{
    Vec2int Center = new Vec2int (R.x - l, R.y - l);
    float a = map [L.x, L.y];
    float b = map [L.x, R.y];
    float c = map [R.x, R.y];
    float d = map [R.x, L.y];
    map [Center.x, Center.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1)
* (Roughnees), l / (size - 1) * (Roughnees));
}

public void diamond(Vec2int point,int l)
{
    float a, b, c, d;

    if (point.y - l >= 0)
        a = map [point.x, point.y - l];
    else
        a = map[point.x, size - l];  

    if (point.x - l >= 0)
        b = map [point.x - l, point.y];
    else
        b = map [size - l, point.y];

    if (point.y + l < size)
        c = map [point.x, point.y + l];
    else
        c = map [point.x, l];    

    if (point.x + l < size)
        d = map [point.x + l, point.y];
    else
        d = map [l, point.y];

    map [point.x, point.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1)
* Roughnees, l / (size - 1) * Roughnees);
}



public static Vec2int[] GetPoints(Vec2int L, Vec2int R, int l)
{
    return new Vec2int[] {
        new Vec2int (L.x, L.y + l),
        new Vec2int (R.x - l, R.y),
        new Vec2int (R.x, R.y - l),
        new Vec2int (L.x + l, L.y)
    };
}
public struct Vec2int
{
    public int x;
    public int y;
    public Vec2int(int x,int y){
        this.x=x;
        this.y=y;
    }
}


Так-же я был бы рад ссылкам на то что можно почитать в этом направлении.


  Важно заметить, что эти две высоты, которые достались нам на предыдущем шаге, должны
быть уже посчитаны — поэтому обсчет нужно вести «слоями», сначала для всех квадратов
выполнить шаг «square» — затем для всех ромбов выполнить шаг «diamond» — и перейти
к меньшим квадратам.


Из статьи на хабре.

В моём случае рекурсия уходит в глубь для левого нижнего квадрата и каждая его правая
и верхняя стороны неверно считается, и только после того как эта рекурсия заканчивается,
начитается следующая для правого верхнего, для которого тоже неверно считаются левая
и нижняя стороны.


Количество вызовов методов на первых 3 итерациях при разрешение картинки 64px 
1 x Square и Diamond
4 x Square и Diamond
16 x Square и Diamond
И для каждого метода нужно знать координаты.
    


Ответы

Ответ 1



Пару дней я только размышлял как решить мою проблему, начал смотреть в сторону yield, изучал его(правда так практически ни чего о нем и не понял), сегодня принялся экспериментировать с ним, и в это время пришла небольшая идея, которую я реализовал отказавшись от yield в процессе. В общем проблема решена, картинка генерируется правильно и достаточно быстро, с настройкой разрешения и шумности. Вот такие картинки генерирует: Сам код: using System.Collections; using System.Collections.Generic; using Global; using UnityEngine; public class DiaSqu : MonoBehaviour { public int size; public float Roughnees = 0.5f; Material mat; float[,] map; Texture2D GeneratedTexture; void Awake() { size++; mat = gameObject.GetComponent().material; GeneratedTexture = new Texture2D(size, size); map = new float[size, size]; map[0, 0] = Random.Range(0.3f, 0.6f); map[0, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, 0] = Random.Range(0.3f, 0.6f); } void Start() { Vec2int Left = new Vec2int(0, 0); Vec2int Right = new Vec2int(size - 1, size - 1); List box = new List(); box.Add(new Box[] { new Box(Left, Right) }); for (int l = size; l > 0; l /= 2) //Генерация box = Generate(box); for (int i = 0; i < size; i++) //Запись в текстуру for (int j = 0; j < size; j++) GeneratedTexture.SetPixel(i, j, new Color(map[i, j], map[i, j], map[i, j], 0)); GeneratedTexture.filterMode = FilterMode.Trilinear; GeneratedTexture.Apply(); mat.mainTexture = GeneratedTexture; } public List Generate(List input) { List next = new List(); foreach (Box[] Arr in input) foreach (Box item in Arr) next.Add(Square(item)); foreach (Box[] Arr in input) foreach (Box item in Arr) diamond(item); return next; } public Box[] Square(Box box) { Vec2int Center = new Vec2int(box.R.x - box.HalfLength, box.R.y - box.HalfLength); map[Center.x, Center.y] = (map[box.L.x, box.L.y] + map[box.L.x, box.R.y] + map[box.R.x, box.R.y] + map[box.R.x, box.L.y]) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); return new Box[]{ new Box(box.L,Center), new Box(Center,box.R), new Box(new Vec2int (box.L.x, box.L.y + box.HalfLength),new Vec2int (box.R.x - box.HalfLength, box.R.y)), new Box(new Vec2int (box.L.x+box.HalfLength, box.L.y),new Vec2int (box.R.x , box.L.y+box.HalfLength)) }; } public void diamond(Box box) { float a, b, c, d; Vec2int Center = new Vec2int(box.L.x + box.HalfLength, box.R.y - box.HalfLength); Vec2int[] points = new Vec2int[] { new Vec2int (Center.x-box.HalfLength,Center.y), //Left new Vec2int (Center.x,Center.y+box.HalfLength), //Top new Vec2int (Center.x+box.HalfLength,Center.y), //Right new Vec2int (Center.x,Center.y-box.HalfLength) //Bottom }; foreach (Vec2int point in points) { if (point.y - box.HalfLength >= 0) a = map[point.x, point.y - box.HalfLength]; else a = map[point.x, size - 1 - box.HalfLength]; if (point.x - box.HalfLength >= 0) b = map[point.x - box.HalfLength, point.y]; else b = map[size-1 - box.HalfLength, point.y]; if (point.y + box.HalfLength < size - 1) c = map[point.x, point.y + box.HalfLength]; else c = map[point.x, box.HalfLength]; if (point.x + box.HalfLength < size - 1) d = map[point.x + box.HalfLength, point.y]; else d = map[box.HalfLength, point.y]; map[point.x, point.y] = (a + b + c + d) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); } } public struct Box { public Vec2int L; public Vec2int R; public int HalfLength; public int Length; public Box(Vec2int L, Vec2int R) { this.L = L; this.R = R; Length = R.x - L.x; HalfLength = Length / 2; } } } Структура из Global public struct Vec2int {    public int x;    public int y;    public Vec2int(int x, int y)    {       this.x = x;       this.y = y;    } }

Ответ 2



Смотрите. Чтобы переделать (нехвостовую) рекурсию в итерацию, нужно использовать явную очередь заданий. Получаем структуру, реализующую одно задание: struct RecTask { public Vec2int L, R; public int l; public RecTask(Vec2int L, Vec2int R, int l) { this.L = L; this.R = R; this.l = l; } } Теперь в коде функции можно явно управлять заданиями: public void diamondSquare(Vec2int L, Vec2int R, int l) { Queue queue = new Queue(); queue.Enqueue(new RecTask(L, R, l)); while (queue.Count > 0) { var task = queue.Dequeue(); Vec2int[] points = GetPoints(task.L, task.R, task.l); foreach (Vec2int elem in points) { diamond(elem, task.l); } square(task.L, new Vec2int(points[3].x, points[2].y), task.l); square(new Vec2int(points[3].x, points[2].y), task.R, task.l); square(points[0], points[1], task.l); square(points[3], points[2], l); var newL = task.l/2; if (newL > 0) { queue.Enqueue(new RecTask(task.L, new Vec2int(points[3].x, points[2].y), newL)); queue.Enqueue(new RecTask(new Vec2int(points[3].x, points[2].y), task.R, newL)); queue.Enqueue(new RecTask(points[0], points[1], newL)); queue.Enqueue(new RecTask(points[3], points[2], newL)); } } } При этом решении порядок выполнения заданий немного другой. Если нужно сохранить и порядок, нужно превратить очередь в стек и класть задания в обратном порядке. public void diamondSquare(Vec2int L, Vec2int R, int l) { Stack stack = new Stack(); stack.Push(new RecTask(L, R, l)); while (stack.Count > 0) { var task = stack.Pop(); Vec2int[] points = GetPoints(L, R, l); foreach (Vec2int elem in points) { diamond(elem, l); } square(L, new Vec2int(points[3].x, points[2].y), l); square(new Vec2int(points[3].x, points[2].y), R, l); square(points[0], points[1], l); square(points[3], points[2], l); var newL = l/2; if (newL > 0) { stack.Push(new RecTask(points[3], points[2], newL)); stack.Push(new RecTask(points[0], points[1], newL)); stack.Push(new RecTask(new Vec2int(points[3].x, points[2].y), R, newL)); stack.Push(new RecTask(L, new Vec2int(points[3].x, points[2].y), newL)); } } }

суббота, 13 июля 2019 г.

Насколько неравномерно распределение случайных чисел при делении по модулю?

В соседнем вопросе зашла речь о неравномерности распределения чисел при использовании ГСЧ и деления по модулю. То же упоминается и в доках (rand):
Notice though that this modulo operation does not generate uniformly distributed random numbers in the span (since in most cases this operation makes lower numbers slightly more likely).
Возьмем пример ГСЧ от 0 до 1000 с шагом 25:
return 25 * (rand() % 41); // Неравномерное распределение
return int((40.0 * rand()) / (RAND_MAX + 1.0)) * 25; // Равномерное распределение
Так вот вопросы: - насколько неравномернее первый подход, чем второй? - насколько этот эффект проявляется в практических задачах? - стоит ли об этом беспокоиться? - если стоит, то начиная с какого момента? - какие есть варианты обхода неравномерности (кроме приведенного примера)?


Ответ

Для реализаций, где RAND_MAX равно 32767, это может быть заметно. Например если нам нужно получить число от 0 до 9999, при использовании
rand() % 10000
для значений до 2767 будет больше на 25% вероятности выпадения, т.к. они попадают в диапазоны rand:
0..2767, 10000..12767, 20000..22767, 30000..32767
в то время как для значений 2768..9999 диапазоны rand:
2768..9999, 12768..19999, 22768..29999
Если результат используется для выбора выигрышного билета в серии, то рекомендовал бы покупать билеты с младшими номерами.
Соответственно чем больше RAND_MAX и меньше делитель, тем равномернее распределение при подходе с модулем.

четверг, 30 мая 2019 г.

Можно ли рассчитывать идентичные последовательности на основе srand?

Вопрос чисто философского характера:
Можно ли полагаться на базу рандомизации при генерации идентичных последовательностей на разных устройствах?
Например, задав некоторую базу(srand) и cгенерировав 100 чисел, можно ли быть уверенным в том, что именно эти самые числа будут сгенерированы с той же базой на более быстром/медленном по частоте процессора компьютере/телефоне etc..?
P.S В основе вопроса - функция srand из стандартной библиотеки C. P.P.S В разных компиляторах получаются разные последовательности.


Ответ

Нет, нельзя. Реализация srand зависит от используемой стандартной библиотеки языка C - а она на разных компьютерах может отличаться. И даже на одном и том же компьютере она может отличаться. Даже если собирать одним и тем же компилятором.
Если вам требуется переносимый детерминированный генератор псевдослучайных чисел - его лучше написать самостоятельно.

суббота, 27 апреля 2019 г.

Как сгенерировать случайное 64-разрядное целое число

Как сгенерировать случайное 64-разрядное число (типа long, он же Int64) на C#?


Ответ

из social.msdn.microsoft.com
Можно так:
private readonly Random rnd = new Random(); // create it just once and reuse private ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes. // As an option, you could also use the cryptography namespace stuff to generate a random byte[8] byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer); return BitConverter.ToUInt64(buffer, 0) % (maxValue - minValue + 1) + minValue; }
или так:
public static ulong Get64BitRandom(ulong minValue, ulong maxValue) { // Get a random array of 8 bytes byte[] buffer = new byte[sizeof(ulong)]; rnd.NextBytes(buffer);
if (minValue == ulong.MinValue && maxValue == ulong.MaxValue) return BitConverter.ToUInt64(buffer, 0);
ulong modValue = maxValue - minValue + 1; return (BitConverter.ToUInt64(buffer, 0) % modValue) + minValue; }

понедельник, 3 декабря 2018 г.

Генерация случайной строки со сбалансированными скобками

Возникла тут проблемка генерить случайную строку со сбалансированными скобками. Т.е. строка abc(def(g)h)i - сбалансирована, а abc(def(g)hi и abc)(def)g - нет. Код есть, и он работает нормально но есть одна проблемка: почти все строки заканчиваются закрывающими скодками. Где я вижу проблему, и собственно вопрос - под кодом.
char * create_balanced_cstring(const char *alphabet, // строка нейтральных символов (напр abcdefg...) char obr, char cbr, // открывающая и закрывающая скобки unsigned lmin, unsigned lmax) // мин и макс длина строки { if (strchr(alphabet, obr) || strchr(alphabet, cbr)) return 0; if (lmin > lmax || lmin == 0) return 0;
int lenalph = strlen(alphabet); // длина "алфавита" нейтральных символов int length = rand() % (lmax - lmin + 1) + lmin; // длина генерирующейся строки char *s = (char*) malloc(length + 1); if (!s) return s;
int opened = 0; // кол-во открытых скобок int just_opened = 0; // флаг для избегания фрагментов '()' char curchar; // текущий символ в строке for (int i = 0; i < length; ++i) { if (opened == length - i) curchar = cbr; else { if (opened + i + 2 >= length) curchar = alphabet[rand() % lenalph]; else { int r = rand() % length; if (r < opened * 3 && !just_opened) curchar = cbr; else if (r > 2 * length / 3 - opened) curchar = obr; else curchar = alphabet[rand() % lenalph]; } }
if (curchar == obr) { ++opened; just_opened = 1; } else { just_opened = 0; if (curchar == cbr) --opened; }
s[i] = curchar; } s[length] = '\0';
return s; }
Проблема, ИМХО, тут:
int r = rand() % length; if (r < opened * 3 && !just_opened) curchar = cbr; else if (r > length - opened) curchar = obr; else curchar = alphabet[rand() % lenalph];
т.е. с выбором в (условно) начале строки - открывать скобку, закрывать, или ставить случайный символ. Хочется, чтобы вероятность открыть скобку увеличивалась, если их открыто мало и наоборот, закрыть - увеличивалась если открыто много и наоборот. Просто поиграться с коэффициэнтами? Текущие *3 и 2/3 - эмпирические, так вроде еще более-менее.
Т.е. в итоге нужно по 3-м параметрам (длина строки l, текущая позиция i и количество незакрытых в этой позиции скобок o) сделать распределение вероятности выбора открывающей/закрывающей скобки или "нейтрального" символа (не скобки) в данной позиции


Ответ

Посмотрите Кнута, "Искусство программирования", т. 4А, стр. 511 русского издания, алгоритм W - равномерно распределенные случайные строки вложенных скобок. Алгоритм генерирует случайную строку корректно вложенных скобок для заданного их количества.
Растыкать случайным образом 2n мест для скобок в строке, сгенерировать строку скобок и вставить на подготовленные места - не подойдет?

понедельник, 22 октября 2018 г.

Как рекурсию переделать в итеративный метод.(Diamond-Square)

Вот тут человек говорит:
переделал все в итеративный метод, чтобы корректно считалось по слоям
У меня такая-же ситуация есть методы, только не знаю как их вызывать послойно? Я не могу зарегистрироваться на этом форуме, что бы спросить его. Там же на форуме он кратко объясняет принцип работы алгоритма.
Попытаюсь объяснить. Метод Square на вход получает два угла, левый нижний и правый верхний и считает центральную точку заданного таким образом квадрата. Diamond принимает на вход только координаты точки, которую надо посчитать (т.е. середины квадрата из предыдущего шага) и половинную сторону этого квадрата, считает координаты четырех точек справа, слева, сверху и снизу от принятой точки и также, как и в Square, усредняет их и прибавляет случайное число, пропорциональное стороне. Если любая из координат этих четырех точек выходит за границы карты, то он берет значение точки, лежащей с другой стороны, т.е. как бы сворачивает плоскость. Метод DiamondSquare комбинирует эти два метода, принимая те же параметры, что и Square. Сначала он вызывает Square для входного квадрата, потом Diamond для всех четырех середин своих сторон, а потом рекурсивно вызывает сам себя для четырех под-квадратов до тех пор, пока не посчитает все пиксели.
Сама рекурсивная функция:
public void diamondSquare(Vec2int L, Vec2int R, int l) { if (l > 0) { Vec2int[] points = GetPoints(L, R, l); foreach (Vec2int elem in points) { diamond (elem, l); } square (L, new Vec2int (points [3].x, points [2].y), l); square (new Vec2int (points [3].x, points [2].y), R, l); square (points [0], points [1], l); square (points [3], points [2], l);
diamondSquare (L, new Vec2int (points [3].x, points [2].y), l / 2); diamondSquare (new Vec2int (points [3].x, points [2].y), R, l / 2); diamondSquare (points [0], points [1], l / 2); diamondSquare (points [3], points [2], l / 2); } }
Остальной код:
public int size = 32; [Range(0,1f)] public float Roughnees = 0.5f; private float[,] map;
public void square(Vec2int L, Vec2int R, int l) { Vec2int Center = new Vec2int (R.x - l, R.y - l); float a = map [L.x, L.y]; float b = map [L.x, R.y]; float c = map [R.x, R.y]; float d = map [R.x, L.y]; map [Center.x, Center.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1) * (Roughnees), l / (size - 1) * (Roughnees)); }
public void diamond(Vec2int point,int l) { float a, b, c, d;
if (point.y - l >= 0) a = map [point.x, point.y - l]; else a = map[point.x, size - l];
if (point.x - l >= 0) b = map [point.x - l, point.y]; else b = map [size - l, point.y];
if (point.y + l < size) c = map [point.x, point.y + l]; else c = map [point.x, l];
if (point.x + l < size) d = map [point.x + l, point.y]; else d = map [l, point.y];
map [point.x, point.y] = (a + b + c + d) / 4 + Random.Range (-l / (size - 1) * Roughnees, l / (size - 1) * Roughnees); }

public static Vec2int[] GetPoints(Vec2int L, Vec2int R, int l) { return new Vec2int[] { new Vec2int (L.x, L.y + l), new Vec2int (R.x - l, R.y), new Vec2int (R.x, R.y - l), new Vec2int (L.x + l, L.y) }; } public struct Vec2int { public int x; public int y; public Vec2int(int x,int y){ this.x=x; this.y=y; } }
Так-же я был бы рад ссылкам на то что можно почитать в этом направлении.
Важно заметить, что эти две высоты, которые достались нам на предыдущем шаге, должны быть уже посчитаны — поэтому обсчет нужно вести «слоями», сначала для всех квадратов выполнить шаг «square» — затем для всех ромбов выполнить шаг «diamond» — и перейти к меньшим квадратам.
Из статьи на хабре.
В моём случае рекурсия уходит в глубь для левого нижнего квадрата и каждая его правая и верхняя стороны неверно считается, и только после того как эта рекурсия заканчивается, начитается следующая для правого верхнего, для которого тоже неверно считаются левая и нижняя стороны.
Количество вызовов методов на первых 3 итерациях при разрешение картинки 64px 1 x Square и Diamond 4 x Square и Diamond 16 x Square и Diamond И для каждого метода нужно знать координаты.


Ответ

Пару дней я только размышлял как решить мою проблему, начал смотреть в сторону yield, изучал его(правда так практически ни чего о нем и не понял), сегодня принялся экспериментировать с ним, и в это время пришла небольшая идея, которую я реализовал отказавшись от yield в процессе. В общем проблема решена, картинка генерируется правильно и достаточно быстро, с настройкой разрешения и шумности. Вот такие картинки генерирует:
Сам код:
using System.Collections; using System.Collections.Generic; using Global; using UnityEngine;
public class DiaSqu : MonoBehaviour { public int size; public float Roughnees = 0.5f;
Material mat; float[,] map; Texture2D GeneratedTexture;
void Awake() { size++;
mat = gameObject.GetComponent().material; GeneratedTexture = new Texture2D(size, size);
map = new float[size, size]; map[0, 0] = Random.Range(0.3f, 0.6f); map[0, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, size - 1] = Random.Range(0.3f, 0.6f); map[size - 1, 0] = Random.Range(0.3f, 0.6f);
} void Start() { Vec2int Left = new Vec2int(0, 0); Vec2int Right = new Vec2int(size - 1, size - 1);
List box = new List(); box.Add(new Box[] { new Box(Left, Right) });
for (int l = size; l > 0; l /= 2) //Генерация box = Generate(box);
for (int i = 0; i < size; i++) //Запись в текстуру for (int j = 0; j < size; j++) GeneratedTexture.SetPixel(i, j, new Color(map[i, j], map[i, j], map[i, j], 0));
GeneratedTexture.filterMode = FilterMode.Trilinear; GeneratedTexture.Apply(); mat.mainTexture = GeneratedTexture; } public List Generate(List input) { List next = new List(); foreach (Box[] Arr in input) foreach (Box item in Arr) next.Add(Square(item)); foreach (Box[] Arr in input) foreach (Box item in Arr) diamond(item); return next; } public Box[] Square(Box box) { Vec2int Center = new Vec2int(box.R.x - box.HalfLength, box.R.y - box.HalfLength); map[Center.x, Center.y] = (map[box.L.x, box.L.y] + map[box.L.x, box.R.y] + map[box.R.x, box.R.y] + map[box.R.x, box.L.y]) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); return new Box[]{ new Box(box.L,Center), new Box(Center,box.R), new Box(new Vec2int (box.L.x, box.L.y + box.HalfLength),new Vec2int (box.R.x - box.HalfLength, box.R.y)), new Box(new Vec2int (box.L.x+box.HalfLength, box.L.y),new Vec2int (box.R.x , box.L.y+box.HalfLength)) }; } public void diamond(Box box) { float a, b, c, d; Vec2int Center = new Vec2int(box.L.x + box.HalfLength, box.R.y - box.HalfLength); Vec2int[] points = new Vec2int[] { new Vec2int (Center.x-box.HalfLength,Center.y), //Left new Vec2int (Center.x,Center.y+box.HalfLength), //Top new Vec2int (Center.x+box.HalfLength,Center.y), //Right new Vec2int (Center.x,Center.y-box.HalfLength) //Bottom }; foreach (Vec2int point in points) { if (point.y - box.HalfLength >= 0) a = map[point.x, point.y - box.HalfLength]; else a = map[point.x, size - 1 - box.HalfLength]; if (point.x - box.HalfLength >= 0) b = map[point.x - box.HalfLength, point.y]; else b = map[size-1 - box.HalfLength, point.y]; if (point.y + box.HalfLength < size - 1) c = map[point.x, point.y + box.HalfLength]; else c = map[point.x, box.HalfLength]; if (point.x + box.HalfLength < size - 1) d = map[point.x + box.HalfLength, point.y]; else d = map[box.HalfLength, point.y]; map[point.x, point.y] = (a + b + c + d) / 4 + Random.Range(-box.Length * Roughnees / (size - 1), box.Length * Roughnees / (size - 1)); } } public struct Box { public Vec2int L; public Vec2int R; public int HalfLength; public int Length;
public Box(Vec2int L, Vec2int R) { this.L = L; this.R = R; Length = R.x - L.x; HalfLength = Length / 2; } } }
Структура из Global public struct Vec2int {    public int x;    public int y;    public Vec2int(int x, int y)    {       this.x = x;       this.y = y;    } }