//數獨游戲c++ class CSudoku { int map[9][9]; int blanks; int smod; int solves; int check(int,int,int*); void dfs(); public: enum{ANY=0,ALL=1}; CSudoku(int); CSudoku::CSudoku(int *data); void SudokuGenerator(int); //隨機生成數獨,n越大越難 void SudokuGenerator(int *data);//人工指定數獨 //virtual ~CSudoku(); void display();//顯示數獨 int resolve(int mod=ALL);//解數獨 void analyze(); }; #include "stdio.h" #include "stdlib.h" #include "time.h" #include "iostream" #include "iomanip" //要用到格式控制符 using namespace std; CSudoku::CSudoku(int n){ int j; j=rand()%3; blanks=n+j; SudokuGenerator(blanks); cout<<endl<<"隨機數獨: --->(Y軸)[x,y坐標均從0開始]"<<endl; cout<<endl<<"填數請按Enter鍵,按指示操作"<<endl; //cout<<(空格子數為"<<blanks<<")"<<endl; display(); cout<<"press enter to continue! "<<endl; getchar(); getchar(); while(1){ cout<<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; cout<<"%%請選擇您的操作:%% "<<endl; cout<<"%%============================%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%1.顯示當前數獨%% "<<endl; cout<<"%%2.分析求解%% "<<endl; cout<<"%%3. 查看結果%% "<<endl; cout<<"%%4.返回%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; int select; cin>>select; switch (select){ case 1:{ cout<<endl<<"當前隨機數獨: "<<endl; display(); cout<<"press enter to continue! "<<endl; getchar(); getchar(); break; } case 2:{ analyze(); break; } case 3:{ cout<<endl<<"顯示結果: "<<endl; resolve(); cout<<"press enter to continue! "<<endl<<endl; getchar(); getchar(); break; } case 4: return; default:{ cout<<"輸入錯誤,請重新輸入."<<endl; break; } } } } CSudoku::CSudoku(int *data){ SudokuGenerator(data); cout<<endl<<"已知數獨為: "<<endl; display(); cout<<"press enter to continue! "<<endl; getchar(); getchar(); analyze(); } void CSudoku::SudokuGenerator(int n){ int i,j; int mark[10]; srand(time(0)); //每一行i產生一個隨機位置(列j)並置為當前行值i+1,0=<i,j<=8。 do{ for(i=0;i<9;++i){ for(j=0;j<9;++j) map[i][j]=0; j=rand()%9; map[i][j]=i+1; } //display(); } while(!resolve(ANY));//生成完整的隨機Sudoku表格 //挖窟窿 for(int k=0;k<n;++k){ int tmp,flag=0,sum=1; do{ //cout<<"sum="<<sum<<endl; if (sum++>81){ SudokuGenerator(n); return; } if (flag==1) map[i][j]=tmp; do{ i=rand()%81; j=i%9; i=i/9; } while (map[i][j]==0); tmp=map[i][j]; map[i][j]=0; flag=1; } while(check(i,j,mark)>1); } } void CSudoku::SudokuGenerator(int *data){ int *pm=(int*)map; for(int i=0;i<81;++i) pm[i]=data[i]; } void CSudoku::display(){ int count=0; printf("┏━┯━┯━┳━┯━┯━┳━┯━┯━┓\n");//最開始的一行 for(int i=0;i<9;++i){ for(int j=0;j<9;++j){ if(j%3==0){ printf("┃");//先輸出加粗制表符 printf(" "); if(map[i][j]>0){ printf("%d",map[i][j]); } else{ printf(" "); } //printf(" ");//把光標移到下一個格子對應的起始位置 //printf(" "); } else{ printf("│");//先輸出正常制表符 printf(" "); if(map[i][j]>0){ printf("%d",map[i][j]); } else{ printf(" "); } //printf(" ");//把光標移到下一個格子對應的起始位置 //printf(" "); } if(j==8){ printf("┃");//一行中最后一個粗黑色制表符 } } //一行輸出完成 if(i!=8){ if((i+1)%3==0){ printf("\n"); printf("┣━┿━┿━╋━┿━┿━╋━┿━┿━┫\n"); } else{ printf("\n"); printf("┠─┼─┼─╂─┼─┼─╂─┼─┼─┨\n"); } } if(i==8){ printf("\n"); printf("┗━┷━┷━┻━┷━┷━┻━┷━┷━┛\n"); //最后一行 } } } int CSudoku::resolve(int mod){ smod=mod; if(mod==ALL){ solves=0; dfs(); return solves; } else if(mod==ANY){ try { dfs(); return 0; } catch(int){ return 1; } } return 0; } int CSudoku::check(int y,int x,int *mark){ int i,j,is,js,count=0; for(i=1;i<=9;++i) mark[i]=0; for(i=0;i<9;++i) mark[map[y][i]]=1; for(i=0;i<9;++i) mark[map[i][x]]=1; is=y/3*3; js=x/3*3; for(i=0;i<3;++i){ for(j=0;j<3;++j) mark[map[is+i][js+j]]=1; } for(i=1;i<=9;++i) if(mark[i]==0) count++; return count; } void CSudoku::dfs(){ int i,j,im=-1,jm,min=10; int mark[10]; // display(); //求自由度最小的格map[im][jm] for(i=0;i<9;++i){ for(j=0;j<9;++j){ if(map[i][j]) //如果此格已填入數則看一下格。 continue; int c=check(i,j,mark); //如果此格空,則求其自由度。 if(c==0)//已到結尾,沒有空格了。 return; if(c<min){ im=i; jm=j; min=c; } } } if(im==-1)//若im=-1,則格子都填滿。 { if(smod==ALL)//smod==ALL是求解過程。 { //printf("No. %d:\n",++solves); display(); return; } else if(smod==ANY) //smod==ANY是初始化過程。 { throw(1); } } check(im,jm,mark); for(i=1;i<=9;++i){ if(mark[i]==0) { map[im][jm]=i;//從小到大讓第一個可填的數填入自由度最小的格。 dfs(); } } map[im][jm]=0; return; } void CSudoku::analyze(){ while(1){ cout<<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; cout<<"%%請問你想做什么?%% "<<endl; cout<<"%%============================%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%1.查找最小不確定度的格子%% "<<endl; cout<<"%%2.指定格子的可填數%% "<<endl; cout<<"%%3.給指定格子填數%% "<<endl; cout<<"%%4.顯示當前數獨%% "<<endl; cout<<"%%5.查看結果%% "<<endl; cout<<"%%6.返回%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; int select; cin>>select; switch(select){ case 1://求不確定度最小的空格map[im][jm] { int i,j,im=-1,jm,min=10; int mark[10]; for(i=0;i<9;++i) { for(j=0;j<9;++j) { if(map[i][j]) //如果此格已填入數則看一下格。 continue; int c=check(i,j,mark); //如果此格空,則求其不確定度。 if(c==0) { cout<<"不能得到結果或已無空格子!自動返回! "<<endl; return; } if(c<min) { im=i; jm=j; min=c; } } } cout<<endl<<"不確定度最小的格子為:["<<im<<","<<jm<<"]"<<"其可填的數的個數為:"<<min<<endl<<endl; cout<<"press enter to continue! "<<endl; getchar(); getchar(); break; } case 2:{ int x,y; int mark[10]; cout<<endl<<"請輸入格子位置(如[2,4],則輸入:2 4,中間用空格.): [x,y]="; cin>>x>>y; getchar(); while (map[x][y]!=0){ cout<<endl<<"警告:此格已經有數!請重新輸入."<<endl<<endl; cout<<"請重新輸入格子位置(如[2,4],則輸入:2 4,中間用空格.): [x,y]="; cin>>x>>y; getchar(); } int i,j,is,js,count=0; for(i=1;i<=9;++i) mark[i]=0; for(i=0;i<9;++i) mark[map[x][i]]=1; for(i=0;i<9;++i) mark[map[i][y]]=1; is=x/3*3; js=y/3*3; for(i=0;i<3;++i) { for(j=0;j<3;++j) mark[map[is+i][js+j]]=1; } cout<<endl<<"此格可填數為:"; for(i=1;i<=9;++i) if(mark[i]==0) { count++; cout<<setw(4)<<i; } cout<<endl; cout<<"press enter to continue! "<<endl; getchar(); break; } case 3:{ int x,y; cout<<endl<<"請輸入您要填格子的位置(如[2,4],則輸入:2 4,中間用空格.): [x,y]="; cin>>x>>y; cout<<"請輸入要填入的數: "; cin>>map[x][y]; cout<<"您填入的格為: map["<<x<<","<<y<<"]="<<map[x][y]<<endl; cout<<"press enter to continue! "<<endl; getchar(); getchar(); break; } case 4:{ cout<<endl<<"當前隨機數獨: "<<endl; display(); cout<<"press enter to continue! "<<endl; getchar(); getchar(); break; } case 5:{ cout<<endl<<"顯示結果: "<<endl; resolve();//沒有輸入參數,則默認為smod==ALL,見程序開始函數聲明。 cout<<"press enter to continue! "<<endl<<endl; getchar(); getchar(); break; } case 6: return; default:{ cout<<"輸入錯誤,請重新輸入."<<endl; break; } } } } //main函數 void main(){ int blanks; while(1){ bool exit_f=true; cout<<endl; cout<<"%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; cout<<"%%SUDOKU游戲%% "<<endl; cout<<"%%白鶴制作%% "<<endl; cout<<"%%=====================%% "<<endl; cout<<"%%1.新游戲%% "<<endl; cout<<"%%2.退出%% "<<endl; cout<<"%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; int select; cin>>select; switch (select){ case 1: //開始新游戲 { while(exit_f) { cout<<"%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; cout<<"%%請選擇游戲難度%% "<<endl; cout<<"%%=====================%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%1.簡單%% "<<endl; cout<<"%%2.中等%% "<<endl; cout<<"%%3.困難%% "<<endl; cout<<"%%4.返回%% "<<endl; cout<<"%%%% "<<endl; cout<<"%%%%%%%%%%%%%%%%%%%%%%%%% "<<endl; /* cout<<endl<<"請選擇游戲難度: "<<endl; cout<<"======================= "<<endl; cout<<"1.簡單"<<endl; cout<<"2.中等"<<endl; cout<<"3.困難"<<endl; cout<<"4. 解一個已知數獨"<<endl; cout<<"5. 退出"<<endl; cout<<"======================= "<<endl<<endl;*/ int level; cin>>level; switch(level){ case 1:{ blanks=33; CSudoku s(blanks); break; } case 2:{ blanks=36; CSudoku s(blanks); break; } case 3:{ blanks=39; CSudoku s(blanks); break; } case 4:{ exit_f=false; break; } default: { cout<<"輸入錯誤,請重新輸入."<<endl<<endl; break; } } } break; } case 2: return; default: { cout<<"輸入有誤,請重新選擇!"<<endl; break; } } } }