Сейчас на форуме: _MBK_, tyns777, UniSoft (+11 невидимых)

 eXeL@B —› Программирование —› алгоритмы автовыбора
Посл.ответ Сообщение

Ранг: 19.4 (новичок), 1thx
Активность: 0.030
Статус: Участник

Создано: 13 июля 2012 19:41 · Поправил: albatros
· Личное сообщение · #1

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



Ранг: 25.7 (посетитель), 4thx
Активность: 0.030
Статус: Участник

Создано: 13 июля 2012 19:47
· Личное сообщение · #2

да. и называются они генератор случайных чисел



Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 13 июля 2012 20:13
· Личное сообщение · #3

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



Ранг: 19.4 (новичок), 1thx
Активность: 0.030
Статус: Участник

Создано: 13 июля 2012 22:36
· Личное сообщение · #4

F_a_u_s_t да. имелось в виду наподобие автовыбора как в aimp



Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 13 июля 2012 23:13
· Личное сообщение · #5

albatros
1
2
Хотя для твоей задачи и обычного рандома хватит, можно и какой нибудь мелкий алгоритм использовать что бы дублей меньше было если список огромный.



Ранг: 19.4 (новичок), 1thx
Активность: 0.030
Статус: Участник

Создано: 14 июля 2012 00:05
· Личное сообщение · #6

F_a_u_s_t thanks



Ранг: 162.4 (ветеран), 11thx
Активность: 0.060
Статус: Участник

Создано: 16 июля 2012 13:51
· Личное сообщение · #7

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



Ранг: 162.2 (ветеран)
Активность: 0.090
Статус: Участник

Создано: 16 июля 2012 14:36
· Личное сообщение · #8

Лучше перед запуском проигрывания перемешать список и начинать его проигрывать. Тогда не будет повторных запусков и не надо вести списков для проигрывания следующий/предыдущий.




Ранг: 756.3 (! !), 113thx
Активность: 0.610.05
Статус: Участник
Student

Создано: 16 июля 2012 22:59
· Личное сообщение · #9

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

-----
z+Dw7uLu5+jqLCDq7vLu8PvpIPHs7uMh


| Сообщение посчитали полезным: ClockMan

Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 17 июля 2012 01:08
· Личное сообщение · #10

Есчо вариант если без сортировки списка то когда проигрывается первая случайная дорожка, заносишь int в какой нибудь vector и во время проигрывания генеришь есчо одно число и проверяешь в векторе если нет то нор, ибо если список большой может появиться неслабый оверхед из за проверок на повторы и будут тормаза при переключении, а если сортировать список, то нужно генерить сразу массив и по нему раскидать список воспроизведения, хотя упомянутый aimp часто помирает на этом деле, а winamp делает это долго и слабое распределение ибо делает это частично, все из за того же оверхеда, мало кто будет ждать N минут пока он отсортирует, уныло в общем.



Ранг: 162.4 (ветеран), 11thx
Активность: 0.060
Статус: Участник

Создано: 17 июля 2012 16:31
· Личное сообщение · #11

так повторы можно оставить, только разнести их по времени.
Например не раньше 20 треков. Тут потребуется хранить только 20 предыдущих событий.



Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 17 июля 2012 17:13
· Личное сообщение · #12

Товарисчи.. я чет не допонимаю? схема генераций псевдослучайного числа предусматривает отсутсвие ближайших повторов. Где я не прав?

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 17 июля 2012 17:27
· Личное сообщение · #13

VodoleY
Все просто, генератор ограничен числом дорожек, пример:
Code:
  1. Randomize;
  2. Rnd := Random(PlayList.Count {Количество дорожек});

Прогони несколько раз и увидишь кучу дублей, уже приводил в пример winamp с его случайным воспроизведением которое одну дорожку может три раза подряд проиграть, факт из личной практики.
Если проверять на дубли и большой список воспроизведения то появляется оверхед.
Оптимально, как предложил SWR разбивать на группы.

