PDA

Visualizza la versione completa : [C++] Controllo vincoli gioco non funzionante


lello82nap
13-12-2013, 20:11
buonasera,
ho un problema con un programma che non restituisce un output corretto, anche se gira.
in pratica devo realizzare un "s u d o k u" particolare, nel senso che puo avere anche una matrice 2x2 3x3 ed anche piu' grande della classica 9x9.

Io sono riuscito a creare la matrice generica con una classe Tabella, che contiene un vector di vector-puntatori di oggetti puntatori "Casella", che rappresentano le caselle del gioco con i seguenti attributi.
-numero (valore che si puo dare alla casella)
-indice di riga
-indice di colonna
-fisso (booleano, true se è un numero fisso cioè una delle caselle iniziali del gioco, false se è vuoto)

in questo modo riesco a generare una matrice di numeri 0 se la casella e vuota, o con un numero random da 1 fino ad arrivare alla grandezza del size. poi visualizzo la matrice vector di vector.

IL PROBLEMA E' QUESTO: Nel mio gioco un numero non si puo ripetere sulla stessa riga, nè sulla stessa colonna. MA A ME COMPAIONO ANCORA VALORI RIPETUTI!!!!
Non so da che dipende, nel costruttore di Tabella cerco di dare dei valori random per generare gli indici e il valore delle Caselle Fisse (Quelle iniziali presenti nel gioco come aiuto), poi applico un metodo booleano
controllaVincoli(Casella * casellaDaControllare), che fino ad ora dovrebbe controllare solo i vincoli per i quali i numeri su stessa riga e colonna non si possono ripete. Il metodo dovrebbe restituire true se fra la casella generata e quella, ma non funziona bene, è come se non riconoscesse tutti i numeri ripetuti generati.

Posto solo parte del codice, quella che non funziona.

STO IMPAZZENDO su questa imperfezione, VI PREGO AIUTATEMI, GRAZIE!!!!





class Tabella
{
private:
int sizeTabella;
int sizeRegione;
int livelloDifficolta;
std::vector<std::vector<Casella*>*> *tabella = new std::vector<std::vector<Casella*>*>();


public:

Tabella(int sizeRegione, int livello); /*Crea Tabella di Default a 0*/
~Tabella();
bool controllaVincoli(Casella* casellaDaControllare);
....
....
....
};

....
....
....
....
....
....

/*Crea Tabella di Inizio */
Tabella::Tabella(int sizeRegione, int livelloDifficolta)
{
this->livelloDifficolta = livelloDifficolta;
this->sizeRegione = sizeRegione;
this->sizeTabella = sizeRegione*sizeRegione;


int quantitaNumeriFissi = this->sizeTabella*this->sizeTabella; //inizializiamo la quantità di fissi alla quantità di numeri in totale in tabella
//per calcolare su di essa in seguito la percentuale di numeri fissi tramite lo
//costrutto Switch - Case
switch (this->livelloDifficolta)
{
case 3:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 5) / 100);
break;
case 2:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 25) / 100);
break;
case 1:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 50) / 100);
break;
}



/**** INIZIO CREAZIONE STRUTTURA MATRICIALE ****/
//Creo un vector di puntatori vector di puntatori Caselle di Default (valore=0).
//Simulo così una matrice di 0
for (int i = 0; i < this->sizeTabella; i++)
{
std::vector<Casella*> *vec = new std::vector<Casella*>;
this->tabella->push_back(vec);


for (int j = 0; j < this->sizeTabella; j++)
{
Casella *casella = new Casella(i,j); //Il Costruttore di Default di Casella, genera numero=0 e fisso=false
tabella->at(i)->push_back(casella); //sull'i-esimo vettore di vettore inseriamo in coda una Casella di valore 0
//std::cout << "inserita casella " << casella->getRiga() <<" "<<casella->getColonna()<< std::endl;
}
}


/**** INIZIO INSERIMENTO NUMERI FISSI IN TABELLA ****/

int riga = 0; int colonna = 0; int valore = 0;
srand((unsigned)time(NULL));

for (int i = 0; i < quantitaNumeriFissi; i++)
{
riga = (rand() % (this->sizeTabella));
colonna = (rand() % (this->sizeTabella));
valore = (rand() % (this->sizeTabella)) + 1;
std::cout << "rand 1 =" << valore << std::endl;

Casella *casella = new Casella(valore,riga, colonna);

if (this->tabella->at(riga)->at(colonna)->getNumero() == 0 && this->controllaVincoli(casella) == true) //se quel valore è gia presente in riga, colonna o regione
{
valore = (rand() % (this->sizeTabella)) + 1; //calcola un valore diverso
std::cout << "rand 2 =" << valore<<std::endl;
}

this->tabella->at(riga)->at(colonna)->setNumero(valore);
this->tabella->at(riga)->at(colonna)->setFisso(true);
}
/************FINE INSERIMENTO NUMERI FISSI ******************/
};

