第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話へ

トップへ