| Сообщение посчитали полезным: DimitarSerg

Ранг: 488.1 (мудрец), 272thx
Активность: 0.350
Статус: Участник

Создано: 17 июля 2012 17:38
· Личное сообщение · #14

F_a_u_s_t для справки.. генерация стойкого рандома это отдельное подразделение математики. Винамп не показатель. алгоритмов масса, я сори, не спец по рандомам. но "совершенный код, майкрософт пресс" советую почитать, там отдельная глава на эту тему.

-----
Наша работа во тьме, Мы делаем, что умеем. Мы отдаем, что имеем, Наша работа во тьме....




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 17 июля 2012 18:28
· Личное сообщение · #15

VodoleY
Если речь об этой книге: М.Ховард Д.Лебланк - Защищенный код
то я ее читал и там нет противоречия моим словам, там так и написано что стандартный random из crt это уг, а более надежные дают неслабый оверхед, а так же выше писал что все числа можно поместить в vector с проверкой на уникальность, но при большом списке будет оверхед, тут дело не в надежности, а в скорости.



Ранг: 162.4 (ветеран), 11thx
Активность: 0.060
Статус: Участник

Создано: 18 июля 2012 15:11
· Личное сообщение · #16

VodoleY
Рандомный генератор не исключает и 1000 подрят одинаковых значений. Только вероятность такого исхода очень мала.

F_a_u_s_t
Ну я предложил не группы, а тупо хранить 20ку последних игравших, и если че исключать повтор по ней.
(закольцованный массив)




Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 18 июля 2012 15:35 · Поправил: ARCHANGEL
· Личное сообщение · #17

А почему не генерировать список всех треков, допустим, изначально их 100, например. Список будет содержать 100 элементов. Потом рандомом получаем номер от 0 до 99, например, выпало 11. Проиграли двенадцатый трек и удалили его из списка. Теперь списко сократился, и в нём уже можно найти элементы по номерам от 0 до 98. Опять рандомный номер, например, опять 11 (если хреновый генератор псевдослучайных чисел), но теперь проигрываться будет трек, который в первоначальном списке был 12, т.е. нет повторов. А, допустим, через 20 проигранных треков заново добавим удалённые в конец списка. Так убивается сразу несколько зайцев. Во-первых, не надо гонять рандомный псевдогенератор. Даже если он - полное фуфло, мы избежим повторов и получим-таки элемент случайности. Во-вторых, один раз сгенерировав служебный список, нам не нужно каждый раз его перестраивать, ведь мы не будем полностью удалять элементы списка, а будем лишь разрушать ссылки элементов друг на друга. В-третьи, получается очень экономично по затрачиваемой памяти, если сделать так, чтоб представить элементы двумя списками, объединёнными в один. Т.е., элемент находится в памяти в единственном экземпляре, но имеет два указателя на другие элементы. Так сказать, у нас будет два односвязных списка. Первый указатель связывает элементы так, как они изначально были заданы в плейлист (например, когда вы открываете винамп, то видите там чёткий порядок, хотя они и могут проигрываться случайно), а второй указывает и положение для списка проигрывания. И разрушая вторые ссылки, мы оставляем первые, что позволит добавлять во второй список элементы, проходя по первому. Надеюсь, не слишком туманно объяснил.

Подумал...
Можно модифицировать алго, упростив его. Предположим, мы составили список всех треков, которые должны проигрываться в случайном порядке. У нас есть переменная, в которой хранится общее число таких треков. Плюс к этому - у нас есть константа, которая показывает минимальное число треков, проигрываемых без повторения. Допустим, у нас в плей-листе 100 песен, при этом мы хотим, чтоб как минимум 20 раз подряд темы не проигрывались повторно, ь.е. если проигрался трек номер 1, то после него должны прозвучать ещё 19 других треков перед тем, как он, возможно, проиграется вновь.

