Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C# / VB.NET - di nuovo problemi coi numeri casuali
Forum - C# / VB.NET - di nuovo problemi coi numeri casuali - Pagina 3

Pagine: [ 1 2 3 4 ] Precedente | Prossimo
Avatar
ZioCrocifisso (Member)
Pro


Messaggi: 135
Iscritto: 06/03/2013

Segnala al moderatore
Postato alle 18:08
Mercoledì, 15/01/2014
Non devi creare e conservare il risultato di Random, ma l'oggetto Random stesso. Il motivo è che esso non restituisce realmente numeri casuali, ma pseudocasuali, che vengono ottenuti tramite una formula: questa genera una sequenza di numeri in base a un seed, che su Random è il tempo (ma puoi deciderlo tu). Se crei diverse istanze di Random nello stesso istante, queste avranno lo stesso seed e genereranno le stesse sequenze di numeri, e poiché prendi solo il primo numero di quella sequenza (Next, come si può intuire dal nome, prende il prossimo numero), visto che stai usando istanze diverse, sarà sempre lo stesso.

Ultima modifica effettuata da ZioCrocifisso il 15/01/2014 alle 18:09
PM Quote
Avatar
Dice (Normal User)
Expert


Messaggi: 238
Iscritto: 26/11/2011

Segnala al moderatore
Postato alle 18:34
Mercoledì, 15/01/2014
Ho provato a fare così:

Codice sorgente - presumibilmente C++

  1. public class Dado
  2.     {
  3.         private int risultato;      //risultato del lancio del dado
  4.        
  5.        Random rnd;
  6.  
  7.         //costruttore
  8.         public Dado()
  9.         {
  10.             rnd = new Random();
  11.             //invoco il metodo per il lancio del dado
  12.             this.LancioDado();
  13.         }
  14.         //metodo per lanciare il dado
  15.         public void LancioDado()
  16.         {
  17.             //ottengo un numero casuale tra 1 e 6
  18.             risultato = rnd.Next(1, 7);
  19.         }
  20.         //proprietà per far ritornare il risultato del lancio del dado
  21.         public int Risultato
  22.         {
  23.             get { return risultato; }
  24.         }
  25.     }



