Browse Source

Add files via upload

master
dnomd343 5 years ago
committed by GitHub
parent
commit
b611a507ef
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 628
      Sudoku.cpp

628
Sudoku.cpp

@ -1,315 +1,313 @@
#include<iostream> #include <iostream>
#include<vector> #include <vector>
#include<fstream> #include <fstream>
using namespace std; using namespace std;
ifstream File_Input; ifstream File_Input;
ofstream File_Output; ofstream File_Output;
struct Sudoku_Class{ //一个宫格的内容 struct Sudoku_Data { //一个宫格的内容
unsigned char Data; //数字1~9,0表示未完成 unsigned char Data; //数字1~9 0表示未完成
bool May[9]; //假设数 bool May[9]; //假设数
}; };
struct Try_Point_Class{ //假设链上的节点 struct Try_Point { //假设链上的节点
unsigned char Block_Num; //被假设的宫格编号 unsigned char Block_num; //被假设的宫格编号
unsigned char Point_Num; //当前正在被假设的Item编号 unsigned char Point_num; //当前正在被假设的item编号
vector <unsigned char> Item; //节点中的所有假设数 vector <unsigned char> item; //节点中的所有假设数
}; };
struct Sudoku_Class Base[81]; //全部81个宫格 struct Sudoku_Data Base[81]; //全部81个宫格
struct Sudoku_Class Backup[81]; //进行假设的时候暂存使用 struct Sudoku_Data Backup[81]; //进行假设的时候暂存使用
unsigned char Addr_Kind[3][9][9]; //行列宫对应的位置表 unsigned char Addr_Kind[3][9][9]; //行列宫对应的位置表
unsigned char Addr_Block[81][3]; //宫格所在行列宫的编号 unsigned char Addr_Block[81][3]; //宫格所在行列宫的编号
vector <struct Try_Point_Class> Try; //假设链 vector <struct Try_Point> Try; //假设链
struct Try_Point_Class Empty_Point; //空的假设节点 struct Try_Point Empty_Point; //空的假设节点
unsigned char Mode; bool display; //决定Solve_Output时是否输出
void Init(); void Init();
void Analyse(); void Analyse();
void Engine(); void Engine();
bool Check_Compete(); bool Check_Compete();
bool Check_Error(); bool Check_Error();
void Create_New_Point(); void Create_New_Point();
void Solve_Output(); void Solve_Output();
bool Try_Next(); bool Try_Next();
void Data_Input(); void Data_Input();
unsigned int Calculate(); unsigned int Calculate();
unsigned char Next_Empty_Block(unsigned char Start); unsigned char Next_Empty_Block(unsigned char Start);
void Init_Point(unsigned char Block_Num,unsigned char Point_Num); void Init_Point(unsigned char Block_num,unsigned char Point_num);
int main(){ int main() {
unsigned int Solve_Num,Dat; unsigned int Solve_num, dat;
Init(); Init();
cout<<"Welcome to Sudoku-Calculator!"<<endl; cout<<"Welcome to Sudoku-Calculator by Dnomd343"<<endl<<endl;
Restart:; Reinput:;
Data_Input(); Data_Input();
cout<<endl<<"The Input Data:"<<endl; cout<<"The Input Data:"<<endl<<endl;
Solve_Output(); for (int i = 0; i < 81; i++) {
cout<<"0.Go back and edit the data"<<endl; if (Base[i].Data == 0) {
cout<<"1.Show all solutions one by one"<<endl; cout<<"- ";
cout<<"2.Find the number of solutions in all cases"<<endl; } else {
cout<<"3.Find all solutions and output them to file"<<endl; cout<<int(Base[i].Data)<<" ";
cout<<endl<<"Select a mode and continue : "; }
cin>>Dat; if (i % 3 == 2) {cout<<" ";}
if((Dat>=1)&&(Dat<=3)){Mode=Dat;}else{goto Restart;} if (i % 9 == 8) {cout<<endl;}
cout<<"The mode is "<<int(Mode)<<" ,Press ENTER to Start Calculate..."; if (i % 27 == 26) {cout<<endl;}
cin.get();cin.get(); }
cout<<"Please Wait..."<<endl; cout<<endl;
Solve_Num=Calculate(); cout<<"0. Go Back and Edit the Data"<<endl;
if(Solve_Num==0){ cout<<"1. Just Search all the Cases"<<endl;
cout<<"Error or No solve!!!"<<endl; cout<<"2. Show all Solutions One by One"<<endl;
} cout<<endl<<"Select a mode and then Continue : ";
else{ cin>>dat;
cout<<"Found "<<Solve_Num<<" Solution"<<endl; cin.get();
} if (dat == 1) {
cout<<"Press ENTER to Exit..."; display=false;
cin.get(); } else if (dat == 2) {
return 0; display=true;
} } else {
void Data_Input(){ //接受命令行下输入数独内容 goto Reinput;
unsigned int Num,i; }
char Dat; cout<<"Please Wait..."<<endl<<endl;
char Data[82]; Solve_num = Calculate();
cout<<"Please Input the Data:"<<endl; if (Solve_num == 0) {
Num=0; cout<<"Error or No solve!!!"<<endl;
Next:; } else {
cout<<endl<<endl<<endl<<endl<<endl<<endl; cout<<"Found "<<Solve_num<<" Solution"<<endl;
cout<<"You can Input the Command and then Press the ENTER"<<endl; }
cout<<"'+' : Next Block '-' : Last Block"<<endl; cout<<"Press ENTER to Exit...";
cout<<"'*' : Next Line '/' : Last Line"<<endl; cin.get();
cout<<"'=' : Compete '0' : Empty Block"<<endl; return 0;
cout<<"'1' to '9' : The Number"<<endl<<endl; }
for(i=0;i<=80;i++){ void Data_Input() { //命令行模式下输入数独内容
Data[i]=Base[i].Data+48; unsigned int num = 0;
} char dat;
Data[81]=0; Next:;
for(i=0;i<=80;i++){ cout<<endl<<endl<<endl<<endl<<endl;
if(i==Num){ cout<<"You can Input the Command and then Press the ENTER"<<endl;
cout<<"_"<<" "; cout<<"'+' : Next Block '-' : Last Block"<<endl;
} cout<<"'*' : Next Line '/' : Last Line"<<endl;
else{ cout<<"'=' : Compete '0' : Empty Block"<<endl;
if(Data[i]=='0'){cout<<"?"<<" ";}else{cout<<Data[i]<<" ";} cout<<"'1' to '9' : The number"<<endl<<endl;
} for (int i = 0; i < 81; i++) {
if(i%3==2){cout<<" ";} if (i == num) {
if(i%9==8){cout<<endl;} cout<<"_"<<" ";
if(i%27==26){cout<<endl;} } else {
} if (Base[i].Data == 48) {
cin>>Dat; cout<<"?"<<" ";
if(Dat==43){ // ‘+’ } else {
if(Num<=79){Num++;} cout<<int(Base[i].Data)<<" ";
goto Next; }
} }
else if(Dat==45){ // '-' if (i % 3 == 2) {cout<<" ";}
if(Num>=1){Num--;} if (i % 9 == 8) {cout<<endl;}
goto Next; if (i % 27 == 26) {cout<<endl;}
} }
else if(Dat==42){ // '*' cin>>dat;
if(Num<=71){Num=Num+9;} if (dat == 43) { // '+'
goto Next; if (num <= 79) {num++;}
} goto Next;
else if(Dat==47){ // '/' } else if (dat == 45) { // '-'
if(Num>=9){Num=Num-9;} if (num >= 1) {num--;}
goto Next; goto Next;
} } else if (dat == 42) { // '*'
else if(Dat==61){} // '=' if (num <= 71) {num = num + 9;}
else if((Dat>=48)&&(Dat<=57)){ goto Next;
Base[Num].Data=int(Dat-48); } else if (dat == 47) { // '/'
if(Num<=79){Num++;} if (num >= 9) {num = num - 9;}
goto Next; goto Next;
} } else if (dat == 61) {// '='
else{goto Next;} } else if ((dat >= 48) && (dat <= 57)) { // 0~9
} Base[num].Data = int(dat - 48);
void Solve_Output(){ if (num <= 79) {num++;}
unsigned char i; goto Next;
char Data[82]; } else { //其他
if(Mode==2){return;} goto Next;
for(i=0;i<=80;i++){Data[i]=Base[i].Data+48;} }
Data[81]=0; }
if(Mode==0){ void Solve_Output() { //命令行模式下显示数独答案
cout<<endl; if (display == true) { //确认是否处于输出模式
for(i=0;i<=80;i++){ cout<<endl;
if(Data[i]==48){cout<<"-"<<" ";}else{cout<<Data[i]<<" ";} for (int i = 0; i < 81; i++) {
if(i%3==2){cout<<" ";} cout<<int(Base[i].Data)<<" ";
if(i%9==8){cout<<endl;} if (i % 3 == 2) {cout<<" ";}
if(i%27==26){cout<<endl;} if (i % 9 == 8) {cout<<endl;}
} if (i % 27 == 26) {cout<<endl;}
} }
else if(Mode==1){ cout<<"Press ENTER to Show Next Solution...";
cout<<endl; cin.get();
for(i=0;i<=80;i++){ cout<<endl;
cout<<Data[i]<<" "; }
if(i%3==2){cout<<" ";} char dat[82];
if(i%9==8){cout<<endl;} for (int i = 0; i < 81; i++) {dat[i] = Base[i].Data + 48;}
if(i%27==26){cout<<endl;} File_Output<<dat<<endl; //将结果保存到文件中
} }
cout<<"Press ENTER to Show Next Solution..."; unsigned int Calculate() { //主计算函数
cin.get(); unsigned char i;
cout<<endl; int Solve_num = 0;
} File_Output.open("Sudoku_Output.txt");
else if(Mode==3){ Engine(); //初步排除运算
File_Output<<Data<<endl; if (Check_Error() == true) { //输入的数独有误
} File_Output.close();
} return 0;
unsigned int Calculate(){ //主计算函数 }
unsigned char i; if (Check_Compete() == true) { //输入的数独已完成
int Solve_Num=0; Solve_Output();
if(Mode==3){File_Output.open("Data_Output.txt");} File_Output.close();
Engine(); //初步排除运算 return 1;
if(Check_Error()==true){File_Output.close();return 0;} //输入的数独有误 }
if(Check_Compete()==true){Solve_Output();File_Output.close();return 1;} //输入的数独已完成 for (i = 0; i < 81; i++) {Backup[i] = Base[i];} //备份数据 假设时暂存
for(i=0;i<=80;i++){Backup[i]=Base[i];} //备份数据 假设时暂存 Create_New_Point(); //创建假设链根节点
Create_New_Point(); //创建假设链根节点 while (1 == 1) {
while(1){ for (i = 0; i < Try.size(); i++) { //装载假设链
for(i=0;i<=(Try.size()-1);i++){ //装载假设链 Base[Try[i].Block_num].Data = Try[i].item[Try[i].Point_num];
Base[Try[i].Block_Num].Data=Try[i].Item[Try[i].Point_Num]; }
} Engine(); //进行排除运算
Engine(); //进行排除运算 if (Check_Error() == 1) { //当前假设错误
if(Check_Error()==true){ //当前假设错误 if(Try_Next() == false) {break;} //没有下一个假设,则该数独无解,退出
if(Try_Next()==false){break;} //没有下一个假设,则该数独无解,退出 } else { //当前假设可能正确
} if (Check_Compete() == false) { //若仍未完成,则创建新的假设节点
else{ //当前假设可能正确 Create_New_Point();
if(Check_Compete()==false){ //若仍未完成,则创建新的假设节点 } else { //若已完成
Create_New_Point(); Solve_Output();
} Solve_num++; //答案数目+1
else{ //已完成 if (Try_Next() == false) {break;} //没有下一个假设,求解完成,退出
Solve_Output(); }
Solve_Num++; //答案数目+1 }
if(Try_Next()==false){break;} //没有下一个假设,求解完成,退出 }
} File_Output.close();
} return Solve_num;
} }
File_Output.close(); bool Try_Next() { //当前假设错误,装载下一个假设
return Solve_Num; unsigned char i;
} while (Try[Try.size()-1].Point_num >= (Try[Try.size()-1].item.size()-1)) {
bool Try_Next(){ //当前假设错误,装载下一个假设 if (Try.size() == 1) {return false;}
unsigned char i; Try.resize(Try.size()-1);
while((Try[Try.size()-1].Point_Num>=(Try[Try.size()-1].Item.size()-1))){ }
if(Try.size()==1){return false;} Try[Try.size()-1].Point_num++; //假设链末节点指向下一个item
Try.resize(Try.size()-1); for (i = 0; i < 81; i++) {Base[i] = Backup[i];} //重新装载备份数据
} return true;
Try[Try.size()-1].Point_Num++; //假设链末节点指向下一个Item }
for(i=0;i<=80;i++){ //将备份数据重新装载 void Create_New_Point() {
Base[i]=Backup[i]; Try.push_back(Empty_Point);
} if (Try.size() == 1) { //若为根节点
return true; //成功 Init_Point(Next_Empty_Block(0),0); //从第一格开始搜索未完成宫格
} } else { //若不是根节点
void Create_New_Point(){ //创建新的假设链节点 Init_Point(Next_Empty_Block(Try[Try.size()-2].Block_num+1),Try.size()-1); //从上一节点指向的宫格开始搜索未完成宫格
Try.push_back(Empty_Point); }
if(Try.size()==1){ //若为根节点 }
Init_Point(Next_Empty_Block(0),0); //从第一格开始搜索未完成宫格 void Init_Point(unsigned char Block_num,unsigned char Point_num) { //初始化假设链节点 Block_num->被假设宫格的编号 Point_num->节点的编号
} unsigned char i;
else{ //若不是根节点 Try[Point_num].Block_num = Block_num;
Init_Point(Next_Empty_Block(Try[Try.size()-2].Block_Num+1),Try.size()-1); //从上一节点指向的宫格开始搜索未完成宫格 for (i = 0; i < 9; i++) {
} if (Base[Try[Point_num].Block_num].May[i] == true) { //遍历目标宫格的所有假设数并加入到该节点的item中
} Try[Point_num].item.push_back(i + 1);
void Init_Point(unsigned char Block_Num,unsigned char Point_Num){ //初始化假设链节点 Block_Num->被假设宫格的编号 Point_Num->节点的编号 }
unsigned char i; }
Try[Point_Num].Block_Num=Block_Num; Try[Point_num].Point_num = 0; //指向item中的第一个假设数
for(i=0;i<=8;i++){ }
if(Base[Try[Point_Num].Block_Num].May[i]==true){ //遍历目标宫格的所有假设数并加入到该节点的Item中 unsigned char Next_Empty_Block(unsigned char Start) { //找到下一个未确定答案的宫格并返回其编号
Try[Point_Num].Item.push_back(i+1); unsigned char i;
} for (i = Start; i < 81; i++) {
} if (Base[i].Data == 0) {return i;}
Try[Point_Num].Point_Num=0; //指向Item中的第一个假设数 }
} return 0; //没有未确定宫格
unsigned char Next_Empty_Block(unsigned char Start){ //找到下一个未确定答案的宫格并返回其编号 }
unsigned char i; bool Check_Error() { //检查数独是否存在错误
for(i=Start;i<=80;i++){ unsigned char kind, num, add, item;
if(Base[i].Data==0){return i;} for (kind = 0; kind < 3; kind++) { //分别扫描行列宫
} for (num = 0; num < 9; num++) {
return 0; //没有未确定宫格 for (item = 1; item <= 9; item++) {
} add = 0;
bool Check_Error(){ //检查数独是否存在错误 for (unsigned char k = 0; k < 9; k++) {
unsigned char kind,num,add,item; if (Base[Addr_Kind[kind][num][k]].Data == item) {add++;}
for(kind=0;kind<=2;kind++){ //分别扫描行列宫 }
for(num=0;num<=8;num++){ if (add >= 2) {return true;} //若一组行列宫中存在两个相同的数 -> 错误退出
for(item=1;item<=9;item++){ }
add=0; }
for(unsigned char k=0;k<=8;k++){ }
if(Base[Addr_Kind[kind][num][k]].Data==item){add++;} for (num = 0; num < 81; num++) { //扫描全部宫格
} if (Base[num].Data == 0) { //若未完成
if(add>=2){return true;} //若一组行列宫中存在两个相同的数 -> 错误退出 add = 0;
} for (unsigned char k = 0; k < 9; k++) { //遍历其所有假设数
} if (Base[num].May[k] == true) {add++;}
} }
for(num=0;num<=80;num++){ //扫描全部宫格 if (add == 0) {return true;} //没有可能的数 -> 错误退出
if(Base[num].Data==0){ //若未完成 }
add=0; }
for(unsigned char k=0;k<=8;k++){ //遍历其所有假设数 return false; //暂时未发现错误
if(Base[num].May[k]==true){add++;} }
} bool Check_Compete() { //判断数独是否完成
if(add==0){return true;} //没有可能的数 -> 错误退出 unsigned char i;
} for (i = 0; i < 81; i++) {
} if (Base[i].Data == 0) {return false;}
return false; //暂时未发现错误 }
} return true;
bool Check_Compete(){ //判断数独是否完成 }
unsigned char i; void Engine() { //使用排除法消去不可能的数
for(i=0;i<=80;i++){ unsigned char kind, num, item, add, dat;
if(Base[i].Data==0){return false;} bool Could_Solve;
} Again:;
return true; Analyse(); //每次排除前应先消去假设数
} Could_Solve = false;
void Engine(){ //使用排除法 for (kind = 0; kind < 3; kind++) { //分别扫描行列宫
unsigned char kind,num,item,add,dat; for (num = 0; num < 9; num++) {
bool Could_Solve; for (item = 0; item < 9; item++) {
Again:; add = 0;
Analyse(); //每次排除前应先消去假设数 for(unsigned char k = 0; k < 9; k++) { //记录一组行列宫中的可能数
Could_Solve=false; if ((Base[Addr_Kind[kind][num][k]].Data == 0) && (Base[Addr_Kind[kind][num][k]].May[item] == true)) {
for(kind=0;kind<=2;kind++){ //分别扫描行列宫 add++;
for(num=0;num<=8;num++){ dat = k;
for(item=0;item<=8;item++){ }
add=0; }
for(unsigned char k=0;k<=8;k++){ if (add == 1) { //若仅有唯一可能数,则该宫格答案确定
if((Base[Addr_Kind[kind][num][k]].Data==0)&&(Base[Addr_Kind[kind][num][k]].May[item]==true)){add++;dat=k;} //记录一组行列宫中的可能数 Base[Addr_Kind[kind][num][dat]].Data = item + 1;
} Could_Solve = true;
if(add==1){Base[Addr_Kind[kind][num][dat]].Data=item+1;Could_Solve=true;} //若仅有唯一可能数,则该宫格答案确定 }
} }
} }
if(Could_Solve==true){goto Again;} //一直循环直到没有排除对象 if (Could_Solve == true) {goto Again;} //一直循环直到没有排除对象
} }
} }
void Analyse(){ //消去假设数 void Analyse() { //消去假设数
unsigned char num,kind,item; unsigned char num, kind, item;
for(num=0;num<=80;num++){ //遍历所有宫格 for (num = 0; num < 81; num++) { //遍历所有宫格
if(Base[num].Data!=0){ //若该宫格已完成 if (Base[num].Data != 0) { //若该宫格已完成
for(kind=0;kind<=2;kind++){ //分别对行列宫操作 for (kind = 0; kind < 3; kind++) { //分别扫描行列宫
for(item=0;item<=8;item++){ for (item = 0; item < 9; item++) {
Base[Addr_Kind[kind][Addr_Block[num][kind]][item]].May[Base[num].Data-1]=false; //消去同行同列同宫的假设数 Base[Addr_Kind[kind][Addr_Block[num][kind]][item]].May[Base[num].Data - 1] = false; //消去同行同列同宫的假设数
} }
} }
} }
} }
} }
void Init(){ //初始化容器 void Init() { //初始化容器
unsigned char i,j,x,y; unsigned char i, j, x, y;
for(i=0;i<=8;i++){ //初始化行与列的位置表 for (i = 0; i < 9; i++) { //初始化行与列的位置表
for(j=0;j<=8;j++){ for (j = 0; j < 9; j++) {
Addr_Kind[0][i][j]=i*9+j; Addr_Kind[0][i][j] = i * 9 + j;
Addr_Kind[1][i][j]=j*9+i; Addr_Kind[1][i][j] = j * 9 + i;
} }
} }
for(x=0;x<=2;x++){ //初始化九宫格的位置表 for (x = 0; x < 3; x++) { //初始化九宫格的位置表
for(y=0;y<=2;y++){ for (y = 0; y < 3; y++) {
for(i=0;i<=2;i++){ for (i = 0; i < 3; i++) {
for(j=0;j<=2;j++){ for (j = 0; j < 3; j++) {
Addr_Kind[2][y*3+x][j*3+i]=(y*3+j)*9+(x*3+i); Addr_Kind[2][y*3 + x][j*3 + i] = (y*3 + j) * 9 + (x*3 + i);
} }
} }
} }
} }
for(i=0;i<=2;i++){ //初始化宫格所在行列宫的编号 for (i = 0; i < 3; i++) { //初始化宫格所在行列宫的编号
for(x=0;x<=8;x++){ for (x = 0; x < 9; x++) {
for(y=0;y<=8;y++){ for (y = 0; y < 9; y++) {
Addr_Block[Addr_Kind[i][x][y]][i]=x; Addr_Block[Addr_Kind[i][x][y]][i] = x;
} }
} }
} }
for(i=0;i<=80;i++){ //清空所有假设数 for (i = 0; i < 81; i++) { //清空所有假设数
for(j=0;j<=8;j++){ for (j = 0; j < 9; j++) {
Base[i].May[j]=true; Base[i].May[j] = true;
} }
} }
for(i=0;i<=80;i++){ //清空所有数字 for (i = 0; i < 81; i++) {Base[i].Data = 0;} //清空所有数字
Base[i].Data=0; }
}
}

Loading…
Cancel
Save