第8講 ハート型・左右上下対称形・点対称形・上下対称性形・上下対称形第2案と問題から解答へ
第9話 関数fと関数sudokukaihoの変更部分
void sudokukaiho(char a, char g) {//数独を解くエンジン
nextcell(a, g);//座標(Y[a][g], X[a][g])の取得
char y = Y[a][g];
char x = X[a][g];
if (keizoku == 0)return;//数独を発見したスレッドからの連絡および閉じよの指令
for (char i = 0; i < mx[a][y][x]; i++) {
char gy[n] = { 0,0,0,0,0,0,0,0,0 };
char r[n] = { 0,0,0,0,0,0,0,0,0 };
char b[n] = { 0,0,0,0,0,0,0,0,0 };
mondai[a][y][x] = lst[a][y][x][i];
//候補の数字を代入 例えば、mondai[0][1]なら{2, 4}の2,4の順に代入する
if (keizoku == 0)return;
//x[y][x]と同じ行にあるセルへの影響を調べる。
//具体的には座標(y, j)においてmondai[a][y][x]が候補数字に入っている場合には
//候補から外し、候補数字の個数も一つ減らす。
for (char j = 0; j < n; j++) {
if (j != x) {//自己を対象から外す。
if (mondai[a][y][j] == 0) {//空欄のみを解析対象にする。
for (char k = 0; k < mx[a][y][j]; k++) {
if (keizoku == 0)return;
if (mondai[a][y][x] == lst[a][y][j][k]) {
lst[a][y][j][k] = lst[a][y][j][mx[a][y][j] - 1];
lst[a][y][j][mx[a][y][j] - 1] = mondai[a][y][x];
mx[a][y][j]--;
gy[j] = 1;//座標(y, j)においてmondai[a][y][x]が候補数字から外され、
//候補数字数も減らされたことを記録している。
}
}
}
}
}
if (keizoku == 0)return;
for (char j = 0; j < n; j++) {
if (j != y) {//自己を対象から外す。
if (mondai[a][j][x] == 0) {//空欄のみを解析対象にする。
for (char k = 0; k < mx[a][j][x]; k++) {
if (keizoku == 0)return;
if (mondai[a][y][x] == lst[a][j][x][k]) {
lst[a][j][x][k] = lst[a][j][x][mx[a][j][x] - 1];
lst[a][j][x][mx[a][j][x] - 1] = mondai[a][y][x];
mx[a][j][x]--;
r[j] = 1;//座標(j, x)においてmondai[a][y][x]が候補数字から外され、
//候補数字数も減らされたことを記録している。
}
}
}
}
}
if (keizoku == 0)return;
char s = 3 * (y / 3);
char t = 3 * (x / 3);
for (char j = 0; j < n; j++) {
char yy = s + (j / 3);
char xx = t + (j % 3);
if (yy != y && xx != x) {//自己を対象から外す。
if (mondai[a][yy][xx] == 0) {//空欄のみを解析対象にする。
for (char k = 0; k < mx[a][yy][xx]; k++) {
if (keizoku == 0)return;
if (mondai[a][y][x] == lst[a][yy][xx][k]) {
lst[a][yy][xx][k] = lst[a][yy][xx][mx[a][yy][xx] - 1];
lst[a][yy][xx][mx[a][yy][xx] - 1] = mondai[a][y][x];
mx[a][yy][xx]--;
b[j] = 1;//座標(j, x)においてmondai[a][y][x]が候補数字から外され、
//候補数字数も減らされたことを記録している。
}
}
}
}
}
if (g + 1 < tm)sudokukaiho(a, g + 1);//内側部屋へ
if (cn1[a] == 2) {
return;//複数解
}
if (keizoku == 0)return;
if (g + 1 == tm) {
for (char j = 0; j < n; j++) {
for (char k = 0; k < n; k++) {
gensudoku[a][j][k] = mondai[a][j][k];//解答の保存
}
}
cn1[a]++;
}
for (char j = 0; j < n; j++) {//以下復元作業
if (gy[j] == 1) {
mx[a][y][j]++;
}
if (r[j] == 1) {
mx[a][j][x]++;
}
if (b[j] == 1) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
mx[a][yy][xx]++;
}
}
}
}
void f(char a, char s) {//ヒント数0の数独を解く関数
if (keizoku == 0)return;
char y = Y[a][s];
char x = X[a][s];
//kyokusyokaiseki(a, y, x);
char ii;
if (mx[a][y][x] > 0)ii = rand() % mx[a][y][x]; else ii = 0;
for (char i = 0; i < mx[a][y][x]; i++) {
char iii = (ii + i) % mx[a][y][x];
char g[n] = { 0,0,0,0,0,0,0,0,0 };
char r[n] = { 0,0,0,0,0,0,0,0,0 };
char b[n] = { 0,0,0,0,0,0,0,0,0 };
sudoku[a][y][x] = lst[a][y][x][iii]; //2次元配列に候補数字を代入
//座標(y, x)に値sudoku[a][y][x]が入ったことによってy行にある他のセル
//への影響を調べています。具体的にはy行にある他のセルの候補数字sudoku[a][y][x]
//が入っている場合にsudoku[a][y][x]を候補数字から外します。
//自己から他セルへの影響を調べています。
for (char j = 0; j < n; j++) {
if (j != x) {//自分自身を含めない
if (sudoku[a][y][j] == 0) {//空欄のみを対象とする
for (char k = 0; k < mx[a][y][j]; k++) {
if (keizoku == 0)return;
if (sudoku[a][y][x] == lst[a][y][j][k]) {
lst[a][y][j][k] = lst[a][y][j][mx[a][y][j] - 1];
lst[a][y][j][mx[a][y][j] - 1] = sudoku[a][y][x];
mx[a][y][j]--;
g[j] = 1;//座標(y,j)上で行われた。この情報は復元するときに必要
break;
}
}
}
}
}
if (keizoku == 0)return;
//座標(y, x)に値sudoku[a][y][x]が入ったことによってy行にある他のセル
//への影響を調べています。具体的にはy行にある他のセルの候補数字にsudoku[a][y][x]
//が入っている場合にsudoku[a][y][x]を候補数字から外します。
//自己から他セルへの影響を調べています。
for (char j = 0; j < n; j++) {
if (j != y) {//自分自身を含めない
if (sudoku[a][j][x] == 0) {//空欄のみを対象とする
for (char k = 0; k < mx[a][j][x]; k++) {
if (keizoku == 0)return;
if (sudoku[a][y][x] == lst[a][j][x][k]) {
lst[a][j][x][k] = lst[a][j][x][mx[a][j][x] - 1];
lst[a][j][x][mx[a][j][x] - 1] = sudoku[a][y][x];
mx[a][j][x]--;
r[j] = 1;//座標(y,j)上で行われた。この情報は復元するときに必要
break;
}
}
}
}
}
if (keizoku == 0)return;
//座標(y, x)に値sudoku[a][y][x]が入ったことによって同じブロックにある他のセル
//への影響を調べています。具体的にはブロックにある他のセルの候補数字にsudoku[a][y][x]
//が入っている場合にsudoku[a][y][x]を候補数字から外します。
//ただし、x列とy行についてはすでに調べているので、それらの空欄は対象から外してあります。
//自己から他セルへの影響を調べています。
for (char j = 0; j < n; j++) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
if (yy != y && xx != x) {//自分自身を含めないおよび行と列との重複を防ぐ
if (sudoku[a][yy][xx] == 0) {//空欄のみを対象とする
for (char k = 0; k < mx[a][yy][xx]; k++) {
if (keizoku == 0)return;
if (sudoku[a][y][x] == lst[a][yy][xx][k]) {
lst[a][yy][xx][k] = lst[a][yy][xx][mx[a][yy][xx] - 1];
lst[a][yy][xx][mx[a][yy][xx] - 1] = sudoku[a][y][x];
mx[a][yy][xx]--;
b[j] = 1;//座標(y,j)上で行われた。この情報は復元するときに必要
break;
}
}
}
}
}
if (keizoku == 0)return;
if (s + 1 < hnt)f(a, s + 1); //1つ奥の部屋に入室
if (keizoku == 0)return;
if (cn[a] == 1)return; //数独が1個できた時点で止める
if (s == hnt - 1) { //一番奥に部屋に到達
for (char c = 0; c < 9; c++) {
for (char d = 0; d < 9; d++) {
if (sudoku[a][c][d] == 0) {
if (keizoku == 0)return;
mxcp[a][c][d] = mx[a][c][d];
for (char k = 0; k < mx[a][c][d]; k++) {
lstcp[a][c][d][k] = lst[a][c][d][k];
}
}
}
}
cn[a]++;
if (cn[a] == 1)return; //数独が1個できた時点でとめる
}
for (char j = 0; j < n; j++) {//以下復元作業
if (g[j] == 1) {
mx[a][y][j]++;
}
if (r[j] == 1) {
mx[a][j][x]++;
}
if (b[j] == 1) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
mx[a][yy][xx]++;
}
}
tobi:;
}
}
第8話へ 第10話へ
トップへ