Dadi da Cambio generatore casuale


10

introduzione

Ti viene dato un generatore di numeri interi casuali con la seguente implementazione

  • La prima chiamata restituisce sempre 1.
  • La seconda invocazione restituisce un numero intero casuale compreso tra 1 e 2.
  • La terza invocazione restituisce un numero intero casuale compreso tra 1 e 3.
  • L'ennesima chiamata restituisce un numero intero casuale compreso tra 1 e n, incluso.

Sulla base della funzione sopra, scrivi un generatore di dadi casuale che sia perfettamente casuale, restituendo un valore compreso tra 1 e 6 (compreso) con uguale probabilità.

Regole

  • Il tuo programma / funzione dovrebbe risultare in un numero intero casuale compreso tra 1 e 6, incluso, in qualche forma utilizzabile, ovvero in output standard o come valore di ritorno della funzione.
  • Il generatore di numeri casuali ascendente sopra può essere definito come una funzione "libera" nel tuo programma (ovvero, non conta per il conteggio dei caratteri) o uno script / programma separato che viene eseguito secondo necessità, supponendo che lo stato ( n) sia persistente tra le chiamate.
  • Supponi che non saranno mai richiesti più di 1000 tiri di dado in un singolo caso del tuo programma e che il generatore di numeri casuali iniziale può essere resettato alla 1fine di 1000 tiri di dado per evitare il trabocco di n.
  • Il tuo programma non può usare nessun'altra fonte di numeri casuali tranne il generatore casuale ascendente sopra definito. Ovviamente puoi richiedere più numeri casuali al generatore di numeri casuali per ogni singolo lancio di dadi.
  • Questo è code-golf, quindi il vincitore è la risposta più breve o la maggior parte dei voti in caso di pareggio. Se riesci a generare 1000 tiri di dado usando meno di 1000 numeri casuali generati, concediti un bonus di efficienza di 10 punti .

Esempio

./asc-rand
1 # random integer between 1 and 1
./asc-rand
1 # random integer between 1 and 2
./asc-rand
3 # random integer between 1 and 3
./asc-rand
4 # random integer between 1 and 4

# dice-gen generates random dice based on output of asc-rand program.
./dice-gen
3
./dice-gen
6
./dice-gen
5
./dice-gen
1

Il programma è iterate(6):b=asc-rand(); print billegale o non funziona? Potrei fraintendere la terza regola.
beary605

@ beary605: il generatore di numeri casuali può essere resettato solo dopo l'intero tiro di 1000 dadi, non tra ogni lancio di dadi. L'unica ragione per cui menziono che si sta occupando di possibili overflow sul valore restituito dal generatore di numeri casuali non è una delle preoccupazioni di questa sfida. Modifica: ho chiarito lo scopo della regola, spero che aiuti.
mellamokb,

Quando dici "numero casuale" intendi "numero intero casuale" o "numero reale casuale (troncato)"? Forse c'è qualche convenzione di cui non sono a conoscenza.
DavidC,

@DavidCarraher: ottimo punto. Intendevo numeri interi casuali e vedo che non è chiaro. Aggiornerò la domanda. Modifica: aggiornato.
mellamokb,

1
Ci è permesso chiedere al randomizzatore quante volte ha generato numeri casuali? Avevo l'impressione di non poterlo fare.
Matt,

Risposte:


2

J - 13 caratteri

Questo fa le stesse ipotesi di Golfscript: che il numero di dadi è in stdin ed elenchiamo i tiri di dadi che devono uscire.

r=:1+?  NB. free random function
r>:i.".1!:1]1

Spiegato dall'esplosione:

r=:1+?           NB. r(x) = 1 + a random number between 0 and n-1
           ]1    NB. input file handle
       1!:1      NB. read in a string
     ".          NB. convert to integer
 >:i.            NB. make a list of numbers, from 1 to that integer
r                NB. apply the random function

Se questo è in qualche modo insoddisfacente, ecco un programma più lungo di 21 caratteri, che può essere chiamato f''per generare numeri casuali, con uno stato e tutto il resto.

r=:1+?  NB. free random function
c=:0
f=:3 :'r c=:1+c'

K analoghi: funzione casuale libera r:{*1_draw x}, versione stdin (10 caratteri) r'1+!. 0:` , versione funzione (14 caratteri) c:0;f:{r@c+:1}chiamata da f[].
Algoritmo di

6

Python, 31 caratteri

Analogamente allo scleaver, definisci il generatore in questo modo:

from random import randint
n=0
def r():
    global n;n+=1
    return randint(1,n)

Quindi una funzione per restituire i tiri di dado:

D=lambda:eval('r(),'*6)[-1]%6+1

Chiama D()ogni volta che hai bisogno di un tiro di dadi uniformemente casuale.


Ah, uso intelligente di eval, mi piace.
scleaver

3

Scala 23

def s={r;r;r;r;r;r%6+1}

Il metodo r può essere (approssimativamente) implementato in questo modo:

var cnt = 0 
val rnd = new util.Random 

def r = {
  cnt %= 1000
  cnt += 1
  rnd.nextInt (cnt)
}

un test approssimativo:

scala> (1 to 6).map (i => ((1 to 600) map (_=>s)).filter (_ == i).size)
res26: scala.collection.immutable.IndexedSeq[Int] = Vector(110, 105, 91, 96, 106, 102)

Ogni sesta chiamata dovrebbe produrre una distribuzione uguale sui 6 valori, quindi lancio 5.


2

GolfScript (15 caratteri)

Ciò presuppone che il numero di rotoli richiesti sia fornito su stdin ed elenca molti risultati su stdout.

# The free increasing random function
0:N;{N):N rand)}:r;

~{r{;r}5*6%)n}*

Demo online

Mentre potrei ottenere il bonus di 10 punti per l'utilizzo di meno di 1000 tiri per generare 1000 numeri, mi costerebbe molto più di 10 caratteri. L'approccio banale di estrarre l'entropia adatta quando N è un multiplo di una potenza di 2 o 3 non è sufficiente perché il numero di risultati disponibili mod 3 è solo 333 + 111 + 37 + 12 + 4 + 1 = 498. Pertanto è necessario adottare un approccio di campionamento e rifiuto. Usando questo approccio puoi ottenere 2242 tiri previsti da 1000 chiamate a r, ma c'è un sovraccarico extra dalla contabilità ed baseè un nome di funzione molto lungo.


5
"ed baseè un nome di funzione molto lungo" Apparentemente non usi Mathematica . Otteniamo meraviglie come NegativeBinomialDistribution, ExponentialGeneratingFunction, MathieuCharacteristicExponent, InverseFourierSequenceTransform, e SemialgebraicComponentInstances. :-)
Mr.Wizard

1

Python 65 63

i=7
while i>5:[R()for x in range(9)];i=int(`R()`[-1])
print i+1

La funzione R()è il randomizzatore crescente.

Uso:

$ ./rollDice.py
3
$ ./rollDice.py
5

Perché non sbarazzarsi del forloop e chiamare Runa volta prima del whileloop?
Keith Randall,

@KeithRandall Il numero che ritorno quando il mio tiro di dadi è l'ultima cifra del numero che il generatore ascendente restituisce. Devo effettuare 10 chiamate al generatore ascendente per garantire pari probabilità a tutte le cifre possibili.
Matt,

Perché 10 chiamate? In linea di principio, se il generatore è casuale, ogni chiamata non dovrebbe offrire la stessa probabilità per una delle (dieci) cifre? Naturalmente, in pratica, ci si può aspettare di avvicinarsi a un numero uguale per ciascuno dei numeri.
DavidC,

@DavidCarraher Il generatore restituisce numeri casuali da 1 a n dove n è il numero di volte che lo hai chiamato. Sto guardando l'ultima cifra di questo numero restituito. Se n non è un multiplo intero di 10 la probabilità non sarà uniforme. Ad esempio: se n = 13 le probabilità verranno suddivise come segue: 1/9 per i tiri 1,5,6 e 2/9 per i tiri 2,3,4
Matt

@Matt: ho pensato che R()stesse restituendo un float e stavi prendendo la cifra meno significativa. Ora che è stato chiarito che R()restituisce un numero intero, ha senso.
Keith Randall,

1

Python, 56

r è definito come:

from random import randint
n=0
def r(z):
    global n;n+=1
    return randint(1,n)

il generatore di dadi d:

import math;d=lambda:math.ceil(6.*r(r(r(r(r(r(0))))))/n)

utilizzo, ad es. per 100 rotoli:

for i in range(100):print d()

probabilmente puoi eliminare il import mathse lo sostituisci math.ceil(...)conint(...)+1
Matt

Vorrei, ma produrrebbe 7 come output possibile.
scleaver

O si. Ho perso questo.
Matt,

mellamokb ha chiarito una domanda che avevo sul randomizzatore ascendente. Non puoi chiedere n.
Matt,

1

Mathematica 51

Il generatore di numeri casuali r, viene ripristinato impostando la variabile globale nsu 1.

n = 1; r[c_] := RandomInteger[{1, c}]

Codice

Non in esecuzione per il codice più breve ...

h := (n++; If[n < 4 \[Or] (y = r@n) > 6 Quotient[n, 6], h, y~Mod~6 + 1])

uso

t = Table[h, {60000}];
n
SortBy[Tally[t], First]

60000 tiri dei dadi hanno richiesto 60031 chiamate a h. Tallymostra la suddivisione per numeri 1-6.

60031

{{1, 9923}, {2, 9966}, {3, 10016}, {4, 10028}, {5, 10009}, {6, 10058}}


1

Perl, 22 o 45

Implementazione del generatore di numeri casuali ascendente:

my $n=0;
sub r { $n++; return 1+int(rand$n); }

Generazione:

#copy of the Scala solution; short code; uses 6N rolls
sub s{r;r;r;r;r;1+r%6}
#more efficient implementation, uses approximately 6+N+lnN rolls
sub roll { do{$a=r-1}while($a>$n-$n%6);return 1+(1+$a)%6 }

Test fuori:

n numero chisquare
1 10001867 0,348569
2 10004853 2.355161
3 9994395 3.141602
4 10000177 0,003133
5 9999227 0.059753
6 9999481 0.026936
T 60000000 5.935154
60000000 tiri di dado hanno richiesto 60000042 chiamate a r e 570.432735 secondi


0

Opcode x86, 15 byte

f:  mov cx, 6
    call r ; return in AX
    loop $-3
    cwd
    div word [f+1]
    inc dx
    ret ; return in DX

Apparentemente questo è un post di bassa qualità?
Muhammad Salman,

0

GolfScript , 8 byte

f;3f*f(-

Provalo online!

Apre il generatore una volta, quindi si libera del risultato. Quindi lancia f2 e lo moltiplica per 3 (3 o 6), quindi sottrae f3-1 (0, 1, 2) che risulta in (3-2, 3-1, 3-0) o (6-2, 6-1, 6-0) W5.

Golfscript e la funzione casuale esistevano prima che questa domanda fosse pubblicata, così come una presentazione legale.

Questa è l'invio solo una volta. Se è necessario eseguirlo più volte in una chiamata,

GolfScript , 12 byte

f;3f*f-)0:i;

Provalo online!

Questo reimposta la mia chiamata a 0, quindi si reimposta di conseguenza. Questo TIO mostra 50 risultati casuali.


0

C (gcc) , 31 byte

f(i){for(i=5;i--;)c;i=~-c%6+1;}

Ogni 6 chiamate, la probabilità di generare un numero compreso tra 1 e 6 compreso è uguale.

cè #defined come una chiamata a una funzione che genera i numeri casuali perfetti.

Provalo online!

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.