PDA

View Full Version : domanda su un comando


neski
12-07-2012, 21:32
Ciao a tutti :D avrei un problema se qualcuno magari sa cm aiutarmi aiutarmi mi farebbe un enorme favore..io ho compilato un gioco del lotto questo:
#include <cstdlib>
#include <iostream>

using namespace std;

const int max_numeri=5;
const int max_citta=11;
string citta[max_citta]={"Bari","Cagliari","Firenze","Genova","Milano","Napoli","Palermo","Roma","Torino","Venezia","Nazionale"};
int numeri[max_numeri];
int giocoEstrazioni(int numero)
{


int numeri;
srand (time(NULL));
for(int j=0; j<max_citta; j++){

cout<<endl<<citta[j]<<" \t";

for(int i=0; i<max_numeri; i++){
numeri=rand()%90+1;

cout<<" \t"<<numeri;

}

}
cout<<endl;
}

int main(int argc, char *argv[])

{
int numero;
giocoEstrazioni(numero);

system("PAUSE");
return EXIT_SUCCESS;
}

ma mi succede che in una stessa ruota mi escono due numeri uguali..c'è un soluzione che non lo fa succedere? grazie scusate :wtf:

demos88
13-07-2012, 09:22
Devi tener traccia dei numeri che estrai memorizzandoli da qualche parte. Quando estrai i successivi, controlla che il nuovo numero non sia già uscito.

neski
13-07-2012, 14:17
grazie mille:) ma riusciresti a farmi un esempio semplice semplice da capire meglio? se non ti disturbo troppo..

demos88
13-07-2012, 16:40
Sono un po' arruginito di c/c++.
Comunque una cosa molto semplice del genere, dichiarando un array di interi di lunghezza max_numeri (sia per esempio numeri[], che ho visto dichiari all'inizio ma non mi pare che usi...) e cambiando il nome della variabile int numeri in int numero (cattiva abitudine dare nomi uguali a variabili che funzionano in modo diverso, array e primitivo in questo caso) e sostituendo queste righe:

for(int i=0; i<max_numeri; i++){
numeri=rand()%90+1;
cout<<" \t"<<numeri;
}

con

//azzero l'array, 0 non può uscire quindi va bene per quello che fai dopo
for (int j=0; j<max_numeri; j++)
numeri[j]=0;

for(int i=0, int j=0; i<max_numeri; i++){
numero=rand()%90+1;

//controllo che non sia già stato estratto
for (j=0; j<max_numeri; j++)
if (numeri[j] == numero)
break; //esce dal ciclo di controllo perchè trova un doppione, j avrà un valore inferiore a max_numeri
if (j<max_numeri) //trovato un doppione
continue; //non stamparlo a video, estraine un altro
cout<<" \t"<<numero;
}


non l'ho compilato, ho cambiato il nome di una variabile per non fare confusione. I commenti dovrebbero essere esplicativi.

neski
13-07-2012, 17:51
grazie la spiegazione seo stato molto chiaro,però guarda mi da sempre dei doppi non capisco come mai...

demos88
13-07-2012, 18:35
edit: ma no dai che pirla che sono. Manca l'inserimento nell'array :)
prova così
//azzero l'array, 0 non può uscire quindi va bene per quello che fai dopo
for (int j=0; j<max_numeri; j++)
numeri[j]=0;

for(int i=0, int j=0; i<max_numeri; i++){
numero=rand()%90+1;

//controllo che non sia già stato estratto
for (j=0; j<max_numeri; j++)
if (numeri[j] == numero || numeri[j] == 0)
break; //esce dal ciclo di controllo perchè trova un doppione o un elemento non inizializzato, j avrà un valore inferiore a max_numeri
if (j<max_numeri && numeri[j] == 0)
numeri[j] = numero; //inserisci il nuovo numero nell'array
else
continue; //non stamparlo a video, estraine un altro

cout<<" \t"<<numero;
}

neski
13-07-2012, 18:50
eh no ancora niente......:muro:

