1. 项目需求:利用程序随机构造N个已解答的数独棋盘
2. 输入:数独棋盘题目个数N (0 < N <= 1000000)
3. 输出:随机生成N个不重复的已解答完毕的数独棋盘, 并输出到sudotiku.txt,每个数独棋盘中间隔一行
可执行文件exe,用法:(sudotiku.exe -c 20)(其中20为题目个数)
头文件sudoku.h:
#ifndef SUDOKU_H
#define SUDOKU_H
bool Sudoku_Row(int sudo[9][9], int row, int num);
bool Sudoku_Col(int sudo[9][9], int col, int num);
bool Sudoku_Square(int sudo[9][9], int row, int col, int num);
void print_sudoku(int sudo[9][9]);
bool makeSquare(int sudo[9][9], int num);
#endif
源程序:
#include "pch.h"
#include <iostream>
#include <ctime>
#include <fstream>
#include <stdlib.h>
#include "sudoku.h"
using namespace std;
#define Random(x) (rand()%x)
bool flag = false;
void Init_sudo(int(*sudo)[9])
{
for(int r=0;r<9;r++)
{
for (int c = 0; c < 9; c++)
sudo[r][c] = 0;
}
sudo[0][0] = 1;//初始化数独,使第一个数为1
}
void Init_sudo_part(int(*sudo)[9])
{
for (int r = 3; r < 9; r++)
{
for (int c = 0; c < 9; c++)
sudo[r][c] = 0;
}
for (int r = 0; r < 3; r++)
{
for (int c = 3; c < 9; c++)
sudo[r][c] = 0;
}
}
bool check_sudo(int sudo[9])
{
int temp;
for (int i = 0; i < 9; i++)
{
temp = sudo[i];
for (int j = i + 1;j < 9; j++)
{
if (sudo[j] == temp)
return false;
}
}
return true;
}
//行检查
bool Sudoku_Row(int sudo[9][9], int row, int num)
{
bool flag = false;//冲突标志
for (int i = 0; i < 9; i++)
{
if (sudo[row][i] == num)
{
flag = true;
break;
}
}
return flag;
}
//列检查
bool Sudoku_Col(int sudo[9][9], int col, int num)
{
bool flag = false;
for (int i = 0; i < 9; i++)
{
if (sudo[i][col] == num)
{
flag = true;
break;
}
}
return flag;
}
//宫检查
bool Sudoku_Square(int sudo[9][9], int row,int col, int num)
{
bool flag = false;
int Square_Row = row / 3 * 3;
int Square_col = col / 3 * 3;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
if (sudo[Square_Row+i][Square_col+j] == num)
{
flag = true;
break;
}
}
}
return flag;
}
void print_sudoku(int sudo[9][9])
{
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
cout << sudo[i][j] << ' ';
}
cout << endl;
}
cout << endl;
}
//生成宫格
bool makeSquare(int sudo[9][9], int num)
{
int square_row = (num / 3) * 3;
int square_col = (num % 3) * 3;
int x, y;
int temp;
if (num = 0) //第一个宫格
{
for (int i = 1; i < 9; i++)
{
x = square_row + i / 3;
y = square_col + i % 3;
temp = Random(8) + 2;//生成2~9的随机数
if (!Sudoku_Square(sudo, x, y, temp) && !Sudoku_Col(sudo,
y, temp) && !Sudoku_Row(sudo, x, temp))
{
sudo[x][y] = temp;
}
else i--;
}
}
else //生成其他宫格
{
int try_count = 0;
temp = Random(9) + 1;//生成1~9的随机数
for (int i = 0; i < 9; i++)
{
x = square_row + i / 3;
y = square_col + i % 3;
temp++;
temp = temp % 10;//循环随机数在1~9范围内
if (!Sudoku_Square(sudo, x, y, temp) && !Sudoku_Col(sudo,
y, temp) && !Sudoku_Row(sudo, x, temp) && temp != 0)
{
sudo[x][y] = temp;
try_count = 0;
}
else
{
i--;
try_count++;
}
if (try_count > 10)
{
return false;
break;
}//若所有可能试完则返回无解
}
}
return true;//有解
}
int main(int argc, char *argv[])
{
int N = atoi(argv[argc-1]);
int(*sudo)[9] = new int[9][9];
ofstream outfile;
outfile.open("sudoku.text");//输出到文档
if (N > 0 && N <= 1000000)
{
srand(unsigned int(time(NULL)));//初始化种子为当前时间
bool retry;//重试
int retry_count = 0;//重试次数
for (int i = 0; i < N;)
{
retry = false;
if (retry_count == 0)
{
Init_sudo(sudo);
makeSquare(sudo, 0);
}
else Init_sudo_part(sudo);
for (int j = 1; j < 9; j++)
{
bool flag = makeSquare(sudo, j);
if (!flag)
{
retry = true;
break;
}
}
if (!retry)
{
for (int row = 0; row < 9; row++)
{
for (int col = 0; col < 9; col++)
{
outfile << sudo[row][col] << ' ';
}
outfile << endl;
}//输出一个数独矩阵
outfile << endl;
retry_count = 0;
i++;
}
else
{
retry_count++;
}//无解重试
}
outfile.close();
}
else cout << "please input a proper number:" << endl;
return 0;
}
输出到sudoku.txt中:
程序分析:输出和生成宫格所用的时间比较多,还有待完善改进,但生成的数独没有重复的。这次项目我耗时比较长,也查了许多资料和百度参考别人的经验。我用的是VS2017版本,在调试过程需要在头文件加#include "pch.h"。
心得体会:通过这次作业,我发现我存在了很多有关于算法和编程方面的不足,程序中一点细微的问题都要处理比较久,但值得开心的是学到了一些知识,以后要加强算法和编程方面的练习。
课外任务:大一学过一点C语言,现在正在自学C++,目前能够看懂一些比较基础的程序代码和编写一些简单的程序,算法是个薄弱环节,距离一个合格的IT专业毕业生还有很大的差距,需要提高算法能力和编程能力,还有优化代码的能力。以下这个表是我目前的技能水平和期待课程结束后能达到的水平: