Rozwiązywanie sudoku [kod]

0

witam. Dostalem zadanie napisania kodu rozwiązującego proste sudoku. Oto treść:

Program powinien zapytać o nazwę pliku z zadaniem (z rozszerzeniem .sud) oraz wyświetlić je. Następnie powinien znaleźć rozwiązanie i wydrukować je na ekranie oraz zapisać w pliku o podanej przez użytkownika nazwie. W przypadku, gdy rozwiązanie nie istnieje, należy wypisać odpowiedni komunikat. Program nie powinien się wieszać lub kończyć błędnie nawet, gdy podawane dane nie są poprawne (plik z zadaniem nie istnieje lub jest niepoprawny).

Oto moj kod:

#include <fstream>
using namespace std;

class sudoku
{
private:
int sud[9][9];
int kolumna_nowa;
int wiersz_nowy;
int wiersz;
int kolumna;
int wartosc;
public:
bool zero(int wiersz,int kolumna);
bool powtarza(int wiersz,int kolumna,int wartosc);
void wybiera(int wiersz,int kolumna);

sudoku(istream & dane);

};

sudoku::sudoku(istream & dane){
for (int wiersz=0 ; wiersz < 9 ; ++wiersz){
for (int kolumna=0 ; kolumna < 9 ; ++kolumna){
char znak;
dane >> znak;
sud[wiersz][kolumna] = znak == '-' ? 0 : znak - '0';

}
}
for (int wiersz=0 ; wiersz < 9 ; ++wiersz)
{
for (int kolumna=0 ; kolumna < 9 ; ++kolumna){
cout << sud[wiersz][kolumna];
}
cout << "\n";
}
cout << "\n";
}

bool sudoku::zero(int wiersz,int kolumna){
if(sud[wiersz][kolumna]==0){return true;}
else{return false;}
}

bool sudoku::powtarza(int wiersz,int kolumna,int wartosc){
for(int i=0; i<9; ++i){
if(sud[i][kolumna]==wartosc || sud[wiersz][i]==wartosc)
{return true;}
}
int wiersz_pocz=(wiersz/3)*3;
int kolumna_pocz=(kolumna/3)*3;
for(int i=wiersz_pocz; i<wiersz_pocz+2; ++i){
for(int i=kolumna_pocz; i<kolumna_pocz+2; ++i){
if(sud[wiersz_pocz][i]==wartosc){return true;}
}
}
return false;
}

void sudoku::wybiera(int wiersz, int kolumna) {
for (int r=0; r<9; ++r){
if (powtarza (wiersz,kolumna,r)==false)
{sud[wiersz][kolumna]=r; break;}
else {
kolumna_nowa = kolumna;
wiersz_nowy = wiersz;
if(kolumna_nowa != 0)
{ kolumna_nowa--;}
if(kolumna_nowa == 0 && wiersz_nowy == 0)
{kolumna_nowa = wiersz_nowy == 0;}
else{wiersz_nowy --; kolumna_nowa=8;}
wybiera(wiersz_nowy,kolumna_nowa);}
}
for (int wiersz=0 ; wiersz < 9 ; ++wiersz){
for (int kolumna=0 ; kolumna < 9 ; ++kolumna){
cout << sud[wiersz][kolumna];
}
cout << "\n";
}
cout << "\n";
}

int main()
{
ifstream plik;
std::string nazwa;
cout<<"podaj nazwe pliku";
cin>>nazwa;
plik.open(nazwa.c_str());
sudoku sudoku1(plik);
for(int i=0; i<1; ++i){
for(int j=0; j<4; ++j){
sudoku1.wybiera(i,j);
}
}
system("pause");
return(0);
}

Program sie kompiluje, ale po wyświetleniu diagramu sudoku, które ma być rozwiązanie, zawiesza się:

Unhandled exception at 0x00411769 in po_kolei.exe: 0xC00000FD: Stack overflow.

