PDA

View Full Version : [C]numerosi numeri casuali


keiler
17-04-2007, 19:43
Ciao a tutti,vorrei fare un programma il poker. Solo che mi serve da generare numeri casuali da 1 a 24 e da 0 a 100...Ho provato utilizzando :
srand(time(0));
x =rand() % 24+1;

il problema è che andando in funzione del tempo, e avendo necessità di randomizzare 5 numeri consegutivi, mi vengono tutti numeri uguali. Se invece metto un if impedendo di darmi lo stesso numero mi da' numeri a intervalli di 3 in 3....
Ho provato a vedere la soluzione che davavate su un'altro post, ma non ho capito nulla, e soprattutto il mio problema è che dovendolo portale al professore devo capire il codice....

grazie in anticipo!:D

andbin
17-04-2007, 20:31
Ciao a tutti,vorrei fare un programma il poker. Solo che mi serve da generare numeri casuali da 1 a 24 e da 0 a 100...Quindi devi generare N numeri unici.

Questo è un mio codice di esempio:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct
{
int *values;
int size;
} UNIQUE_RANDOM;

int rand_int (int min, int max)
{
double d;

d = rand () / (RAND_MAX+1.0);
return ((int) (d * (max-min+1))) + min;
}

int UniqueRandom_Init (UNIQUE_RANDOM *ur, int min, int max)
{
int size, i;
int *values;

if (min > max)
return 0;

size = max - min + 1;

values = (int*) malloc (size * sizeof (int));

if (values == NULL)
return 0;

for (i = 0; i < size; i++)
values[i] = min + i;

ur->values = values;
ur->size = size;

return 1;
}

int UniqueRandom_Extract (UNIQUE_RANDOM *ur, int *value_out)
{
int idx;

if (ur == NULL || value_out == NULL || ur->size == 0)
return 0;

idx = rand_int (0, --ur->size);
*value_out = ur->values[idx];
ur->values[idx] = ur->values[ur->size];

return 1;
}

void UniqueRandom_Free (UNIQUE_RANDOM *ur)
{
if (ur != NULL && ur->values)
free (ur->values);
}


/*-- Main di prova --*/
int main (void)
{
UNIQUE_RANDOM ur;
int num;

srand ((unsigned int) time (NULL));

if (UniqueRandom_Init (&ur, -10, 10))
{
while (UniqueRandom_Extract (&ur, &num))
printf ("%d ", num);

printf ("\n");
UniqueRandom_Free (&ur);
}

return 0;
}

keiler
17-04-2007, 23:11
scusa non e' che potresti spiegarmi passaggio per passaggio? che non ci ho capito nulla...innanzitutto cos'e' unique_random? poi io l'int l'ho sempre utilizzato per assegnare una sola variabile, tipo a,b,c,d ecc. mai usando cose tipo:int rand_int (int min, int max)...

non c'e' un metodo un po' piu' semplice? grazie lo stesso!

cionci
18-04-2007, 00:36
Quella è una funzione...sai cosa sono le funzioni ?

keiler
18-04-2007, 08:08
se devo essere sincero mai fatte.......
per questo ho bisogno di qualche spiegazioncina in piu' ^^....

andbin
18-04-2007, 10:25
scusa non e' che potresti spiegarmi passaggio per passaggio? che non ci ho capito nulla...innanzitutto cos'e' unique_random? poi io l'int l'ho sempre utilizzato per assegnare una sola variabile, tipo a,b,c,d ecc. mai usando cose tipo:int rand_int (int min, int max)...Purtroppo non è facile (e non è breve) spiegare il tutto se non hai conoscenze chiare e precise su cosa sono le strutture, le funzioni, ecc....

Per poter generare N numeri casuali unici (che non si ripetano) c'è un modo molto semplice, adesso ti spiego il concetto tramite un esempio.

