Correttezza programma.

di il
17 risposte

Correttezza programma.

Salve a tutti, chiedo nuovamente scusa per il distrurbo ma avrei un dubbio circa la correttezza di questo programma che dovrebbe simulare il lancio di 2 monete le funzioni di quest'ultime sono gestite tramite le classi. Si vince quando una delle 2 monete fa 3 volte consecutive Testa o Croce. Però da come è strutturato il codice la moneta, che sia la prima o la seconda, vince se e solo se fa 3 volte Testa se fa 3 volte Croce quest'ultima non viene considerata come vittoria o anche compilato e la moneta vince sempre e solo con 3 vv Testa quando fa 3 vv Croce mai

Qui vi sono i codici e il relativo header della moneta:

#include <iostream>
#include "moneta.h"

using namespace std;


int main()
{
    //numero di volte consecutive per testa o croce 
   const int GOAL = 3;

         int cont1 = 0, //contatore testa o croce
             cont2 = 0;

   Moneta moneta1; //due monete, vedi class moneta
   Moneta moneta2;
      
   srand(time(0));
 
  //finche' sia la prima che la seconda moneta non hanno fatto 
  //una sequenza di tre testa o croce consecutivi
   while (cont1 < GOAL && cont2 < GOAL) 
      {
         moneta1.effettuaLancio(); // lancio
         moneta2.effettuaLancio();

         cout << "Moneta 1: " << moneta1; // overloading operatore << 
         cout << "Moneta 2: " << moneta2 << endl;

         if (moneta1.getFaccia() == 'T')
             cont1++;
         else
             cont1 = 0;
         
         cont2 = (moneta2.testa() ? cont2+1 : 0); // operatore condizionale, testa
      }

   if (cont1 < GOAL)
      cout << "Vince la moneta 2";
   else 
    if (cont2 < GOAL)
      cout << "Vince la moneta 1";
    else
      cout << "Pari!";
            
   cout << endl;

   //system("PAUSE"); sui sistemi windows OK 
} // end main()





#include <iostream>
#include "moneta.h"
#include <cstdlib>


Moneta::Moneta()
{
    effettuaLancio(); 
}

void Moneta::effettuaLancio ()
   {
     short faccia = (short) (rand()%2);

      if (faccia == 0) 
	ultimaFaccia = 'T';
      else ultimaFaccia = 'C';
   }

bool Moneta::testa() const
   {
//      ultimaFaccia = 'C'; // darebbe errore in fase di compilazione, il metodo e' const
      if (ultimaFaccia == 'T')
         return true;
      else 
         return false;
   }
   
bool Moneta::croce() const
   {
      return  !testa();
   }
   
char Moneta::getFaccia () const
   {
      return  ultimaFaccia;
   }
   
      
ostream &operator<< (ostream &stream, Moneta m)
   {
      if (m.ultimaFaccia == 'T')
           stream << "TESTA" << endl;
      else
           stream << "CROCE\n";
      return stream;     
   }
   

#ifndef MONETA_H
#define MONETA_H

#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;


//************
class Moneta {
//************

public:  

   Moneta(); 
   
   void effettuaLancio();

   bool testa() const; //indica al compilatore che il metodo testa() non modifichera' lo stato dell'oggetto
 
   bool croce() const;

   char getFaccia() const;

   friend ostream &operator<< (ostream &stream, Moneta m);
   

private: 
        
   char ultimaFaccia;

};   // end class Moneta

#endif