.
.
.
.
.
bool Tabella::controllaVincoli(Casella* casellaDaControllare)
{
bool esistenza=false;


//CONTROLLO PRIMO VINCOLO - ESISTENZA SU STESSA RIGA
int ii = casellaDaControllare->getRiga();
int jj = 0;


while (jj <this->sizeTabella && this->tabella->at(ii)->at(jj)->getNumero()!=casellaDaControllare->getNumero())
jj++;
if (jj == this->sizeTabella)
esistenza = false;
else
esistenza = true;


//CONTROLLO SECONDO VINCOLO - ESISTENZA SU STESSA COLONNA

ii = 0;
jj = casellaDaControllare->getColonna();


while (ii <this->sizeTabella && this->tabella->at(ii)->at(jj)->getNumero() != casellaDaControllare->getNumero())
ii++;
if (ii == this->sizeTabella)
esistenza = esistenza && false;
else
esistenza = esistenza && true;


std::cout << "esistenza = " << esistenza << std::endl;
return esistenza;


};
/*** FINE CONTROLLO VINCOLI ***/








class Casella {


private:
int numero;
int riga;
int colonna;
bool fisso; //Se è Numero Fisso = TRUE, se Numero Non Fisso = FALSE


public:
Casella(int riga, int colonna);
Casella(int numero, int riga, int colonna);
Casella(int numero, int riga, int colonna, bool fisso);


~Casella();
void setNumero(int numero){ this->numero = numero; };
void setRiga(bool fisso){ this->fisso = fisso; };
void setColonna(int colonna){ this->colonna = colonna; };
void setFisso(bool fisso){ this->fisso = fisso; };
int getNumero(){ return this->numero; };
int getRiga(){ return this->riga; };
int getColonna(){ return this->colonna; };
bool getFisso(){ return this->fisso; };
};

lello82nap
14-12-2013, 14:25
nessun aiuto?

mio dio :spy:

MItaly
14-12-2013, 16:07
Forse la gente era intimidita dalle dieci righe di titolo :D l'ho cambiato in qualcosa di più sintetico.

Comunque, ad occhio il problema sta qui:


if (this->tabella->at(riga)->at(colonna)->getNumero() == 0 && this->controllaVincoli(casella) == true) //se quel valore è gia presente in riga, colonna o regione
{
valore = (rand() % (this->sizeTabella)) + 1; //calcola un valore diverso
std::cout << "rand 2 =" << valore<<std::endl;
}
Quell'if dovrebbe essere un while o roba del genere: così com'è ora, se il primo numero generato non va bene ne genera un altro ma non ricontrolla se va bene.

Comunque, secondo me stai facendo "overengineering" del problema; non ha senso fare un oggetto a parte per ogni casella in cui di nuovo vai a memorizzarne la posizione - basta una semplice matrice di struct contenente valore e flag "fisso".

lello82nap
14-12-2013, 16:13
ciao, si in effetti nel thread l'avevo scritto che il problema è quel metodo che non funziona nell'if, questa era l'unica cosa che mi era chiara dall'inizio.
però per cortesia nel titolo potresti sostituire la parola sudoku con la parola gioco?
avevo pensato anche io a un titolo come il tuo solo che non voglio che i miei colleghi usando google vengano a copiarmi il progetto, il prof boccia per queste cose.
ad ogni mi è tassativamente negato usare struct, malloc e calloc.
il prof vuole solo classi e istanziamento con NEW