neski
13-07-2012, 20:11
nessuno?....

demos88
13-07-2012, 20:25
eh no ancora niente......:muro:
lol è diventata una questione di principio per me ormai xD
ho bootato con ubuntu e compilato con code blocks.
Allora, la funzione come te l'ho postata io mi da un errore di compilazione che ho risolto scrivendo int i=0,j=0 nel for anzichè int i=0, int j=0
L'ho provato e funziona tranquillamente, ho impostato il numero di valori possibili a 10 anzichè 90 per alzare le probabilità di doppioni e non ne vedo nemmeno uno.
Ovviamente stiamo intendendo doppioni all'interno della stessa ruota vero?
A scanso di equivoci, riporto per intero la funzione:

int giocoEstrazioni(){

int numero;
srand (time(NULL));
for(int j=0; j<max_citta; j++){
cout<<endl<<citta[j]<<" \t";

//azzero l'array, 0 non può uscire quindi va bene per quello che fai dopo
for (int j=0; j<max_numeri; j++)
numeri[j]=0;

for(int i=0,j=0; i<max_numeri; i++){
numero=rand()%90+1;

//controllo che non sia già stato estratto
for (j=0; j<max_numeri; j++)
if (numeri[j] == numero || numeri[j] == 0)
break; //esce dal ciclo di controllo perchè trova un doppione o un elemento non inizializzato, j avrà un valore inferiore a max_numeri
if (j<max_numeri && numeri[j] == 0)
numeri[j] = numero; //inserisci il nuovo numero nell'array
else
continue; //non stamparlo a video, estraine un altro

cout<<"\t"<<numero;
}
}
cout<<endl;
}


questa mi funziona, ho provato anche approcci diversi (con un loop while true perchè mi piace il while :P ) e funziona seguendo lo stesso ragionamento.
Se a te non va, non so più che fare xD

neski
13-07-2012, 21:12
niente ancora niente non capisco come mai ci perderò la testa......grazie comunque...:)

neski
14-07-2012, 10:15
ah comunque con questo tuo codice non mi tira fuori dei numeri.....ci sono dei punti vuoti..

starfred
14-07-2012, 10:55
Ciao, a mio avviso il codice è un po' bruttino...
Partiamo dall'inizio:

int numeri[max_numeri];


Non è utilizzata e crea solo confusione dato che poi dichiari la funzione giocoEstrazioni con all'interno la variabile

int numeri;

Altra cosa:

int giocoEstrazioni(int numero)

Viene chiamata dal main con

int numero;
giocoEstrazioni(numero);

Tuttavia la variabile "numero" non è inizializzata, fortunatamente non viene usata all'interno della funzione giocoEstrazioni, tuttavia potrebbe portare a problemi.
Quindi il mio consiglio è quello di utilizzare l'opzione -Wall quando compili.

Passiamo ora al problema da te esposto ovvero i numeri doppi sulla stessa ruota.

Riprendendo la tua funzione io farei una cosa così:



....
map<int,int> numeri;
map<int,int>::iterator it;
....

int giocoEstrazioni(int numero)
{
int estratto;
srand (time(NULL));
for(int j=0; j<max_citta; j++){
numeri.clear();

cout<<endl<<citta[j]<<" \t";

for(int i=0; i<max_numeri; i++){
estratto=rand()%90+1;

it=numeri.find(estratto);

if (it==numeri.end())
cout<<" \t"<<estratto;
else
i--;
}

}
cout<<endl;
}



Ovviamente avendo prima "ripulito" il codice come ti ho esposto prima.

E' abbastanza semplice concettualmente, sicuramente non è il massimo dell'efficienza :)
Ciao

bender86
14-07-2012, 11:52
Decisamente poco elegante e poco efficiente: ogni volta che generi un numero devi controllare di non averlo già estratto, e nel caso ripetere (anche molte volte).