17 Risposte

  • Re: Correttezza programma.

    È perché aumenti i contatori solo se esce testa.
  • Re: Correttezza programma.

    Alexv ha scritto:


    È perché aumenti i contatori solo se esce testa.
    Ho cambiato così l'operatore condizionale ho fatto alcuni test e ora funziona.
    
    #include <iostream>
    #include "moneta.h"
    
    using namespace std;
    
    
    int main()
    {
        //numero di volte consecutive per testa o croce 
       const int GOAL = 3;
    
             int cont1 = 0, //contatore testa o croce
                 cont2 = 0;
    
       Moneta moneta1; //due monete, vedi class moneta
       Moneta moneta2;
          
       srand(time(0));
     
      //finche' sia la prima che la seconda moneta non hanno fatto 
      //una sequenza di tre testa o croce consecutivi
       while (cont1 < GOAL && cont2 < GOAL) 
          {
             moneta1.effettuaLancio(); // lancio
             moneta2.effettuaLancio();
    
             cout << "Moneta 1: " << moneta1; // overloading operatore << 
             cout << "Moneta 2: " << moneta2 << endl;
    
             if (moneta1.getFaccia() == 'T')
                 cont1++;
             else
                 cont1 = 0;
             
             cont2 = (moneta2.getFaccia()=='C' ? cont2+1 : cont2=0); // operatore condizionale, testa
          }
    
       if (cont1 < GOAL)
          cout << "Vince la moneta 2";
       else 
        if (cont2 < GOAL)
          cout << "Vince la moneta 1";
        else
          cout << "Pari!";
                
       cout << endl;
    
       //system("PAUSE"); sui sistemi windows OK 
    } // end main()
    
    
    Posso chiederti una curiosità? realativa alla parte di questo codice(stesso programma):
    
    #include <iostream>
    #include "moneta.h"
    #include <cstdlib>
    
    
    Moneta::Moneta()
    {
        effettuaLancio(); 
    }
    
    
    Volevo chiederti come mai nel costruttore mettiano "effettuaLancio()". voglio dire il costrutture in questo caso non dovrebbe essere nella forma:
    
    
    #include <iostream>
    #include "moneta.h"
    #include <cstdlib>
    
    
    Moneta::Moneta()
    {
         
    }
    
    perché tanto poi nel main viene richiamata la funzione effettuaLancio()...o sbaglio io a pensarla così?
  • Re: Correttezza programma.

    Viene chiamata perché così appena creata l'istanza venga assegnato un valore certo.
  • Re: Correttezza programma.

    Così la moneta 1 fa punti solo con le teste e la 2 solo con le croci. Era questo che prevedeva la traccia?
  • Re: Correttezza programma.

    Alexv ha scritto:


    Così la moneta 1 fa punti solo con le teste e la 2 solo con le croci. Era questo che prevedeva la traccia?
    No infatti adesso ho aggiustato non ci avevo fatto caso, grazie ancora
  • Re: Correttezza programma.

    Però la chiamata a srand sarebbe bene inserirla nel costruttore
  • Re: Correttezza programma.

    oregon ha scritto:


    Però la chiamata a srand sarebbe bene inserirla nel costruttore
    Intendi utilizzando per esempio un qualche membro statico al fine di inizializzare il seme una sola volta?
  • Re: Correttezza programma.

    No
  • Re: Correttezza programma.

    Sarebbe stato troppo di disturbo argomentare un po' ... in ogni caso volendo stare al gioco: intendi quindi inizializzare il seme con la funzione time(0) ogni volta che viene richiamato il costruttore? Oppure cosa intendi?
  • Re: Correttezza programma.

    Sì nippolo hai capito bene. Puoi argomentare direttamente tu se non sei d'accordo al posto di fare domande di cui conosci la risposta...

    Certo se la inserisce nel costruttore, nel caso di creazioni multiple di oggetti, si rischia che time sia lo stesso e le sequenze ripetute ma si può ovviare con vari merodi.
    La questione era sul rendere più autonomo possibile l'oggetto evitando il fatto di farlo dipendere da codice esterno che facilmente può essere omesso.
  • Re: Correttezza programma.

    oregon ha scritto:


    Puoi argomentare direttamente tu se non sei d'accordo al posto di fare domande di cui conosci la risposta...
    In realtà ho voluto concederti il beneficio del dubbio visto che il rischio di utilizzare più volte la stessa sequenza di numeri pseudocasuali risulta concreto.

    oregon ha scritto:


    Certo se la inserisce nel costruttore, nel caso di creazioni multiple di oggetti, si rischia che time sia lo stesso e le sequenze ripetute ma si può ovviare con vari merodi.
    Poi sarei io quello che vuole polemizzare?! Cioè tu stesso ammetti che il rischio è concreto e bisogna ovviarlo, ma quando parlo di inizializzare il seme una sola volta utilizzando per esempio un membro statico (che ci dice se la funzione srand() sia stata già richiamata o meno), tu mi rispondi con "no"...
  • Re: Correttezza programma.

    Vedi ... non devi concedere il beneficio del dubbio a nessuno.

    Quello che hai da dire dillo direttamente nella risposta con franchezza e umiltà. So che c'è quel rischio ma puoi semplicemente ammettere che esiste anche il rischio di dimenticare la srand nel codice e dunque, sebbene concordi, sarebbe preferibile il membro statico...

    Nulla di più semplice, senza risposte contorte.

    Comunque, per includere nella classe la srand (e ridurre il grado di accoppiamento con codice esterno) si può usare qualcosa del genere
    [Code] struct timeval time; gettimeofday(&time,NULL); srand((time.tv_sec * 1000) + (time.tv_usec / 1000)); senza giri di parole o retropensiero, che ne pensi? Si raggiungono i due scopi?
  • Re: Correttezza programma.

    Hai introdotto degli argomenti che non conoscevo, cmq da una rapida lettura della documentazione mi sembra di capire che per evitare di inizializzare il seme sempre allo stesso valore vai a considerare oltre ai secondi anche i millisecondi.
    Così su due piedi ti direi che ha senso, ma non sapendo cosa realmente succede nella pratica ho provato a fare qualche esperimento:
    Con questo codice
    #include <iostream>
    #include <cstdlib>
    #include <sys/time.h>
    
    using namespace std;
    
    class dado
    {
    public:
    
        dado()
        {
            struct timeval time;
            gettimeofday(&time,NULL);
            srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
        }
    
        unsigned int effettua_lancio()
        {
            return rand() % 6 + 1;
        }
    };
    
    int main()
    {
        for(unsigned int i = 0; i < 10; ++i)
        {
            dado a;
            for(unsigned int j = 0; j < 10; ++j)
            {
                cout << a.effettua_lancio() << "\t";
            }
            cout << endl;
        }
    }
    ottengo
    4       1       4       5       5       6       2       1       2       4
    
    5       5       1       4       6       6       3       2       5       4
    
    2       6       3       5       5       2       2       3       2       6
    
    5       2       3       6       5       5       6       4       2       2
    
    3       5       5       4       6       2       4       6       6       4
    
    6       5       5       5       4       5       3       1       5       6
    
    3       1       1       6       5       5       1       2       3       4
    
    1       4       2       2       6       2       6       2       6       6
    
    4       4       2       5       4       5       4       3       6       2
    
    1       1       4       6       5       1       3       4       3       4
    
    
    Process returned 0 (0x0)   execution time : 0.933 s
    Press any key to continue.
    
    e sembra funzionare.

    Con questo codice invece
    #include <iostream>
    #include <cstdlib>
    #include <sys/time.h>
    
    using namespace std;
    
    class dado
    {
    public:
    
        dado()
        {
            struct timeval time;
            gettimeofday(&time,NULL);
            srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
        }
    
        unsigned int effettua_lancio()
        {
            return rand() % 6 + 1;
        }
    };
    
    int main()
    {
        for(unsigned int i = 0; i < 30; ++i)
        {
            dado a;
            for(unsigned int j = 0; j < 1; ++j)
            {
                cout << a.effettua_lancio() << "\t";
            }
            cout << endl;
        }
    }
    ottengo il seguente output
    5
    5
    2
    2
    2
    2
    2
    2
    2
    2
    6
    6
    6
    6
    6
    6
    6
    6
    6
    3
    3
    3
    3
    3
    3
    6
    6
    3
    3
    1
    
    Process returned 0 (0x0)   execution time : 0.022 s
    Press any key to continue.
    
    e risulta evidente che qualcosa non quadra, evidentemente perché il tempo che intercorre tra due chiamate del costruttore è inferiore a quello necessario per innescare una modifica nell'argomento della srand().
  • Re: Correttezza programma.

    oregon ha scritto:


    senza giri di parole o retropensiero, che ne pensi? Si raggiungono i due scopi?
    Io ti ho risposto, qualche osservazione sarebbe ben accetta!
Devi accedere o registrarti per scrivere nel forum
17 risposte