Si vuole generare numeri casuali unici compresi tra 10 e 15 (inclusi). Si crea innanzitutto un array di 6 elementi:
0 1 2 3 4 5 <-- indice
+----+----+----+----+----+----+
| 10 | 11 | 12 | 13 | 14 | 15 |
+----+----+----+----+----+----+A questo punto bisogna generare un numero casuale compreso tra 0 e 5 (inclusi). Supponiamo venga generato il numero 2. In valore all'indice 2 è il 12, pertanto il primo numero casuale unico è il 12.

A questo punto l'array è da "accorciare" dal punto di vista logico. Si prende l'ultimo elemento (il 15) e lo si mette nel "buco" rimasto libero dal numero 12 appena estratto. L'array diventa così:
0 1 2 3 4 5
+----+----+----+----+----+----+
| 10 | 11 | 15 | 13 | 14 |////|
+----+----+----+----+----+----+Ora bisogna generare un numero casuale compreso tra 0 e 4 (inclusi) ..... e la cosa continua allo stesso modo di prima fino a quando ci sono elementi nell'array.

Chiaro adesso? Io nel mio esempio di codice che ho postato ho sviluppato la cosa in modo da poterla rendere abbastanza riutilizzabile. Ho creato una struttura che permette di gestire questo array "particolare" e 3 funzioni che operano su questa struttura. Una funzione per inizializzare la struttura, una per estrarre i valori e una per terminare l'utilizzo della struttura (fa una free di ciò che è stato allocato).

Nulla di trascendentale .... ma il concetto comunque è quello che ho appena spiegato. Poi sei libero di implementarlo come meglio credi.

cionci
18-04-2007, 11:17
Posso provare a fartela un po' più semplice e senza funzioni, magari non hai visto nemmrno le liste...vediamo:

int estratti[NUMERO_ELEMENTI];
int numero_estrazioni = 0;
int estratto;


Per ogni estrazione devi fare:

/* estraggo un numero fra 0 e (NUMERO_ELEMENTI - numero_estrazioni - 1) */
estratto = (((double)rand()) / (RAND_MAX + 1)) * (NUMERO_ELEMENTI - numero_estrazioni);
numero_estrazioni++;

for(i = 0; i <= estratto; i++)
if(estratti[i] != 0)
estratto++;

/* setto a 1 l'elemento corrispondente nel vettore estratti in modo da rendere impossibile l'estrazione dell'elemento nelle prossime estrazioni */
estratti[estratto] = 1;

In estratto hai il numero corretto...
Questa è una versione semplificata, per farti capire meglio cosa fa quello che ti ho scritto sopra:

/*l'avresti anche potuto scrivere come: */
estratto = rand() % (NUMERO_ELEMENTI - numero_estrazioni);
/* ma così come l'ho scritto sopra mantengo l'equiprobabilità.
In pratica diminuisco l'intervallo di estrazione di uno per ogni estrazione effettuata, perchè di fatto gli elementi da scegliere sono diminuiti */

numero_estrazioni++;

/*il ciclo avresti potuto scriverlo anche così: */
for(i = 0; i < NUMERO_ELEMENTI; i++)
if(estratti[i] != 0 && i <= estratto)
estratto++;

estratti[estratto] = 1;

In pratica incremento il numero estratto per ogni numero già estratto minore del suo valore attuale, questo serve per riportare il numero estratto nell'intervallo originale:
- mettiamo che NUMERO_ELEMENTI sia 10
- dopo la prima estrazione estraggo il numero 1, il ciclo non trova alcun elemento già estratto, setto a 1 estratti[1]
- la seconda estrazione sarà fra 0 e 9
- estraggo 3, 3 deve individuare il quarto numero che non è stato ancora estratto (si parte da zero, quindi zero, uno, due, tre)
- eseguo il ciclo e quando i == 1, trovo la casella segnata ed incremento estratto a 4, infatti il 4 è il quarto numero che non è stato ancora estratto (zero, uno è stato estratto, due, tre, quattro)
E così via per ogni estrazione...

Ad esempio il vettore estratti è fatto così:
NUMERO_ELEMENTI = 10