MItaly
14-12-2013, 16:27
Titolo cambiato; comunque, in C++ le struct e le class sono esattamente equivalenti (semplicemente nelle class i membri e l'ereditarietà sono private di default). Concordo su new invece di malloc, ma ribadisco che tutte queste istanze allocate sull'heap non mi paiono una buona idea.

Per il resto, usando un while al posto di un if lì il problema è andato a posto?

lello82nap
14-12-2013, 18:42
grazie infinite per il titolo.

con il while non ho risolto, credo perchè alla fine il while equivale ad un (for + if)

tu mastichi c++?

lello82nap
14-12-2013, 18:47
ho cambiato un pasticcio che avevo fatto anche se non ha risolto il problema, ora ho capito cosa volevi dire con l'inutilità di generare il nuovo oggetto, ora la tabella punta all'oggetto creato, che pasticcio avevo fatto.


if (this->tabella->at(riga)->at(colonna)->getNumero() == 0 && this->controllaVincoli(casella) == true) //se quel valore è gia presente in riga, colonna o regione
{
valore = (rand() % (this->sizeTabella)) + 1; //calcola un valore diverso
std::cout << "rand 2 =" << valore << std::endl;
casella->setNumero(valore);
casella->setFisso(true);

}
this->tabella->at(riga)->at(colonna) = casella; //<--------------------- cambiato qui

MItaly
14-12-2013, 18:56
Forse conviene se carichi l'intero sorgente (se non ci sta in un post sul forum prova con pastebin o simili), così provo ad eseguirlo e ci do un'occhiata più approfondita.

lello82nap
14-12-2013, 19:01
Ti cairico tutto

classe Tabella.h








#include "Casella.h"
#include <vector>
#include <iostream>
#include <string>
#include <ctime>
#include <cstdlib>




class Tabella
{
private:
int sizeTabella;
int sizeRegione;
int livelloDifficolta;
std::vector<std::vector<Casella*>*> *tabella = new std::vector<std::vector<Casella*>*>();


public:


Tabella(int sizeRegione, int livello); /*Crea Tabella di Default a 0*/
~Tabella();
void mostraSudoku();
bool controllaVincoli(Casella* casellaDaControllare); //OVERLOADING DI METODI
bool controllaVincoli(int, int, int );
long int BackTracking();
};


/*Crea Tabella di Default a 0*/
Tabella::Tabella(int sizeRegione, int livelloDifficolta)
{
this->livelloDifficolta = livelloDifficolta;
this->sizeRegione = sizeRegione;
this->sizeTabella = sizeRegione*sizeRegione;


int quantitaNumeriFissi = this->sizeTabella*this->sizeTabella; //inizializiamo la quantità di fissi alla quantità di numeri in totale in tabella
//per calcolare su di essa in seguito la percentuale di numeri fissi tramite lo
//costrutto Switch - Case
switch (this->livelloDifficolta)
{
case 3:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 5) / 100);
break;
case 2:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 25) / 100);
break;
case 1:
quantitaNumeriFissi = (int)floor((quantitaNumeriFissi * 50) / 100);
break;
}




/**** INIZIO CREAZIONE STRUTTURA MATRICIALE ****/
//Creo un vector di puntatori vector di puntatori Caselle di Default (valore=0).
//Simulo così una matrice di 0
for (int i = 0; i < this->sizeTabella; i++)
{
std::vector<Casella*> *vec = new std::vector<Casella*>;
this->tabella->push_back(vec);


for (int j = 0; j < this->sizeTabella; j++)
{
Casella *casella = new Casella(i, j); //Il Costruttore di Default di Casella, genera numero=0 e fisso=false
tabella->at(i)->push_back(casella); //sull'i-esimo vettore di vettore inseriamo in coda una Casella di valore 0
//std::cout << "inserita casella " << casella->getRiga() <<" "<<casella->getColonna()<< std::endl;
}
}


/**** INIZIO INSERIMENTO NUMERI FISSI IN TABELLA ****/


int riga = 0; int colonna = 0; int valore = 0;
srand((unsigned)time(NULL));


for (int i = 0; i < quantitaNumeriFissi; i++)
{
riga = (rand() % (this->sizeTabella));
colonna = (rand() % (this->sizeTabella));
valore = (rand() % (this->sizeTabella)) + 1;
std::cout << "rand 1 =" << valore << std::endl;


Casella *casella = new Casella(valore, riga, colonna);


if (this->tabella->at(riga)->at(colonna)->getNumero() == 0 && this->controllaVincoli(casella) == true) //se quel valore è gia presente in riga, colonna o regione
{
valore = (rand() % (this->sizeTabella)) + 1; //calcola un valore diverso
std::cout << "rand 2 =" << valore << std::endl;
casella->setNumero(valore);
casella->setFisso(true);

}

this->tabella->at(riga)->at(colonna) = casella;
this->mostraSudoku();
//system("PAUSE");
}
/************FINE INSERIMENTO NUMERI FISSI ******************/
};


Tabella::~Tabella()
{
for (int i = 0; i < tabella->size(); i++)
{
for (int j = 0; j < tabella->size(); j++)
{
delete tabella->at(i)->at(j); //sull'i-esimo vettore di vettore inseriamo in coda 0
}
tabella->at(i)->clear(); //libera la memoria di ogni vettore
delete tabella->at(i);
}


tabella->clear();
delete tabella;
}


/*** CONTROLLO DEI VINCOLI DI BACKTRACKING ***/
//Questo metodo, controlla se il numero della casella presa in argomento sia uguale al numero di una presente
//sulla stessa riga, colonna o regione
//l'uguaglianza è verificata attraverso RICERCA SEQUENZIALE ITERATIVA