Devi estrarre senza reinserimento n numeri tra quelli da 1 a 90: crea una lista di numeri da 1 a 90, mischiala casualmente e prendi i primi n (che poi è proprio come funziona realmente un'estrazione del lotto).

#include <iostream>
#include <vector>
#include <algorithm>

#include <cstdlib>
#include <ctime>

std::vector<int> estrai(const int n, const int max = 90)
{
// Crea un vettore contenente numeri da 1 a max.
std::vector<int> numbers(max);
for (int i = 1; i <= max; ++i) {
numbers[i - 1] = i;
}

// Mischia casualmente il vettore (ricordati di inizializzare generatore
// di numeri casuali con std::srand).
std::random_shuffle(numbers.begin(), numbers.end());

// Copia i primi n numeri.
std::vector<int> result(n);
std::copy(numbers.begin(), numbers.begin() + n, result.begin());

return result;
}

int main()
{
std::srand(std::time(0));

std::vector<int> result = estrai(5);

std::cout << "Results: \n";
for (std::vector<int>::const_iterator i = result.begin();
i != result.end();
++i) {
std::cout << " " << *i << '\n';
}
}

neski
19-07-2012, 09:30
l'unico codice che mi funziona è quello d bender ma non lo riesco a comprendere del tutto....in tutti i passaggi...

demos88
19-07-2012, 13:12
l'unico codice che mi funziona è quello d bender ma non lo riesco a comprendere del tutto....in tutti i passaggi...
Il codice di bender fa semplicemente uso di alcune classi e metodi più complessi per non dover eseguire a mano (sui vettori) le operazioni.
E' concettualmente diverso. I suoi commenti mi sembrano esaustivi e il codice chiaro, riassumendo il suo codice:
- crea un oggetto di tipo vector di capienza "max" numeri
- nel primo ciclo for inizializza il vettore assegnando il valore n alla n-esima posizione del vettore (i + 1 è la posizione dell'elemento di indice i). In pratica hai un vettore di 90 interi ordinati dall'1 al 90.
- con il metodo random_shuffle mescola il vettore
- prende i primi 5 numeri del vettore e quelli sono i 5 numeri estratti, che sono casuali e sicuramente non ripetuti.

neski
19-07-2012, 14:48
Grazie demos88 per a spiegazione molto semplice e chiara,ma stavo pensando e se semplicemente creassi solo un vettore dove salvo i 90 numeri poi come faccio a estrarli casualmente(lo so è molto simile al suo codice) così come hai detto te è impossibile che si ripetano e in più il codice sarebbe ancora più semplice...grazie in anticipo

demos88
19-07-2012, 16:43
Grazie demos88 per a spiegazione molto semplice e chiara,ma stavo pensando e se semplicemente creassi solo un vettore dove salvo i 90 numeri poi come faccio a estrarli casualmente(lo so è molto simile al suo codice) così come hai detto te è impossibile che si ripetano e in più il codice sarebbe ancora più semplice...grazie in anticipo
L'"astuzia" del codice di bender è proprio che non ti devi curare di "estrarli casualmente" in quanto il loro ordine nell'array è già casuale di per se.
Se tu inserisci 90 numeri in un array e li vuoi estrarre casualmente hai due possibilità:
- Rendi casuale l'ordine e estrai sequenzialmente come ha fatto bender. In questo caso non devi generare numeri casuali, basta che estrai i primi 5 (ma potrebbero essere anche gli ultimi 5, o 5 numeri nel mezzo dell'array, non cambia nulla).
- Lasci l'array ordinato e estrai casualmente. Ma in questo caso il problema ritorna di nuovo: per estrarli casualmente devi generare indici dell'array da 1 a 90 casuali e non ripetuti, quindi non combini niente, ti riduci sempre a dover gestire la generazione di numeri casuali non ripetuti.

Se vuoi usare un array da cui estrarre, l'unico modo sensato di farlo è quello di mescolarlo come ha fatto bender.

neski
19-07-2012, 16:57
e naturalmente servono tutte le librerie che ha messo lui o alcune possono anche non essere usate?comunque grazie demos88 mi stai dando una grande mano

demos88
19-07-2012, 18:25
e naturalmente servono tutte le librerie che ha messo lui o alcune possono anche non essere usate?comunque grazie demos88 mi stai dando una grande mano
Non uso molto il C++, penso che abbia messo solo quelle servono. Puoi sempre provare a toglierne una e vedere se compila :D

neski
19-07-2012, 18:48
e std:: cosa sarebbe?sta a significare che crea un vettore standard?perchè non trovo niente in rete,anche se l' ho già visto molte volte

demos88
19-07-2012, 19:12
e std:: cosa sarebbe?sta a significare che crea un vettore standard?perchè non trovo niente in rete,anche se l' ho già visto molte volte
std è la libreria da cui prende la classe vector.
Se a inizio del codice metti "using namespace std;", sottintendi che vector lo deve cercare in std e l'anteposizione o meno di "std::" è ininfluente. Bender non lo ha specificato quindi è obbligato ad anteporre std::

bender86
19-07-2012, 19:41
Vediamo di commentare passo passo:
// Crea un vettore contenente numeri da 1 a max.
std::vector<int> numbers(max);
for (int i = 0; i < max; ++i) {
numbers[i] = i + 1;
}

std::vector<T> è un vettore di elementi di tipo T. Più o meno è equivalente agli array C-style (T numbers[max];). Gli elementi sono accessibili dall'indice 0 all'indice max-1 ma, dato che le palline nel lotto partono da 1, alla posizione i-esima c'è la pallina i+1-esima (in effetti credo sia più chiaro così che nel mio primo esempio).
Quindi il vettore numbers contiene:
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
...
numbers[89] = 90;

A questo punto mischiamo il vettore con std::random_shuffle() (http://en.cppreference.com/w/cpp/algorithm/random_shuffle), in questo modo il vettore sarà ordinato casualmente.

Gli algoritmi della libreria standard di norma prendono come parametri degli iteratori. Cosa sia un iteratore è un po' complesso, ma in sostanza è la generalizzazione di un puntatore ad un elemento di un array. Un iteratore "punta" ad un elemento di un contenitore. Incrementando l'iteratore si ottiene l'elemento successivo, decrementandolo si ottiene l'elemento precedente. Dereferenziandolo (con l'operatore *) si ottiene l'elemento puntato.
int array[4] = {1, 2, 3, 4};
int * inizio = & array[0]; // *inizio = 1
int * i = inizio; // *i = 1
i++; // *i = 2
int * fine = inizio + 4; // fine punta appena oltre la fine dell'array
fine--; // *fine = 4

std::vector<int> vettore = {1, 2, 3, 4}; // In realtà questa inizializzazione non è possibile,
// ma assumi che contenga quegli elementi.
std::vector<int>::iterator inizio = vettore.begin(); // *inizio = 1
std::vector<int>::iterator i = inizio; // *i = 1
i++; // *i = 2
std::vector<int>::iterator fine = inizio + 4; // fine punta appena oltre la fine del vettore
fine--; // *fine = 4

Quindi la linea seguente mischia tutti gli elementi compresi tra l'inizio e la fine del vettore (cioè tutti gli elementi del vettore):
std::random_shuffle(numbers.begin(), numbers.end());

Alla fine si crea un altro vettore di n elementi e ci si copiano dentro i primi n elementi del vettore numbers, che saranno casuali. std::copy() funziona sempre con gli iteratori: copia dall'inizio del vettore fino all'inizio del vettore più n posizioni, a partire dall'inizio del vettore 'result'.
std::vector<int> result(n);
std::copy(numbers.begin(), numbers.begin() + n, result.begin());

È ancora equivalente ad usare array C-style:
int vettore[10] = {...};
int result[3];
int * inizio_vettore = & vettore[0];
int * inizio_result = & result[0];
std::copy(inizio_vettore, inizio_vettore + 3, inizio_result)

// Oppure

int * i, *j;
for (i = inizio_vettore, j = inizio_result; i != inizio_vettore + 3; ++i, ++j) {
*j = *i;
}


In effetti in questo particolare esempio è un'operazione inutile, sarebbe meglio semplicemente ridurre la dimensione del vettore numbers e restituire quest'ultimo. Ma nel caso volessi fare più estrazioni allora l'esempio sarebbe perfetto.

L'ultimo blocco nel main() serve a stampare i risultati. Nota che uso const_iterator e non iterator perché non mi serve modificare gli elementi.


std::vector è definito nell'header <vector>
std::random_shuffle() e std::copy() sono definite nell'header <algorithm>
std::cout è definito nell'header <iostream>
std::srand() è definita nell'header <cstdlib>
std::time() è definita nell'header <ctime>

Quindi servono tutti gli header (anche se alcuni compilatori potrebbero essere poco severi nel caso ne manchi qualcuno).


std::vector indica che il simbolo 'vector' (in questo caso una classe template) sta nel namespace 'std' (che è il namespace della libreria standard). I namespace permettono di avere simboli con lo stesso nome (ad esempio puoi scrivere la tua classe 'vector', purché sia definita in un namespace diverso).
Usare "using namespace std;" non è considerata una buona pratica perché equivale a non usare namespace. In ogni caso non usarlo mai in un header, poiché si propagherebbe in tutti i file che lo includono.

std::vector è una classe che rappresenta un vettore, così come std::list rappresenta una lista, std::stack una pila, std::queue una coda... In C++ non dovresti mai usare array C-style direttamente, queste classi li incapsulano offrendo un'interfaccia più sicura.

IngMetallo
19-07-2012, 21:01
e std:: cosa sarebbe?sta a significare che crea un vettore standard?perchè non trovo niente in rete,anche se l' ho già visto molte volte

EDIT: non avevo visto la pagina 2 con il commento di demos88 e avevo risposto anche io, scusate !

Approfitto per aggiungere un consiglio: Studiare per bene la Standard Template Library (STL) che aiuta veramente molto nello sviluppo dei programmi ! Magari in cose semplici si va a scrivere più codice, ma ne vale la pena perché sono affidabili e comode.

AnonimoVeneziano
20-07-2012, 00:20
e std:: cosa sarebbe?sta a significare che crea un vettore standard?perchè non trovo niente in rete,anche se l' ho già visto molte volte

Da dove stai imparando il C++? Probabilmente cambiare fonte di apprendimento potrebbe essere una buona idea, perchè questa domanda fa pensare che un libro diverso sarebbe meglio.

neski
20-07-2012, 14:46
AnonimoVeneziano eh già :mbe:

IngMetallo
21-07-2012, 00:14
Da dove stai imparando il C++? Probabilmente cambiare fonte di apprendimento potrebbe essere una buona idea, perchè questa domanda fa pensare che un libro diverso sarebbe meglio.

Purtroppo in alcuni testi cose basilari come i namespace vengono trattate negli ultimi capitoli.. sul libro che ho io (Deitel&Deitel dell'Apogeo) vengono trattati addirittura nel secondo libro di "tecniche avanzate". La semplice soluzione in questi casi è cercare su internet quello che non si capisce e non accontentarsi mai di far funzionare un programma senza capirne il perché.

neski
22-07-2012, 10:54
Purtroppo in alcuni testi cose basilari come i namespace vengono trattate negli ultimi capitoli.. sul libro che ho io (Deitel&Deitel dell'Apogeo) vengono trattati addirittura nel secondo libro di "tecniche avanzate". La semplice soluzione in questi casi è cercare su internet quello che non si capisce e non accontentarsi mai di far funzionare un programma senza capirne il perché.

IngMetallo giustissimo...anche se non sempre è facile trovare materiale....comunque volevo ringraziare te,bender,demos88 e tutti gli altri che hanno cercato di autarmi mi avete aiutato moltissimo e non solo per sto programma grazie a tutti!:)