С постановкой задачи определились. Теперь в плане реализации. У нас также есть некий генератор случайных чисел, который позволяет худо-бедно генерировать псевдослучайные числа в заданном диапазоне. Допустим, нам нужно сгенерировать число в диапазоне [0,99]. он генерирует 45 (например). Мы проигрываем трек № 45, и перемещаем (!!!) его в конец списка, счётчик же всех элементов уменьшаем на 1. Так мы делаем столько раз, сколько указано в нашей константе. В примере выше указано 20 раз. Получается, что на каждой последующей итерации мы уменьшаем счётчик, который одновременно является верхней границей диапазона случайных чисел. Поэтому он не может сгенерировать номер, соответствующий уже проигранным трекам. Когда же цикл завершится, добавляем значение константы к уменьшенному в результате работы цикла значению счётчика, и он снова равен числу всех элементов списка. Плохо будет лишь в том случае, если генератор вообще дерьмовый и генерирует числа в диапазоне Верхняя_граница - Константа. Тогда всё время будет слушать всё то же количество треков, равных константе. Но такого не будет в случае с тем же rand(), т.к. это не совсем фуфло.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 20 июля 2012 23:34
· Личное сообщение · #18

ARCHANGEL
Вполне годный вариант и реализация простая, первый вариант больше понравился, так как исключает повторы.




Ранг: 104.9 (ветеран), 47thx
Активность: 0.040.02
Статус: Участник

Создано: 21 июля 2012 00:00
· Личное сообщение · #19

Isaev пишет:
можно составить массив и когда рандомом выбераешь помечать чтобы исключить дубли. Будет рандом без повторов

Поддержу этот вариант. Классический алгоритм тасовки колоды карт в компьютерных играх: каждой карте присваивается случайный индекс, затем колода (массив) упорядочивается по этому индексу, например, по возрастанию. В случае с плеером выполняется сортировка треков, затем воспроизведение идет уже по этому списку. При достижении конца списка операция сортировки повторяется. Гарантированно никаких повторов, всегда доступна информация о следующем и предыдущем треке.

| Сообщение посчитали полезным: obfuskator


Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 21 июля 2012 10:10
· Личное сообщение · #20

F_a_u_s_t
Первый вариант - как-бы частный случай второго, во втором тоже самое достигается, если значение константы равно количеству треков в списке, т.е. он более гибкий.

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

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 369.8 (мудрец), 400thx
Активность: 0.390
Статус: Участник

Создано: 21 июля 2012 10:28
· Личное сообщение · #21

F_a_u_s_t пишет:
aimp часто помирает на этом деле, а winamp делает это долго и слабое распределение ибо делает это частично, все из за того же оверхеда, мало кто будет ждать N минут пока он отсортирует, уныло в общем.

Либо у вас плейлисты на 100500 миллионов песен, либо в плеерах мега-индусский код. Хоть сортировка хоть перемешивание десятка тысяч строк занимает доли секунды на самых стандартных контейнерах и алгоритмах.
Хинт: std::vector, std::string, std::sort, std::random_shuffle

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

Хинт: #include <random>, std::random_device, std::mt19937

-----
PGP key <0x1B6A24550F33E44A>


| Сообщение посчитали полезным: obfuskator


Ранг: 568.2 (!), 465thx
Активность: 0.550.57
Статус: Участник
оптимист

Создано: 21 июля 2012 10:52
· Личное сообщение · #22

ARCHANGEL пишет:
генератора псевдослучайных чисел

На то ини и псевдо что повторяютя при каждом первом запуске
Небольшой код на delphi генерирующий псевдо случайное число
Code:
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   T1:string;
  4.   T2:integer;
  5.   T3:byte;
  6. begin
  7.   Edit1.Text:='';
  8.   T2:=SpinEdit1.Value;
  9.   while Length(Edit1.Text) < T2 do
  10.     begin
  11.     T3:=Random(255);
  12.     if (T3>=48) and (T3<=57) then T1:=T1+chr(T3);
  13.       if(T3>=65) and (T3<=90) then T1:=T1+chr(T3);
  14.         if(T3>=97) and (T3<=122) then T1:=T1+chr(T3);
  15.     Edit1.Text:=T1;
  16.     end;
  17. end;
  18.  
  19. end.

