经过许久的不屑努力,在数独终结者5的版本上,增加了可以输入数独的功能
输入规则
按照九宫格从左到右,从上到下的排序方式
分别将数字输入进去,输入数字后需要继续输入空格,PS空的值请输入0
不然程序没法运算出结果
每输入完一行请输入回车
如果需要修改请输入1 不需要修改请输入0 如有类似逻辑的地方请参考此输入规则
上代码
#include "pch.h"
#include <iostream>
void inputSudoku(int **p, bool jud);
void modifySudoku(int **p, bool jud);
void judgeLRN(int **c, int **cc, int **a);
void judgeMaybeA(int **am, int **c);
void fillA(int **am, int **a, int **cc);
void outputSudoku(int **a);
void outputSudokuIn(int **a);
void dealSudoku(int **ppc, int**ppc_c, int **ppa, int**ppa_m);
int main()
{
int i, j, k;
std::cout << "数独终结者\n";
int maybe_a[9][9][9]; // 某个数字可能存在的值
int c[3][9][9]; // 行列九宫格 限制条件
int cal_c[9][9]; // 用于计数 当该单元格的被限制条件限制只能取1个数时,则将该数填入数独数组
int flag; //用于标记那一个数的位置
bool jud;//用于判断输入是否需要修改
jud = true;
bool jud_1 = true; //用于判定是否完成了数独
bool jud_2 = true; //用于判定是否运算次数过多而毫无进展
int jud_i = 0; //计数循环次数,大于某一值认为当前算法有问题,无法解决数独问题,中断循环
int a[9][9] = { {5,3,0,8,4,1,6,2,0},{9,0,0,5,0,2,8,0,0},{0,0,0,0,6,9,0,0,1},
{0,0,0,2,0,0,0,1,0},{7,5,2,1,0,0,9,8,6},{1,4,0,7,9,0,0,5,3},
{0,0,0,0,8,3,0,4,2},{4,0,1,6,2,7,3,9,5},{0,0,3,0,0,5,0,6,0} }; //初始数独
//二级指针用于快速寻址
int *pa;
int **ppa;
pa = &a[0][0];
ppa = &pa;
int *pc;
int **ppc;
pc = &c[0][0][0];
ppc = &pc;
int *pc_c;
int **ppc_c;
pc_c = &cal_c[0][0];
ppc_c = &pc_c;
int *pa_m;
int **ppa_m;
pa_m = &maybe_a[0][0][0];
ppa_m = &pa_m;
//数独输出
inputSudoku(ppa, jud);
modifySudoku(ppa, jud);
outputSudokuIn(ppa);
dealSudoku(ppc, ppc_c, ppa, ppa_m);
}
//输入数独
void inputSudoku(int **p, bool jud)
{
int i, j;
std::cout << "计算默认数独请输入1";
std::cin >> jud;
if (!jud)
{
for (i = 0; i < 9; i++)
{
std::cout << "请输入第" << i + 1 << "行\n";
for (j = 0; j < 9; j++)
{
std::cin >> *(*p + i * 9 + j);
}
}
}
}
//修改数独
void modifySudoku(int **p, bool jud)
{
bool xg, xgg, xggg;//如果输入数独错误,用于标记是否需要修改的状态
xg = true;
xgg = true;
xggg = true;
int i, j;
int xg1, xg2, xg3;
std::cout << "如需继续修改请输入1\n";
std::cin >> xggg;
if (xggg)
{
if (xg && !jud)
{
while (1)
{
std::cout << "如需修改请输入行数和列数\n\n";
std::cout << "请输入行数\n";
std::cin >> xg1;
std::cout << "请输入列数\n";
std::cin >> xg2;
std::cout << "请输入修改数\n";
std::cin >> xg3;
*(*p + 9 * xg1 + xg2) = xg3;
for (i = 0; i < 9; i++)
{
std::cout << "数独如下";
for (j = 0; j < 9; j++)
{
std::cout << *(*p + i * 9 + j) << " ";
}
std::cout << "\n";
}
std::cout << "如需继续修改请输入1\n";
std::cin >> xgg;
if (!xgg)
{
break;
}
}
}
}
}
//行列以及九宫格的判定
void judgeLRN(int **c, int **cc, int **a)
{
int i, j, k;
for (i = 0; i < 243; i++) // c
*(*c + i) = 1;
for (i = 0; i < 81; i++) //cal_c
*(*cc + i) = 0;
//这里的主要思路是行列和九宫格,分别将已有的数字标记为0
for (i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
if (*(*a + i * 9 + j) != 0) //a[i][j]
{
//行
*(*c + i * 9 + *(*a + i * 9 + j) - 1) = 0; //c[0][i][a[i][j] - 1]
//列
*(*c + j * 9 + *(*a + i * 9 + j) + 80) = 0; //c[1][j][a[i][j] - 1]
//九个九宫格
if (i < 3 && j < 3)
{
*(*c + 162 + *(*a + i * 9 + j) - 1) = 0; //c[2][0][a[i][j] - 1] = 0;
}
else if (i < 3 && j > 2 && j < 6)
{
*(*c + 171 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i < 3 && j > 5)
{
*(*c + 180 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i > 2 && i < 6 && j < 3)
{
*(*c + 189 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i < 6 && i > 2 && j > 2 && j < 6)
{
*(*c + 198 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i > 2 && i < 6 && j > 5)
{
*(*c + 207 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i > 5 && j < 3)
{
*(*c + 216 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i > 5 && j > 2 && j < 6)
{
*(*c + 225 + *(*a + i * 9 + j) - 1) = 0;
}
else if (i > 5 && j > 5)
{
*(*c + 234 + *(*a + i * 9 + j) - 1) = 0;
}
}
}
}
}
//每个空余格子可能取值
void judgeMaybeA(int **am, int **c)
{
int i, j, k;
for (i = 0; i < 729; i++) //maybe_a
*(*am + i) = 1;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
for (k = 0; k < 9; k++)
{
if (*(*c + i * 9 + k) == 0) //c[0][i][k]
*(*am + i * 81 + j * 9 + k) = 0; //maybe_a[i][j][k]
if (*(*c + j * 9 + k + 81) == 0)
*(*am + i * 81 + j * 9 + k) = 0;
//九个九宫格
if (i < 3 && j < 3 && *(*c + 162 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i < 3 && j > 2 && j < 6 && *(*c + 171 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i < 3 && j > 5 && *(*c + 180 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 2 && i < 6 && j < 3 && *(*c + 189 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 2 && i < 6 && j > 2 && j < 6 && *(*c + 198 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 2 && i < 6 && j > 5 && *(*c + 207 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 5 && j < 3 && *(*c + 216 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 5 && j > 2 && j < 6 && *(*c + 225 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
else if (i > 5 && j > 5 && *(*c + 234 + k) == 0)
{
*(*am + i * 81 + j * 9 + k) = 0;
}
}
}
}
}
//将智能有一个数字填入的空格填入数字
void fillA(int **am, int **a, int **cc)
{
int i, j, k;
for (i = 0; i < 81; i++) //maybe_a
*(*cc + i) = 0;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
for (k = 0; k < 9; k++)
{
if (*(*am + i * 81 + j * 9 + k) != 0)
{
(*(*cc + i * 9 + j))++;
}
}
if (*(*cc + i * 9 + j) == 1 && *(*a + i * 9 + j) == 0)
{
for (k = 0; k < 9; k++)
{
if (*(*am + i * 81 + j * 9 + k) != 0)
{
*(*a + i * 9 + j) = k + 1;
}
}
}
}
}
}
//输出输入数独
void outputSudokuIn(int **a)
{
int i, j;
std::cout << "数独如下\n";
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
std::cout << *(*a + i * 9 + j) << " ";
}
std::cout << "\n";
}
}
//输出结果数独
void outputSudoku(int **a)
{
int i, j;
std::cout << "结果如下\n";
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
std::cout << *(*a + i * 9 + j) << " ";
}
std::cout << "\n";
}
}
//数独整体判断
void dealSudoku(int **ppc, int**ppc_c, int **ppa, int**ppa_m)
{
//这里的主要思路是行列和九宫格,分别将已有的数字标记为0
bool jud_1 = true; //用于判定是否完成了数独
bool jud_2 = true; //用于判定是否运算次数过多而毫无进展
int jud_i = 0; //计数循环次数,大于某一值认为当前算法有问题,无法解决数独问题,中断循环
int i;
while (jud_1&&jud_2)
{
//这里的主要思路是行列和九宫格,分别将已有的数字标记为0
judgeLRN(ppc, ppc_c, ppa);
judgeMaybeA(ppa_m, ppc);
fillA(ppa_m, ppa, ppc_c);
jud_1 = false;
for (i = 0; i < 81; i++)
{
if (*(*ppa + i) == 0)
jud_1 = true;
}
jud_i++;
if (jud_i > 10000)
jud_2 = false;
}
outputSudoku(ppa);
}
相对上一版本,这一版本使用了函数的调用,主函数看起来更加干净,整体函数更容易读懂,功能模块更加清晰