Estratti è fatto così:
0 1 2 3 4 5 6 7 8 9
1 1 1 1 0 0 1 0 1 0

Quindi abbiamo estratto 6 numeri...

L'estrazione avviene fra 0 e (NUMERO_ELEMENTI - numero_estrazioni - 1), cioè fra 3 (10 - 6 -1). Estraggo 2 (il terzo elemento non estratto).

Ecco cosa avviene nel ciclo:

i = 0 --> estratti[0] è 1, 0 <= estratto: estratto++, quindi 3
i = 1 --> estratti[1] è 1, 1 <= estratto: estratto++, quindi 4
i = 2 --> estratti[2] è 1, 2 <= estratto: estratto++, quindi 5
i = 3 --> estratti[3] è 1, 3 <= estratto: estratto++, quindi 6
i = 4 --> estratti[4] è 0: quindi non incremento estratto
i = 5 --> estratti[5] è 0: quindi non incremento estratto
i = 6 --> estratti[6] è 1, 6 <= estratto: estratto++, quindi 7
i = 7 --> estratti[7] è 0: quindi non incremento estratto
i = 8 --> 8 non <= estratto: quindi non incremento estratto
i = 9 --> 8 non <= estratto: quindi non incremento estratto

estratto è quindi 7, che corrisponde appunto al terzo elemento libero nel vettore degli estratti ;)
Setto a 1 l'elemento corrispondente e sono pronto a poter utilizzare il numero che ho estratto...

Nel ciclo che ho scritto per primo evito di fare le ultime due iterazioni del ciclo.
Ovviamente se vuoi ricominciare l'estrazione dall'inizio devi azzerare il vettore estratti e mettere numero_estrazioni a 0.

Ziosilvio
18-04-2007, 12:21
se devo essere sincero mai fatte.......
per questo ho bisogno di qualche spiegazioncina in piu' ^^....
Senti, non è che le nostre spiegazioni possono essere sufficienti se tu non studi.

keiler
18-04-2007, 14:32
Non è che non studio...è che a scuola ci siamo fermati al ciclo for....(sto alle superiori) :P e siccome ero riuscito a fare il filetto volevo provare qualcosa di più complicato e pensavo che la generazione di numeri casuali fosse molto più semplice. Comunque ringrazio tutti, più o meno ho capito il ragionamento...ora vedo di andarmi a vedere le cose che ancora non so...grazie ancora ^^

Ziosilvio
18-04-2007, 15:16
Non è che non studio...è che a scuola ci siamo fermati al ciclo for....(sto alle superiori)
Allora ti chiedo scusa.

keiler
18-04-2007, 15:40
vabbeh tranquillo! ^^
Sono io che pretendo un po' troppo! :P
Comunque ultima domandina...Visto che a scuola non si fa niente... mi sono comprato un libro di c++, mi conviene iniziare con quello o meglio che faccio ancora un bel po' di c prima di passare al c++?

Ziosilvio
18-04-2007, 19:44
Visto che a scuola non si fa niente
Il che, peraltro, è il vero problema della scuola italiana.
Potenzialmente, si potrebbe fornire una preparazione paragonabile almeno a quella di un primo anno di università all'estero.
Solo che, se non si fanno lavorare gli alunni, questo è impossibile.
mi sono comprato un libro di c++
Spero non sia lo Schildt.
mi conviene iniziare con quello o meglio che faccio ancora un bel po' di c prima di passare al c++?
Io suggerisco di fare bene il C, che hai già iniziato e che devi studiare per la scuola. Poi, semmai, passerai a qualcos'altro.
Visto che voglia di lavorare ne hai, prendi pure il Kernighan&Ritchie che è il punto di riferimento di tutti i programmatori C seri.

oNaSsIs
18-04-2007, 22:59
Volevo fare i complimenti a andbin per l'algoritmo che ha usato per generare numeri casuali diversi...molto utile e semplice...non lo conoscevo... :D