bool Tabella::controllaVincoli(Casella* casellaDaControllare)
{
bool esistenza = false;


//CONTROLLO PRIMO VINCOLO - ESISTENZA SU STESSA RIGA
int ii = casellaDaControllare->getRiga();
int jj = 0;


while (jj < this->sizeTabella && this->tabella->at(ii)->at(jj)->getNumero() != casellaDaControllare->getNumero())
jj++;
if (jj == this->sizeTabella)
esistenza = false;
else
esistenza = true;


//CONTROLLO SECONDO VINCOLO - ESISTENZA SU STESSA COLONNA
ii = 0;
jj = casellaDaControllare->getColonna();


while (ii < this->sizeTabella && this->tabella->at(ii)->at(jj)->getNumero() != casellaDaControllare->getNumero())
ii++;
if (ii == this->sizeTabella)
esistenza = esistenza && false;
else
esistenza = esistenza && true;


//CONTROLLO TERZO VINCOLO - ESISTENZA IN REGIONE


/*
.
.
.
.
.
.*/


std::cout << "esistenza = " << esistenza << std::endl;
return esistenza;


};
/*** FINE CONTROLLO VINCOLI ***/


void Tabella::mostraSudoku()
{
std::string *barra = new std::string("--------"); //unità semplice di una barra grafica inferiore
for (int k = 0; k < this->sizeRegione - 1; k++) //la barra viene aumentata in relazione alla grandezza e alla quantità di Regioni
{
barra->append(*barra);
}


for (int i = 0; i < tabella->size(); i++)
{


for (int j = 0; j < tabella->size(); j++)
{
if (tabella->at(i)->at(j)->getNumero() >= 10)
{
std::cout << (tabella->at(i)->at(j)->getNumero()) << " ";
}
else if (tabella->at(i)->at(j)->getNumero() <= 9 && tabella->at(i)->at(j)->getNumero() >= 0)
{
std::cout << (tabella->at(i)->at(j)->getNumero()) << " ";
}


if (j % sizeRegione == sizeRegione - 1) std::cout << "| ";
}


if (i % sizeRegione == sizeRegione - 1)
{
std::cout << std::endl << *barra << std::endl;
}


std::cout << std::endl;
}
};






classe Casella.h

#ifndef _SUDOKU_#define _SUDOKU_


#include <vector>
#include <ctime>
#include <cstdlib>


class Casella {


private:
int numero;
int riga;
int colonna;
bool fisso; //Se è Numero Fisso = TRUE, se Numero Non Fisso = FALSE


public:
Casella(int riga, int colonna);
Casella(int numero, int riga, int colonna);
Casella(int numero, int riga, int colonna, bool fisso);


~Casella();
void setNumero(int numero){ this->numero = numero; };
void setRiga(bool fisso){ this->fisso = fisso; };
void setColonna(int colonna){ this->colonna = colonna; };
void setFisso(bool fisso){ this->fisso = fisso; };
int getNumero(){ return this->numero; };
int getRiga(){ return this->riga; };
int getColonna(){ return this->colonna; };
bool getFisso(){ return this->fisso; };
};


/* OVERLOADING DI COSTRUTTORI */


Casella::Casella(int riga, int colonna){
this->numero = 0;
this->fisso = false;
this->riga = riga;
this->colonna = colonna;
};


Casella::Casella(int numero, int riga, int colonna){
this->numero = numero;
this->fisso = false;
this->riga = riga;
this->colonna = colonna;
};


Casella::Casella(int numero, int riga, int colonna, bool fisso)
{
this->numero = numero;
this->fisso = fisso;
this->riga = riga;
this->colonna = colonna;


}


/* FINE OVERLOADING */


Casella::~Casella(){
delete this;
}


#endif

file cpp Sudoku.cpp





#include "stdafx.h"
#include "Tabella.h"
#include <iostream>
//#include "Tabella.h"




int _tmain(int argc, _TCHAR* argv[])
{
int size = 0;
int livello = 0;
std::cout << "Inserisci il size di riga e colonna della Cella: " << std::endl;
std::cin >> size;
std::cout << "Inserisci il livello di difficolta' " << std::endl;
std::cout << "[1] : Inesperto" << std::endl << "[2] : Medio" << std::endl << "[3] : Esperto" << std::endl;
std::cin >> livello;
Tabella *tabella = new Tabella(size,livello);
tabella->mostraSudoku();
system("PAUSE");
return 0;
}





cmq ho l'impressione che sia il corpo di quel metodo contollaVincoli(Casella *casellaDaControllare) che non funziona bene dentro. ma non mi spiego perchè dato che implementa una semplice ricerca sequenziale presa da wiki!

spero tu riesca... io sto letteralmente impazzendo.

GRAZIE MILLE!!!

lello82nap
15-12-2013, 16:40
nada? :-(

Loading