Як я можу створювати "приємно" випадкові, на відміну від псевдовипадкових?


26

Я створюю гру, яка представляє кілька різних головоломок послідовно. Я вибираю кожну головоломку з псевдовипадковим числом. Для кожної головоломки існує ряд варіацій. Я вибираю варіант з іншим псевдовипадковим числом. І так далі.

Справа в тому, що, хоча це створює майже справжню випадковість, це не те, що гравця насправді хоче. Гравець, як правило, хоче те, що вони сприймають, і визначає як випадкове, але тільки якщо він не має тенденції повторювати головоломки. Отже, не дуже випадково. Просто непередбачувано.

Даючи йому якусь думку, я можу уявити собі хиткі способи зробити це. Наприклад, тимчасово виключивши останні N вибір з набору можливостей при виборі нового вибору. Або призначити кожному вибору рівну ймовірність, зменшуючи ймовірність вибору до нуля при відборі, а потім повільно збільшуючи всі ймовірності при кожному виділенні.

Я припускаю, що існує усталений спосіб зробити це, але я просто не знаю термінології, тому я не можу її знайти. Хтось знає? Або хтось вирішив це приємно?


4
У книзі "Ігри Програмування Ігор Мудрості 2" є розділ про відфільтровану випадковість, яка, наскільки я пам’ятаю, в значній мірі саме те, що ви шукаєте. Наразі у мене цього немає, хоча я не можу реально дати тобі повну відповідь.
Антон

Щоб спробувати уточнити: коли ви говорите «не повторювати пазли», ви маєте на увазі, що вам просто не потрібні дві загадки одного типу поруч? Інакше кажучи, якщо ви тільки що вибрали судоку, не пропонуйте ще одну головоломку судоку, але якщо це був судоку №19, тоді пропонувати Picross №19 наступний (іншими словами, номер варіанта не має значення) ?
Стівен Стадницький

2
Дуже пов’язане питання: stackoverflow.com/questions/910215/…
Кріс Берт-Браун

1
Гаразд, моя копія програми AI Game Programming Wisdom 2 щойно прибула. Я прочитав розділ про відфільтровану випадковість і перевірив вихідний код. Це, мабуть, найкращий підхід. Це дозволяє мені просто використовувати випадкові числа, але потім фільтрувати числа, щоб не виникало несподіваних зразків. Це здається більш стійким до кулі, ніж сумка.
Хілтон Кемпбелл

1
Ще одне оновлення ... для моєї конкретної програми відфільтрована випадковість не зовсім цього зробила. Я дуже хочу, щоб гравець грав перед усіма типами і підтипами перед повторенням, тому я пішов з мішком перетасування.
Хілтон Кемпбелл

Відповіді:


25

Якщо у вас є загальна кількість головоломок, ви можете:

  • Створіть список головоломок, будь-яких із них або декількох випадково вибраних;
  • Перемішайте цей список (див., Наприклад, змішування Кнута );
  • Нехай ваш гравець грає через цей список;
  • Коли список порожній, почніть з нового.

EDIT

Я цього не знав, але переглядаючи SE, я дав мені зрозуміти, що це насправді відоме як "мішок перетасування". Дещо більше тут , тут чи там .

EDIT 2

Класичний Knuth Shuffle йде таким чином:

To shuffle an array a of n elements (indices 0..n-1):
    for i from n  1 down to 1 do
        j  random integer with 0  j  i
        exchange a[j] and a[i]

Стівен Стадницький справедливо зазначив у своєму коментарі, що подібні речі не перешкоджають повторенню в перестановці. Спосіб врахувати це - додати спеціальний регістр для останнього елемента:

To reshuffle an array a of n elements and prevent repetitions (indices 0..n-1):
    return if n <= 2

    // Classic Knuth Shuffle for all items *except* the last one
    for i from n  2 down to 1 do
        j  random integer with 0  j  i
        exchange a[j] and a[i]

    // Special case for the last item
    // Exchange it with an item which is *not* the first one
    r  random integer with 1  r  n - 1
    exchange a[r] and a[n - 1]

1
Це може спрацювати, але вам потрібно бути трохи обережними, якщо ви повторно змінюєте команду після кожного проходження, щоб не починати з того самого предмета, на якому закінчили.
Стівен Стадницький

@ Справді дійсно. Цей елемент може бути виключений із нового списку. Насправді, може бути ідеєю скласти список лише декількох випадкових елементів та створити наступний список лише з пунктами, що залишилися. Отже, якщо у вас є 100 предметів, складіть, наприклад, перетасований список з 10. Після закінчення цього списку побудуйте наступний з 10 предметів у 90, які раніше не були вибрані.
Лоран Кувіду

+1. Додана підтримка, щоб ця методика була "веселішою": ось так, наприклад, "Тетріс" випускає "випадкові" твори. Набір по одному з кожного твору переміщується та повторюється, що дозволяє уникнути довгих послідовностей дублікатів, які справжня випадковість неминуче створювала б.
KutuluMike

1
@Hilton Я схильний не подобатися такому підходу "поки цикл, поки випадковий дає мені те, що я хочу" ... Не дуже ймовірно, що це спричинить якісь проблеми. Але все одно, я завжди відчуваю, що це заклик до випадкових нескінченних циклів або крапель продуктивності - які жахливо налагоджувати. Виключення останнього пункту попереднього списку з нового дозволяє переміщувати переміщення лише один раз, для того ж результату.
Лоран Кувіду

1
Ви маєте рацію, і у мене були такі ж застереження. Замість того, щоб виключати попередній останній елемент, у мене зараз його просто перемішують один раз, а якщо попередній останній елемент зараз перший, я поміняю його випадково на якийсь інший предмет.
Хілтон Кемпбелл

2

Варіант підходу lorancou: для кожного типу головоломки зберігайте масив (перетасованих) головоломки; то кожного разу, коли ви потрапляєте на загадку такого типу, отримуйте наступне число зі списку. Наприклад, скажімо, у вас є головоломки Судоку, Пікросс та Кенкен, у кожній із яких є пазли №1..6. Ви б створили три перетасованих масиви чисел 1..6, по одному для кожного типу головоломки:

  • Судоку: [5, 6, 1, 3, 4, 2]
  • Пікрос: [6, 2, 4, 1, 3, 5]
  • КенКен: [3, 2, 5, 6, 4, 1]

Тепер ви перетасувати типи головоломок так, як пропонує Лоранку; скажімо, це з'являється [Picross, Sudoku, Kenken]. Потім кожен раз, коли ви потрапляєте на головоломку заданого типу, використовуйте наступне число у його списку "перетасувати"; загалом ваша головоломна презентація складе [Судоку №5, Пікросс # 6, Кенкен №3, Судоку №6, Пікросс №2, Кенкен №2, ...]

Якщо ви не хочете тримати головоломки у тому самому загальному порядку кожного разу через цикл, я вважаю, що ваш варіант "вибір випадковим чином, ігнорування останніх кількох виборів" є найкращим. Є також способи зробити це трохи ефективнішим; Наприклад, скажімо, що у вас є 20 речей, і ви хочете ігнорувати останні 5 обраних. Тоді замість випадкового вибору числа 1..20 та «перекручування», поки не з’явиться одне поза останніх 5, замість цього просто виберіть число 1..15 і пройдіться через ваші головоломки на багато кроків, просто пропустивши будь-який тип головоломки Ви вибрали (це можна зробити легко, зберігаючи невеликий масив, який містить 5 останніх вибраних головоломок).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.