Ktos wie może co powoduje ten bład i w jaki sposób go należy rozwiązać?

0

Bez patrzenia w kod: "Stack overflow." = masz nieskończoną rekurencję, jakaś metoda wywołuje sama siebie niekontrolowaną ilość razy.

0

A nie chodzi o to?

void sudoku::wybiera(int wiersz, int kolumna) {
for (int r=0; r<9; ++r){
if (powtarza (wiersz,kolumna,r)==false)
{sud[wiersz][kolumna]=r; break;}
else {
kolumna_nowa = kolumna;
wiersz_nowy = wiersz;
if(kolumna_nowa != 0)
{ kolumna_nowa--;}
if(kolumna_nowa == 0 && wiersz_nowy == 0)
{kolumna_nowa = wiersz_nowy == 0;}
else{wiersz_nowy --; kolumna_nowa=8;}
wybiera(wiersz_nowy,kolumna_nowa);}
}
for (int wiersz=0 ; wiersz < 9 ; ++wiersz){
for (int kolumna=0 ; kolumna < 9 ; ++kolumna){
cout << sud[wiersz][kolumna];
}

I jeszcze jedno - forrmatowanie kodu!

0

też kiedyś pisałem program do rozwiązywania sudoku i z powodu rekurencji wieszał się podczas próby rozwiązania zbyt skomplikowanych zadań (ilość wywołań rekurencji przekraczała kilkadziesiąt tysięcy, nie pamiętam dokładnie ile)

oto co mi polecono tutaj na forum:
http://4programmers.net/Forum/516378?h=#id516378

przerobiłem potem program, żeby działał iteracyjnie i śmiga bez problemu :-)

0

Do carlic:

to jest plansza na ktorej testuje dzialanie kodu:

http://www.mimuw.edu.pl/~ziemians/pk/a.sud

Nie wiem za bardzo na jakim jest poziomie :) Chociaz na pierwszy rzut oka nie wydaje sie najlatwiejsza.

Do MSM, MarekR22:

to jest jedyna rekurencja w tym programie wiec pewnie tam tez jest blad. Macie pomysl jak to rozwiazac?

P.S generlanie dla mnie c++ to troche czarna magia. Miałem tylko 1 semestr zajeć, który obejmował raczej podstawowe zagadnienia.

0

Jak ja pisałem rozwiązywanie sudoku, to nie używałem rekurencja aż do ostatniej chwili.
Czyli rozwiązywałem ile się da na logikę (drogą eliminacji), z pomocą zwykłych pętli for.
Oczywiście zorganizowałem sobie sprytnie dane. Użyłem std::bitset każde pole zawierało info jakie liczby teoretyczni da się wsadzić w dane pole (jeśli liczba była dana to tylko jeden bit był ustawiony). Podobne pole miałem dla każdego wiersza, kolumny kwadratu. Podczas analizy i eliminowania kolejnych liczb (bitów) pilnowałem, żeby zawartość pól dla wierszy, kolumn i kwadratów była aktualna. W ten sposób byłem w stanie rozwiązać wszystkie proste sudoku.
W momencie, gdy drogą eliminacji nie dało się nic już nic więcej wywnioskować, wtedy korzystałem z rekurencji (w efekcie w najgorszym przypadku jak mogłem znaleźć rekurencja zagłębiała mi się maksymalnie 4-5 razy).
Kodu nie mam pod ręką, bo został na kompie w domu.

0

Chetnie bym zobaczyl ten kod. Jest mozliwosc zebys go wkleil tutaj do wieczora?

0

Rozwiązanie do Twojej planszy wymagało tylko 577 kroków iteracyjnych także jest to bardzo łatwa plansza, nie powinno być mowy o "zapchaniu się" stosu czy czegoś w tym stylu podczas obliczeń ;-)

0

Ok wielkie dzieki. Przynajmniej to wiem :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1