基于第二次数独游戏,添加GUI界面
#include<iostream> #include<cstdlib> #include<ctime> #include<fstream> using namespace std; ofstream ocout; int sudo[9][9]; bool set(int x,int y,int val) { if(sudo[x][y]!=0) //非空 return false; int x0,y0; for(y0=0;y0<9;y0++) //行冲突 { if(sudo[x][y0]==val) return false; } for(x0=0;x0<9;x0++) //列冲突 { if(sudo[x0][y]==val) return false; } for(x0=x/3*3;x0<x/3*3+3;x0++) //格冲突 { for(y0=y/3*3;y0<y/3*3+3;y0++) { if(sudo[x0][y0]==val) return false; } } sudo[x][y]=val; return true; } void current(int* cur) ///0~9随机序列 { int i,j,temp; for(int i=0;i<9;i++) { cur[i]=i; } for(int i=0;i<9;i++) { j=rand()%9; temp=cur[j]; cur[j]=cur[i]; cur[i]=temp; } } void reset(int x,int y) { sudo[x][y]=0; } bool fill(int x,int val) { int cur[9]; current(cur); //生成当前行的扫描序列 for(int i=0;i<9;i++) { int y=cur[i]; if(set(x,y,val)) //可以先把每一行的1填了,再填每一行的2...以此类推 { if(x==8) //到了最后一行 { if(val==9||fill(0,val+1)) //当前填9则结束,否则从第一行填下一个数 return true; } else { if(fill(x+1,val)) //下一行继续填当前数 return true; } reset(x,y); //回溯 } } return false; } void digHole(int holeCnt) //挖空 { int x,y; for(int i=0;i<2;i++) { x = rand() % 3; y = rand() % 3; while( sudo[x][y] == 0 ) { x = rand() % 3; y = rand() % 3; } sudo[x][y]=0; sudo[x][y+3]=0; sudo[x][y+6]=0; sudo[x+3][y]=0; sudo[x+3][y+3]=0; sudo[x+3][y+6]=0; sudo[x+6][y]=0; sudo[x+6][y+3]=0; sudo[x+6][y+6]=0; } for (int j = 0; j < holeCnt; j++ ) { y = rand() % 9; y = rand() % 9; while(sudo[x][y] == 0 ) { x= rand() % 9; y = rand() % 9; } sudo[x][y] = 0; } } void clear(int temp[9][9]) //清空 { for(int i=0;i<9;i++) { for(int j=0;j<9;j++) { temp[i][j]=0; } } } void printsudo() //输出到屏幕 { for(int x=0;x<9;x++) { (x%3==0)?(cout<<" -----------------------\n "):(cout<<" "); cout<<"| "; for(int y=0;y<9;y++) { cout<<sudo[x][y]<<" "; (y%3==2)?(cout<<"| "):(cout<<""); } cout<<endl; } cout<<" -----------------------\n"<<endl; } void printsudotxt() //输出到sudotiku.txt { for(int x=0;x<9;x++) { (x%3==0)?(ocout<<" -----------------------\n "):(ocout<<" "); ocout<<"| "; for(int y=0;y<9;y++) { ocout<<sudo[x][y]<<" "; (y%3==2)?(ocout<<"| "):(ocout<<""); } ocout<<endl; } ocout<<" -----------------------\n"<<endl; } int main() { srand((unsigned)time(NULL)); //这个是种子函数 为rand函数提供不同的种子 每次运行程序产生不同的随机数,不然rand函数每次运行程序产生的随机数都是一样的 ocout.open("sudotiku.txt"); cout<<"请输入数独棋盘题目个数N (0 < N <= 1000000):"<<endl; int N; cin>>N; cout<<"随机生成"<<N<<"个不重复的已解答完毕的数独棋盘如下:"<<endl; ocout << "随机生成"<<N<<"个不重复的已解答完毕的数独棋盘如下:" << endl; for(int i=0;i<N;i++) { clear(sudo); while(!fill(0,1)); digHole(rand()%31+30); printsudo(); printsudotxt(); } ocout.close(); return 0; }
输入:数独棋盘题目个数N (0 < N <= 1000000)
输出:随机生成N个不重复的有唯一解的数独棋盘。挖空处用数字0表示,每个数独棋盘中至少要有30个以上的0。每个棋盘隔一行,输出需要到文件sudotiku.txt中。
基于第二次数独游戏,添加GUI界面,实现以下功能:
- 生成任意数量的数独题目并将数独棋局依次显示,棋盘上总空格数大于30,小于60,每3*3小棋盘中挖空不少于2个。
- 数独题目有且仅有唯一解。
- 用户可以在界面上通过编辑输入完成数独题目。
- 用户完成数独题目后可以得到正确性反馈。
- 友好的使用说明。
关于GUI界面的代码,已上传到Coding,网址:https://coding.net/u/dhlg_201810812001/p/sudo/git
生成数独的GUI界面如下所示:
点击自动计算数独结果,就会生成数独的唯一解,结果如下:
经测试,程序可以正确运行,但如上游戏信息所提示,计算结果最多只能保存1000个,有一定的局限性,还需继续完善。
这次作业相比上次而言,有一定的难度。关于GUI界面,由于使用不是很熟练,所以只能参考别人的代码来进行实现,我搜集了CSDN中关于数独的一些代码,对于通过MFC来进行绘图这块由于之前没有接触过,所以只能借鉴别人的,遇到不懂的语句再去百度,通过不断学习,对其结构有了一定的理解,达到了能够看懂的地步,但要想自己做出一个界面还是有一定困难。
整个作业的完成花费了大量时间,大概有一个星期左右,主要是因为对于MFC的使用不熟练,通过本次作业的完成,我又掌握了一项新的技能——MFC的使用,为以后深入的学习奠定了一些基础。