第8講 理詰め解法エンジンの開発
第3話 色塗りを実現するプログラム
を実現するコード例
void ridume(char a);
char onoff[th][n][n][n];
char keizoku;
char A;
char H;
char main() {
clock_t hj, ow;
hj = clock();
hnt = 24;
int teisu = 1;
keizoku = 1;
sng = 1;
H = 1;
unsigned int ii[th];
for (unsigned char i = 0; i < th; i += 1) {
ii[i] = i;
_beginthread(hontai, 0, &ii[i]); //新しいスレッドを起動して、そのスレッド上で関数f1を働かせなさいの命令
}
while (keizoku);
char k = 0;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (sudoku[A][y][x] > 0)k++;
}
}
hys(A);
cout << "予定されたヒント数:" << +hnt << endl;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
mondai[A][y][x] = sudoku[A][y][x];
}
}
for (char i = 0; i < 10; i++) {
ridume(A);
k = 0;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (mondai[A][y][x] > 0)k++;
}
}
cout << "実際のヒント数:" << +k <<" "
<< i + 1 << "回目" << endl;
hym(A);
hyg(A);
for (char i = 0; i < n; i++) {
for (char j = 0; j < n; j++) {
if (mondai[A][i][j] == 0)kyokusyokaiseki(A, i, j);
//セルリスト構造解析 = 単セル解析を積み重ねれば全体構造解析になる
if (mx[A][i][j] == 1) {
mondai[A][i][j] = lst[A][i][j][0];
cout << "候補数字が1つのみの場合があって代入した。" << endl;
}
}
}
if (k == 81)break;
}
int h = 1;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (gensudoku[A][y][x] == mondai[A][y][x])cout << "〇";
else cout << "×";
}
cout << endl;
}
//以降CSVファイルの作成
FILE* fp;
/*ファイル(save.csv)に書き込む*/
if ((fp = fopen("a.csv", "w")) != NULL) {
for (unsigned char i = 0; i < n; i++) {
for (unsigned char j = 0; j < n; j++) {
fprintf(fp, "%d,\n", sudoku[A][i][j]);//数独表示
}
}
for (unsigned char i = 0; i < n; i++) {
for (unsigned char j = 0; j < n; j++) {
fprintf(fp, "%d,\n", gensudoku[A][i][j]);//数独解答
}
}
}
/*忘れずに閉じる*/
fclose(fp);
ow = clock();
cout << "数独生成にかかった時間は平均で" << (double)(ow - hj)
/ (teisu * CLOCKS_PER_SEC) << "秒です。" << endl;
return(0);
}
void hontai(void* aa) {
int a = *(int*)aa;
srand(u - 19 * a);
while (1) {
if (keizoku == 0)return;
zahyousakusei(a);
syokika(a);
f(a, 0);
for (char i = 0; i < n; i++) {
for (char j = 0; j < n; j++) {
mondai[a][i][j] = sudoku[a][i][j];
}
}
sudokukaiho(a, hnt);//数独を解くエンジン 部分構造解析を進めながら問題を解いていく
if (keizoku == 0)return;
if (cn1[a] == 1) {
if (H == 1) {
A = a;
H = 0;
}
keizoku = 0;
return;
}
}
}
void ridume(char a) {
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (mondai[a][y][x] > 0) {
for (char i = 0; i < n; i++) {
if (i != x) {
if (mondai[a][y][i] == 0) {
onoff[a][y][i][mondai[a][y][x] - 1] = 1;
}
}
}
for (char i = 0; i < n; i++) {
if (i != y) {
if (mondai[a][i][x] == 0) {
onoff[a][i][x][mondai[a][y][x] - 1] = 1;
}
}
}
for (char i = 0; i < n; i++) {
char yy = 3 * (y / 3) + (i / 3);
char xx = 3 * (x / 3) + (i % 3);
if (yy != y || xx != x) {
if (mondai[a][yy][xx] == 0) {
onoff[a][yy][xx][mondai[a][y][x] - 1] = 1;
}
}
}
}
}
}
for (char i = 0; i < n; i++) {
for (char y = 0; y < n; y++) {
char k = 0;
for (char j = 0; j < n; j++) {
if (mondai[a][y][j] == 0) {
if (onoff[a][y][j][i] == 0)k++;
}
}
if (k == 1) {
char xk;
for (char j = 0; j < n; j++) {
if (mondai[a][y][j] == 0) {
if (onoff[a][y][j][i] == 0) {
xk = j;
break;
}
}
}
mondai[a][y][xk] = i + 1;
for (char j = 0; j < n; j++) {
if (j != xk) {
if (mondai[a][y][j] == 0) {
onoff[a][y][j][i] = 1;
}
}
}
for (char j = 0; j < n; j++) {
if (j != y) {
if (mondai[a][j][xk] == 0) {
onoff[a][j][xk][i] = 1;
}
}
}
for (char j = 0; j < n; j++) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (xk / 3) + (j % 3);
if (yy != y && xx != xk) {
if (mondai[a][yy][xx] == 0) {
onoff[a][yy][xx][i] = 1;
}
}
}
}
}
for (char x = 0; x < n; x++) {
char k = 0;
for (char j = 0; j < n; j++) {
if (mondai[a][j][x] == 0) {
if (onoff[a][j][x][i] == 0)k++;
}
}
if (k == 1) {
char yk;
for (char j = 0; j < n; j++) {
if (mondai[a][j][x] == 0) {
if (onoff[a][j][x][i] == 0) {
yk = j;
break;
}
}
}
mondai[a][yk][x] = i + 1;
for (char j = 0; j < n; j++) {
if (j != yk) {
if (mondai[a][j][x] == 0) {
onoff[a][j][x][i] = 1;
}
}
}
for (char j = 0; j < n; j++) {
if (j != x) {
if (mondai[a][yk][j] == 0) {
onoff[a][yk][j][i] = 1;
}
}
}
for (char j = 0; j < n; j++) {
char yy = 3 * (yk / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
if (yy != yk || xx != x) {
if (mondai[a][yy][xx] == 0) {
onoff[a][yy][xx][i] = 1;
}
}
}
}
}
for (char y = 0; y < 9; y ++) {
for (char x = 0; x < 9; x++) {
if (mondai[A][y][x] > 0) {
char k = 0;
for (int j = 0; j < 9; j++) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
if (yy != y || xx != x) {
if (mondai[a][yy][xx] == 0) {
if (onoff[A][yy][xx][i] == 0)k++;
}
}
}
if (k == 1) {
char yk;
char xk;
for (int j = 0; j < 9; j++) {
char yy = 3 * (y / 3) + (j / 3);
char xx = 3 * (x / 3) + (j % 3);
if (yy != y || xx != x) {
if (mondai[a][yy][xx] == 0) {
if (onoff[A][yy][xx][i] == 0) {
yk = yy;
xk = xx;
break;
}
}
}
}
mondai[A][yk][xk] = i + 1;
for (int j = 0; j < n; j++) {
if (j != xk) {
onoff[A][yk][j][i] = 1;
}
}
for (char j = 0; j < n; j++) {
if (j != x) {
if (mondai[a][yk][j] == 0) {
onoff[a][yk][j][i] = 1;
}
}
}
for (char j = 0; j < n; j++) {
char yy = 3 * (yk / 3) + (j / 3);
char xx = 3 * (xk / 3) + (j % 3);
if (yy != yk || xx != x) {
if (mondai[a][yy][xx] == 0) {
onoff[a][yy][xx][i] = 1;
}
}
}
}
}
}
}
}
}
・
・
・
テキストファイル
本当は
for (char i = 0; i < 10; i++) {
ridume(A);
k = 0;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (mondai[A][y][x] > 0)k++;
}
}
cout << "実際のヒント数:" << +k <<" "
<< i + 1 << "回目" << endl;
hym(A);
hyg(A);
for (char i = 0; i < n; i++) {
for (char j = 0; j < n; j++) {
if (mondai[A][i][j] == 0)kyokusyokaiseki(A, i, j);
//セルリスト構造解析 = 単セル解析を積み重ねれば全体構造解析になる
if (mx[A][i][j] == 1) {
mondai[A][i][j] = lst[A][i][j][0];
cout << "候補数字が1つのみの場合があって代入した。" << endl;
}
}
}
if (k == 81)break;
}
int h = 1;
for (char y = 0; y < n; y++) {
for (char x = 0; x < n; x++) {
if (gensudoku[A][y][x] == mondai[A][y][x])cout << "〇";
else cout << "×";
}
cout << endl;
}
本当は青はルートスレッドではなく派生スレッドでやりたいところですが、
疲れてしまったので明日ということでお願いします。
原理と方法
概要 | 概要 | |
原理1 | ライン排除 | |
原理2 | ライン間接排除 | |
原理3 | ブロック排除 | |
原理4 | 1:1対応確定と排除 | |
方法 | 空欄候補数字探索 | |
原理5 | #排除 |
今回組み込んだのはライン排除・ブロック排除・ライン間接排除のみです。
重要なことを言い忘れていました。
かつてライン反照排除と呼んでいたものは、
ライン間接排除に名称が変更してあるということです。
それからセルリスト絞り込みも名称が変更してあり、
空欄候補数字探索となっています。
で、これはすべに組み込んであることは皆さん理解していますよね。
本稿では単セルリスト解析と呼んでいるものです。
予定通り派生スレッドに組み込むことに成功しました。
極めて速くなりました。
原理4と原理5は組み込んでありませんが、
おそらく90%以上の確度で理詰めで解ける問題を生成していますので、
マルチスレッド版ver1の完成を宣言したいと思います。
C++プログラムは1割程度で理詰めで解けない問題を作ってしまいますが、
成功するまでVBA何回でもC++に指令しますから、
C++とVBAを組み合わせたものは100%の精度で理詰めのみで解ける数独を生成できます。
もちろん、ver2以降では残りのコツを組み込むことによって、
VBAの助力を必要としない完全バージョンとします。
第2話へ 第4話へ
トップへ