при длине генератора ключа 10 первое значение будет всегда
3EQlyJSNTv

при включение генератора случайных чисел получить одиннаковую строку сводится к обычному нулю
Code:
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   T1:string;
  4.   T2:integer;
  5.   T3:byte;
  6. begin
  7.   Edit1.Text:='';
  8.   T2:=SpinEdit1.Value;
  9.   while Length(Edit1.Text) < T2 do
  10.     begin
  11.     Randomize;
  12.     T3:=Random(255);
  13.     if (T3>=48) and (T3<=57) then T1:=T1+chr(T3);
  14.       if(T3>=65) and (T3<=90) then T1:=T1+chr(T3);
  15.         if(T3>=97) and (T3<=122) then T1:=T1+chr(T3);
  16.     Edit1.Text:=T1;
  17.     end;
  18. end;
  19.  
  20. end.

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

-----
Чтобы правильно задать вопрос, нужно знать большую часть ответа. Р.Шекли.





Ранг: 681.5 (! !), 405thx
Активность: 0.420.21
Статус: Участник
ALIEN Hack Team

Создано: 21 июля 2012 11:44
· Личное сообщение · #23

ClockMan пишет:
На то ини и псевдо что повторяютя при каждом первом запуске

Та нет, не потому. А потому что под псевдо подразумевается наличие некоей не случайной зависимости. Т.е. в первом приближении элементы такого пседослучайного ряда представляют собой рекуррентное соотношение. И при одном и том же начальном элементе имеем один и тот же ряд. Естественно, библиотечные функции заточены под генерацию разных последовательностей.

-----
Stuck to the plan, always think that we would stand up, never ran.




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 21 июля 2012 14:48
· Личное сообщение · #24

ntldr
Смотрим реализацию random_shuffle и видим там rand() который нормально работает с time(0), потом пилим семпл примерно такого содержания -
Code:
  1.     vector<int> PlayList;
  2.  
  3.     for (int i = 0; i != 1000; i++)
  4.     {
  5.         PlayList.push_back(i);
  6.     }
  7.          
  8.          
  9.     for (int i = 0; i != 10; i++)
  10.     {
  11.         random_shuffle(PlayList.begin(), PlayList.end());
  12.                  
  13.         for (int index = 0; index != 100; index++)
  14.         {
  15.             cout << PlayList[index] << endl;
  16.  
  17.         }
  18.         cout << "********************************************************************************" << endl;
  19.  
  20.     }

И выскакивают одни и те же числа, random_device и плей лист как то слабо сочетаются, ибо ограничено размером листа и число от фонаря не катит, а нужно от 0 до MAX_LIST.
О минутах было сказано в контексте winamp и aimp первый долго сортирует (глазуальный список), а второй иногда помирает на этом деле. А так, есчо есть boost с кучей алгоритмов это не является каким то откровением, а по поводу списка то у меня иногда добегает до 6к дорожек. Ну и о скорости, тот же SQLite сортирует 1м записей несколько секунд. Есчо я выпил и в коде мог накосячить, ну да ладно кому надо тот поймет.



Ранг: 369.8 (мудрец), 400thx
Активность: 0.390
Статус: Участник

Создано: 21 июля 2012 15:28
· Личное сообщение · #25

Смотрим --> документацию <-- на random_shuffle и видим что это шаблонный класс, который может принимать RNG отличный от дефолтового.
Пример:

Code:
  1. std::vector<int>   test;
  2. std::random_device random_dev;
  3.  
  4. for (int i = 0; i < 5; i++) test.push_back(i);
  5. std::random_shuffle(test.begin(), test.end(), [&](ptrdiff_t i) { return random_dev() % i; });

