Название: [РЕШЕНО] Генератор доски Судоку
Отправлено: gil9red от Июнь 07, 2012, 00:02
Здравствуйте! Имеется у меня алгоритм генерации доски судоку, это игра такая. Алгоритм не мною написан, иногда, глючит (бывает заполняет часть матрицы 0), собственно вот класс, который и реализует эту генерацию: #include <QTime>
const short N = 9;
typedef int TCandidat[N]; typedef int Matrix9x9[N][N];
class SudokuMatrixGenerator { public: SudokuMatrixGenerator(); Matrix9x9& getGenerateSudokuMatrix();
private: void Cand_Init(TCandidat a); int Cand_to_Number(TCandidat a); int Cand_Count(TCandidat a);
void Init_9_9(int matrix[N][N]); int Unic_RCM(int matrix[N][N], int a, int b, int val);
void Step1(int matrix[N][N]); void Step2(int matrix[N][N]);
void clearAllVar();
private: TCandidat mesh[N][N]; TCandidat temp_cand;
Matrix9x9 start; Matrix9x9 board;
int tempi; int tempj; int Rall_number; int cont; int old_opened; };
SudokuMatrixGenerator::SudokuMatrixGenerator() { qsrand(QTime(0,0,0).secsTo(QTime::currentTime())); }
Matrix9x9& SudokuMatrixGenerator::getGenerateSudokuMatrix() { clearAllVar(); Step1(board); return board; }
void SudokuMatrixGenerator::clearAllVar() { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) for(int z = 0; z < N; z++) { mesh[i][j][z] = 0; }
for(int i = 0; i < N; i++) { temp_cand[i] = 0; }
Init_9_9(start); Init_9_9(board); tempi = 0; tempj = 0; Rall_number = 0; cont = 0; old_opened = -1; }
void SudokuMatrixGenerator::Cand_Init(TCandidat a) { for(int i = 0; i < N; i++) { a[i] = 1; } }
int SudokuMatrixGenerator::Cand_Count(TCandidat a) { int c = 0; for(int i = 0; i < N; i++) { if(a[i] == 1) { c++; } } return c; }
void SudokuMatrixGenerator::Init_9_9(int matrix[N][N]) { for(int i = 0; i < N; i++) for(int j = 0; j < N; j++) { matrix[i][j] = 0; } }
int SudokuMatrixGenerator::Unic_RCM(int matrix[N][N], int a, int b, int val) { int i, j, flag = 0; // unic in a row for(j = 0; j < N; j++) { if(matrix[a][j] == val) { flag++; } }
if(flag == 0) //unikalno v stroke, proverjaem stolbets { for(i = 0; i < N; i++) { if(matrix[i][b] == val) { flag++; } }
} if(flag == 0) //unikalno i v stroke, i v stolbtse, proverim sector { for(i = (a / 3) * 3; i < (a / 3) * 3 + 3; i++) for(j = (b / 3) * 3 ;j < (b / 3) * 3 + 3; j++) { if(matrix[i][j] == val) { flag++; } } } if(flag == 0) { return 1; // chislo unikalno }else { return 0; // chislo ne unikalno } }
int SudokuMatrixGenerator::Cand_to_Number(TCandidat a) { int i,c=0; for(i=0;i<N;i++) if(a[i]==1) { c=i+1; break; } return c; }
void SudokuMatrixGenerator::Step1(int board[N][N]) { for(int i=0;i<N;i++) for(int j=0;j<N;j++) board[i][j]=start[i][j]; // find a place for a value do { tempi=qrand()%N; tempj=qrand()%N; } while(board[tempi][tempj]!=0); // cout<<"\nposition:"<<tempi<<" "<<tempj; //find a value int val_count=0, temp_val; Cand_Init(temp_cand); while(val_count<N) { do { temp_val=qrand()%N; } while(temp_cand[temp_val]==0);// eto znachenie ushe vibiralos val_count++; temp_cand[temp_val]=0; if(Unic_RCM(board, tempi,tempj, temp_val+1)==1) { board[tempi][tempj]=temp_val+1; start[tempi][tempj]=temp_val+1; break; } }
if(Rall_number<=50) { //cout<<endl<<"Rall_number="<<Rall_number; if(val_count==8) Step1(board); //rekursija else Step2(board); // popitka reshenija } else { if(cont<30) { Rall_number=0; //cout<<endl<<"cont="<<cont;//getch(); for(int i=0;i<15;i++) { tempi=qrand()%N; tempj=qrand()%N; start[tempi][tempj]=0; } cont++; Step1(board); } //cout<<endl<<"Rall_number="<<Rall_number<<"!!! Stop!!!"; } }
void SudokuMatrixGenerator::Step2(int board[N][N]) { int i,j,k1,k2; // cout<<endl<<"position:"<<tempi<<" "<<tempj; //cout<<endl<<"val -= "<<board[tempi][tempj]<<endl;
for(i=0;i<N;i++) for(j=0;j<N;j++) Cand_Init(mesh[i][j]);
for(i=0;i<N;i++) for(j=0;j<N;j++) if (board[i][j]!=0)// v jachejku vpisano chislo { //zapreschaem v stolbtse for(k1=0;k1<N;k1++) mesh[k1][j][board[i][j]-1]=0;
//zapreschaem v stroke for(k2=0;k2<N;k2++) mesh[i][k2][board[i][j]-1]=0; // sektor for(k1=(i/3)*3;k1<(i/3)*3+3;k1++) for(k2=(j/3)*3;k2<(j/3)*3+3;k2++) mesh[k1][k2][board[i][j]-1]=0; //sozdaem masku jachejki (i,j) for(k1=0;k1<N;k1++) mesh[i][j][k1]=0; mesh[i][j][board[i][j]-1]=1;
} //jachejki, gde vse chisla zaprescheni int flag=0, t=0; for(i=0;i<N;i++) for(j=0;j<N;j++) if (Cand_Count(mesh[i][j])==0) flag++; if (flag!=0) //net reshenija { //cout<<endl<<"Net reshenija! Otkat poslednego izmenenija!"<<endl; start[tempi][tempj]=0; Rall_number++; Step1(board); } else { for(i=0;i<N;i++) for(j=0;j<N;j++) if (Cand_Count(mesh[i][j])==1) { //podstavliajem tsifru na dosku board[i][j]=Cand_to_Number(mesh[i][j]); t++; } int number; //prosmatrivaem stroki for(i=0;i<N;i++) for(number=0;number<N;number++) { flag=0; for(j=0;j<N;j++) if(mesh[i][j][number]==1) flag++; if(flag==1)//nashli tolko odno vozmozhnoje mesto for(j=0;j<N;j++) if(mesh[i][j][number]==1) {board[i][j]=number+1; t++;} } //prosmatrivaem stolbtsi for(j=0;j<N;j++) for(number=0;number<N;number++) { flag=0; for(i=0;i<N;i++) if(mesh[i][j][number]==1) flag++; if(flag==1) for(i=0;i<N;i++) if (mesh[i][j][number]==1) {board[i][j]=number+1; t++;} } // prosmatrivaem sectora for(int a=0;a<N;a=a+3) for(int b=0;b<N;b=b+3) //eto perebiraem vse sectora { for(number=0;number<N;number++) { flag=0; for(i=(a/3)*3;i<(a/3)*3+3;i++) for(j=(b/3)*3;j<(b/3)*3+3;j++) if(mesh[i][j][number]==1) flag++; if(flag==1) for(i=(a/3)*3;i<(a/3)*3+3;i++) for(j=(b/3)*3;j<(b/3)*3+3;j++) if(mesh[i][j][number]==1) {board[i][j]=number+1; t++;} } } //schitaem skolko mest zapolneno v matritse flag=0; for(i=0;i<N;i++) for(j=0;j<N;j++) if (board[i][j]==0) flag++; //cout<<endl<<"Not opened cells:"<<flag; //cout<<"\nt="<<t<<endl; if((flag>0)&&(flag<81)&&(old_opened!=flag)) { old_opened=flag; //cout<<"\nGOTO Step2"; Step2(board); } else if((flag>0)&&(flag<81)&&(old_opened==flag)) { old_opened=flag; //cout<<"\nGOTO Step1"; Step1(board); } } }
У меня просьба: есть ли у кого нибудь работающий без глюков такой алгоритм генерирования или помогите оптимизировать этот, пробовал разобраться в этом, но... это жесть... такая дикая логика... :o Так как пишу игру под симбиан, хочется чтобы генерация была минимально ресурсоемкой и быстрая. Саму игру я написал, осталось пару штрихов. Заранее спасибо :)
Название: Re: Генератор доски Судоку
Отправлено: Igors от Июнь 07, 2012, 02:51
Когда я начал посещать этот форум один из модераторов сказал примерно такую фразу (не ручаюсь за точность) ты сильно ошибаешься полагая что кто-то будет копаться в твоем коде..
Грубовато но в принципе верно. Не все даже слышали о такой игре, с какой стати заниматься довольно затратным "reversed engineering"? Да и вообще смахивает на "разберитесь за меня" :) Действуйте тоньше, расскажите что должен делать этот алгоритм, в чем проблема и.т.п.
Название: Re: Генератор доски Судоку
Отправлено: gil9red от Июнь 07, 2012, 06:50
Все просто) Алгоритм должен заполнить матрицу размером 9 на 9 числами от 1 до 9, так чтобы, во всех строках и столбцах матрицы числа не повторялись :) Проблема в том что тот алгоритм, код которого я разместил, иногда генерирует с "ляпами" Например треть матрицы заполнена нулями, я как то давал потестить другу, так у него, в одной строке два одинаковых числа попались
Название: Re: Генератор доски Судоку
Отправлено: gil9red от Июнь 07, 2012, 06:56
Вот так выглядит такая матрица: 6 2 7 5 1 4 9 3 8 3 4 9 7 2 8 6 5 1 1 5 8 9 6 3 2 4 7
2 1 4 3 8 5 7 6 9 8 9 5 6 4 7 3 1 2 7 6 3 2 9 1 4 8 5
4 8 2 1 3 9 5 7 6 9 7 1 4 5 6 8 2 3 5 3 6 8 7 2 1 9 4
Название: Re: Генератор доски Судоку
Отправлено: gil9red от Июнь 07, 2012, 06:57
Как видите, такая матрица в судоку делится на 9 секторов, в которых, кст, тоже нет повторения чисел
Название: Re: Генератор доски Судоку
Отправлено: Igors от Июнь 07, 2012, 16:13
Все просто) Алгоритм должен заполнить матрицу размером 9 на 9 числами от 1 до 9, так чтобы, во всех строках и столбцах матрицы числа не повторялись :)
Так бы и сказали, а то судоку-мудоку.. Ну доказать что "решение найдется" и.т.п. я конечно не смогу. Но "брутой форсой" это сделать несложно (аттач)
Название: Re: Генератор доски Судоку
Отправлено: gil9red от Июнь 07, 2012, 21:32
Спасибо :) Ваш код намного понятнее и читабельнее, хоть и заполняет практически правильно, но модифицировать я смогу :)
|