Ma mi da ancora i numeri sempre uguali :(

PM Quote
Avatar
ZioCrocifisso (Member)
Pro


Messaggi: 135
Iscritto: 06/03/2013

Segnala al moderatore
Postato alle 18:46
Mercoledì, 15/01/2014
Hai lasciato i cambiamenti inutili di prima (riguardo al risultato), quindi non so come lo usi adesso LanciaDado. Posta anche il codice con cui lo usi.
Comunque dovresti sforzarti di capire come funziona, invece di chiedere cosa cambiare senza capirci niente, altrimenti riavrai lo stesso problema in futuro.

PM Quote
Avatar
Dice (Normal User)
Expert


Messaggi: 238
Iscritto: 26/11/2011

Segnala al moderatore
Postato alle 20:03
Mercoledì, 15/01/2014
Per caso quello che sbaglio è che calcolo il risultato del lancio fuori dal costruttore?
Devo mettere anche il calcolo del risultato nel costruttore ed eliminare il metodo LanciaDado?

PM Quote
Avatar
ZioCrocifisso (Member)
Pro


Messaggi: 135
Iscritto: 06/03/2013

Segnala al moderatore
Postato alle 20:27
Mercoledì, 15/01/2014
...

PM Quote
Avatar
tuttodiMC (Normal User)
Expert


Messaggi: 327
Iscritto: 29/10/2012

Segnala al moderatore
Postato alle 21:47
Mercoledì, 15/01/2014
Potresti provare a creare tu un generatore di numeri pseudocasuali in modo da gestire meglio il tutto.
Per esempio potresti provare una cosa simile

Codice sorgente - presumibilmente Plain Text

  1. risultato = rnd.Next(1,101) % 6;



Ma mettendo al posto di quel 6 una variabile di un ciclo for che viene incrementata in continuazione, in questo modo avrai per forza numeri diversi.

Ultima modifica effettuata da tuttodiMC il 15/01/2014 alle 21:55
PM Quote
Avatar
Ultimo (Member)
Guru


Messaggi: 883
Iscritto: 22/05/2010

Segnala al moderatore
Postato alle 9:52
Giovedì, 16/01/2014
Come ti è stato detto è normale che ti escano i numeri uguali, perchè i 5 lanci vengono effettuati praticamente
nello stesso istante, quindi il seed(seme) della funzione Random che genera una sequenza pseudocasuale sarà
sempre lo stesso.
Quindi per risolvere il problema o fai trascorrere del tempo tra un lancio e l'altro, oppure nella classe Dado
inserisci un Array che rappresenti le sei facce del Dado, e nel costruttore della classe avvii una procedura
che ne mischia il suo ordine, in modo tale da avere sempre delle sequenze diverse.

Una soluzione semplice:

Codice sorgente - presumibilmente C++

  1. using System;
  2.  using System.Collections.Generic;
  3.  using System.Linq;
  4.  using System.Text;
  5.  
  6. namespace APP_Lancio_del_Dado
  7. {
  8.     class Program
  9.     {
  10.        
  11.  
  12.         static void Main(string[] args)
  13.         {
  14.  
  15.         int risultato1 = 0;
  16.         int risultato2 = 0;
  17.         int risultato3 = 0;
  18.         int risultato4 = 0;
  19.         int risultato5 = 0;
  20.        
  21.             //istanzio un'oggetto della classe Dado
  22.             Dado dado = new Dado();
  23.  
  24.     while (true)
  25.         {
  26.         //lancio i dadi e memorizzo i risultati
  27.         risultato1 = dado.LancioDado();
  28.         System.Threading.Thread.Sleep(300);
  29.         risultato2 = dado.LancioDado();
  30.         System.Threading.Thread.Sleep(300);
  31.         risultato3 = dado.LancioDado();
  32.         System.Threading.Thread.Sleep(300);
  33.         risultato4 = dado.LancioDado();
  34.         System.Threading.Thread.Sleep(300);
  35.         risultato5 = dado.LancioDado();
  36.         System.Threading.Thread.Sleep(300);
  37.         //stampo i risultati
  38.         Console.WriteLine(" Risultato dei 5 Lanci del Dado:  ");
  39.         Console.WriteLine("  " + risultato1 + " " + risultato2 + " " + risultato3 + " " + risultato4 + " " + risultato5 + "\n\n");
  40.  
  41.         Console.ReadKey();          
  42.     }
  43.         }
  44.  
  45.         /// <summary>
  46.         /// Oggetto Dado
  47.         /// </summary>
  48.         public class Dado
  49.         {
  50.             private int risultato;      //risultato del lancio del dado
  51.  
  52.             Random rnd;
  53.  
  54.             //costruttore
  55.             public Dado()
  56.             {
  57.                 rnd = new Random();
  58.  
  59.                 risultato = 0;
  60.             }
  61.             //metodo per lanciare il dado
  62.             public int LancioDado()
  63.             {
  64.                 rnd = new Random();
  65.                 //ottengo un numero casuale tra 1 e 6
  66.                 risultato = rnd.Next(1, 7);
  67.  
  68.                 return risultato;
  69.             }
  70.          
  71.            
  72.         }
  73.  
  74.     }
  75. }


Ultima modifica effettuata da Ultimo il 16/01/2014 alle 10:32


If ok Then GOTO Avanza else GOTO Inizia

PM Quote
Avatar
ZioCrocifisso (Member)
Pro


Messaggi: 135
Iscritto: 06/03/2013

Segnala al moderatore
Postato alle 12:03
Giovedì, 16/01/2014
Testo quotato

Postato originariamente da tuttodiMC:

Potresti provare a creare tu un generatore di numeri pseudocasuali in modo da gestire meglio il tutto.
Per esempio potresti provare una cosa simile

Codice sorgente - presumibilmente Plain Text

  1. risultato = rnd.Next(1,101) % 6;



Ma mettendo al posto di quel 6 una variabile di un ciclo for che viene incrementata in continuazione, in questo modo avrai per forza numeri diversi.


Non c'è bisogno di fare tutto ciò, perché, come dico dal primo post, Random genera una sequenza di numeri pseudocasuali. Basta un solo Random con qualunque seme, esso potrà generare numeri pseudocasuali in qualunque momento. Facendo come ha fatto lui e come stai facendo tu, Random viene usato male, perché si prende solo il primo numero da diversi Random (creati nello stesso istante nel caso del suo programma, e quindi con lo stesso seme).

Per fare un esempio, un PRNG (generatore di numeri pseudocasuali) molto semplice è lo LCG (non è quello usato da .NET), la cui formula è (a*x+c)%m, dove a, c ed m sono costanti a piacere (da cui dipende l'efficienza dell'algoritmo), e x è il numero precedentemente generato. Scegliendo per esempio le costanti usate da glibc, e come seme (che è il primo x) 1389869749 (tempo UNIX):
Codice sorgente - presumibilmente Plain Text

  1. > lcg' 1389869749
  2. 1572590922
  3. > lcg' 1572590922
  4. 3845295291
  5. > lcg' 3845295291
  6. 1359549912
  7. > lcg' 1359549912
  8. 43404593


Dunque, con lo stesso seed verrà generata la stessa sequenza.

Scegliendo un seed simile (UNIX time qualche secondo dopo):
Codice sorgente - presumibilmente Plain Text

  1. > lcg' 1389869760
  2. 826356729
  3. > lcg' 826356729
  4. 1110388542
  5. > lcg' 1110388542
  6. 3597676959


(per fare questi esempi ho usato Haskell e GHCi, ma non importa, ho semplicemente fatto una funzione con la formula dello LCG)

I numeri sono dunque completamente diversi, dunque scegliendo ogni volta un seed diverso (come ha fatto Ultimo) effettivamente funziona, ma non è realmente necessario (è complicato e fa rallentare il programma per via degli sleep), visto che, come si può vedere in entrambi casi, basta un primo seed per generare poi numeri diversi. Quello che viene fatto alla creazione di Random() è scegliere come seed il tempo, mentre Next utilizza la formula (non questa, ma il concetto è lo stesso) per ottenere il prossimo numero in base al seed (se è il primo numero) o al numero generato precedentemente.

PM Quote
Pagine: [ 1 2 3 4 ] Precedente | Prossimo