Учимся юзать стандартную библиотеку господа.

-----
PGP key <0x1B6A24550F33E44A>




Ранг: 0.0 (гость)
Активность: 0.250
Статус: Участник

Создано: 21 июля 2012 15:59 · Поправил: F_a_u_s_t
· Личное сообщение · #26

ntldr пишет:
Смотрим --> документацию <-- на random_shuffle

Спасибо конечно за ссылку, но у меня есть стандарт:
Code:
  1. 25.3.12 Random shuffle
  2. template<class RandomAccessIterator>
  3. void random_shuffle(RandomAccessIterator first,
  4. RandomAccessIterator last);
  5.  
  6. template<class RandomAccessIterator, class RandomNumberGenerator>
  7. void random_shuffle(RandomAccessIterator first,
  8. RandomAccessIterator last,
  9. RandomNumberGenerator&& rand);
  10.  
  11. template<class RandomAccessIterator, class UniformRandomNumberGenerator>
  12. void shuffle(RandomAccessIterator first,
  13. RandomAccessIterator last,
  14. UniformRandomNumberGenerator&& g);
  15.  
  16. Remarks: To the extent that the implementation of these functions makes use of random numbers, the
  17. implementation shall use the following sources of randomness:
  18. The underlying source of random numbers for the first form of the function is implementation-defined.
  19. An implementation may use the rand function from the standard C library.
  20. In the second form of the function, the function object rand shall serve as the implementation’s source
  21. of randomness.
  22. In the third shuffle form of the function, the object g shall serve as the implementation’s source of
  23. randomness.


Add:
В голове не много прояснилось, теперь к сути, так как не известен язык написания то задача решается в контексте C и Delphi - rand, srand и randomize, random... vector мной упомянут, так как в delphi есть его аналог TList, а вот аналога random_shuffle там нет, а так можно взять boost и не ипать себе моск.




Ранг: 104.9 (ветеран), 47thx
Активность: 0.040.02
Статус: Участник

Создано: 21 июля 2012 19:36
· Личное сообщение · #27

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


Что мешает сделать проверку на повтор предыдущего числа? Код увеличивается всего на пару строчек.
Начальная задача же стоит, как я понимаю, не в написании самого удачного и не повторяющегося генератора ПСЧ, а в наиболее эффективной сортировке плей-листа, чтобы в нем не было повторов и был максимальный разброс. Конкретно эта задача решается именно упорядочиванием списка по случайному индексу.

| Сообщение посчитали полезным: DimitarSerg

Ранг: 65.3 (постоянный), 10thx
Активность: 0.020
Статус: Участник

Создано: 29 июля 2012 21:49
· Личное сообщение · #28

Ничего себе, напридумывали. Заметили, что тс с 14 июля тут не отписывался?
К вопросу о ГСЧ и shuffle в музыкальном проигрывателе - у меня тоже возникали какие-то мысли относительно алгоритма. Включая очередь с приоритетами, вычисляемыми на основании того, какие песни дослушали до конца, а какие переключили.

Насчет того, что поиск по массиву займет много времени - это просто смешно. Сколько песен надо добавить в плейлист, чтобы поиск по соответствующему массиву занял хотя бы секунду?

Однако, если поставить себе цель сделать случайную выборку без повторов с сохранением истории, наиболее быстрым будет алгоритм, предложенный ARCHANGEL, со сложностью поиска следующей песни - O(1), кратко:
1. M = число песен
2. Случайно выбрать песню из первых M элементов массива
3. Переставить выбранную песню и M-1й элемент массива (нумеруем с 0)
4. Уменьшить M.
5. Проиграть выбранную песню
6. Если M = 0, перейти на 1, иначе на 2.
С точностью до констант, как-то так.

В результате, в конце массива окажется перевёрнутая история, и повторов не будет.

Но кому это надо?)


 eXeL@B —› Программирование —› алгоритмы автовыбора
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати