Come faccio a produrre "piacevolmente" casualmente, al contrario di pseudo-casuali?


26

Sto realizzando un gioco che presenta una serie di diversi tipi di puzzle in sequenza. Scelgo ogni puzzle con un numero pseudocasuale. Per ogni puzzle, ci sono diverse varianti. Scelgo la variazione con un altro numero pseudocasuale. E così via.

Il fatto è che, mentre questo produce casualità quasi vera, questo non è ciò che il giocatore vuole davvero. Il giocatore in genere vuole ciò che percepisce e si identifica come casuale, ma solo se non tende a ripetere i puzzle. Quindi, non è davvero casuale. Imprevedibile.

Ripensandoci, posso immaginare modi bizzarri di farlo. Ad esempio, eliminando temporaneamente le più recenti N scelte dall'insieme di possibilità quando si seleziona una nuova scelta. O assegnando ad ogni scelta un'eguale probabilità, riducendo la probabilità di una scelta a zero sulla selezione e quindi aumentando lentamente tutte le probabilità ad ogni selezione.

Suppongo che ci sia un modo stabilito per farlo, ma non conosco la terminologia, quindi non riesco a trovarlo. Qualcuno sa? O qualcuno ha risolto questo in modo piacevole?


4
Il libro "AI Game Programming Wisdom 2" ha un capitolo sulla casualità filtrata che, da quello che ricordo, è praticamente esattamente quello che stai cercando. Al momento non ce l'ho, quindi non posso davvero darti una risposta completa.
Anton,

Per cercare di chiarire: quando dici "non ripetere i puzzle", vuoi dire che non vuoi semplicemente due puzzle dello stesso tipo uno accanto all'altro? Quindi, in altre parole, se hai appena scelto un sudoku, non offrire un altro puzzle di sudoku, ma se fosse Sudoku # 19, allora va bene offrire Picross # 19 successivo (in altre parole, il numero di variazione non ha importanza) ?
Steven Stadnicki,


1
OK, la mia copia di AI Game Programming Wisdom 2 è appena arrivata. Ho letto il capitolo sulla casualità filtrata e ho verificato il codice sorgente. Questo è probabilmente l'approccio migliore. Mi permette di usare solo numeri casuali, ma poi filtrare i numeri in modo che non si verifichino schemi imprevisti. Sembra più a prova di proiettile rispetto alla borsa shuffle.
Hilton Campbell

1
Ancora un altro aggiornamento ... per la mia particolare applicazione, la casualità filtrata non lo ha fatto del tutto. Voglio davvero che il giocatore giochi attraverso tutti i tipi e sottotipi prima di ripetere, quindi sono andato con una borsa shuffle.
Hilton Campbell,

Risposte:


25

Se hai un numero finito di puzzle, puoi:

  • Costruisci un elenco di enigmi, tutti o alcuni scelti casualmente;
  • Mischia questo elenco (vedi Knuth Shuffle per esempio);
  • Lascia che il tuo giocatore giochi attraverso questo elenco;
  • Quando l'elenco è vuoto, inizia con uno nuovo.

MODIFICARE

Non lo sapevo, ma navigare su SE mi ha fatto capire che questo è in realtà noto come "shuffle bag". Altre informazioni qui , qui o .

MODIFICA 2

Il classico Knuth Shuffle va così:

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]

Steven Stadnicki ha giustamente sottolineato nel suo commento che questo genere di cose non impedisce la ripetizione di un rimpasto. Un modo per tenerne conto è aggiungere un caso speciale per l'ultimo elemento:

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
Questo può funzionare ma devi fare un po 'di attenzione se rimetti in ordine dopo ogni playthrough per non iniziare con lo stesso oggetto su cui sei finito.
Steven Stadnicki,

@Steven Indeed. Questo articolo potrebbe essere escluso dal nuovo elenco. In realtà, potrebbe essere un'idea costruire un elenco di pochi elementi casuali e costruire l'elenco successivo con solo gli elementi rimanenti. Quindi, se hai 100 oggetti, costruisci ad esempio un elenco mescolato di 10. Quando hai finito con questo elenco, costruisci il prossimo con 10 oggetti nei 90 che non erano stati scelti in precedenza.
Laurent Couvidou,

+1. Il supporto aggiunto per questa tecnica è "più divertente": è così che Tetris, ad esempio, produce pezzi "casuali". Una serie di uno di ciascun pezzo viene mescolata e ripetuta, evitando le lunghe sequenze di duplicati che la vera casualità produrrebbe inevitabilmente.
KutuluMike,

1
@Hilton Tendo a non apprezzare questo tipo di approccio "while loop while random mi dà quello che voglio" ... Non molto probabilmente ciò causerà problemi. Tuttavia, ho sempre la sensazione che si tratti di una chiamata per loop infiniti casuali o calo delle prestazioni, che sono terribili per il debug. Escludendo l'ultimo elemento dell'elenco precedente da quello nuovo, puoi mescolare una sola volta, per lo stesso risultato.
Laurent Couvidou,

1
Hai ragione, e avevo le stesse riserve. Invece di escludere l'ultimo elemento precedente, ora lo faccio solo mescolare una volta, quindi se l'ultimo elemento precedente è ora il primo, lo cambio con qualche altro oggetto in modo casuale.
Hilton Campbell,

2

Una variante dell'approccio di lorancou: per ogni tipo di puzzle, tenere una serie di numeri (mescolati) di puzzle; quindi ogni volta che colpisci un puzzle di quel tipo, togli il numero successivo dalla lista. per esempio, supponiamo che tu abbia dei puzzle di Sudoku, Picross e Kenken, ognuno con i puzzle # 1..6. Creeresti tre matrici mischiate dei numeri 1..6, una per ogni tipo di puzzle:

  • Sudoku: [5, 6, 1, 3, 4, 2]
  • Picross: [6, 2, 4, 1, 3, 5]
  • KenKen: [3, 2, 5, 6, 4, 1]

Ora, mescolerai i tipi di puzzle proprio come suggerisce lorancu; diciamo che arriva [Picross, Sudoku, Kenken]. Quindi ogni volta che colpisci un puzzle di un determinato tipo, usa il numero successivo nella sua "lista casuale"; nel complesso la presentazione del tuo puzzle sarebbe [Sudoku # 5, Picross # 6, Kenken # 3, Sudoku # 6, Picross # 2, Kenken # 2, ...]

Se non vuoi mantenere i puzzle nello stesso ordine generale ogni volta che esegui il ciclo, penso che la tua opzione "scegli in modo casuale, ignorando le ultime scelte" sia la migliore. Ci sono modi per renderlo anche un po 'più efficiente; ad esempio, supponiamo che tu abbia 20 cose e desideri ignorare le ultime 5 scelte. Quindi invece di scegliere in modo casuale un numero 1..20 e 'rilanciare' fino a quando non ne ottieni uno al di fuori degli ultimi 5, scegli semplicemente un numero 1..15 e cammina attraverso i tuoi tipi di puzzle in molti passaggi, semplicemente saltando qualsiasi tipo di puzzle che è è stato scelto (puoi farlo facilmente mantenendo un array di bit che contiene gli ultimi 5 puzzle scelti).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.