第8講 理詰め解法エンジンの開発
第4話 確かめを派生スレッドで行う!

を実現するコード例
テキストファイル

#pragma warning(disable: 4996)
#include<iostream>
#include<conio.h> //while (!_kbhit())を使うために必要
#include <process.h> /* _beginthread, _endthread を使うために必要*/
using namespace std;
void f(char a, char s); //sは次元番号=部屋番号
const char n = 9; //16次数独や25次数独も考えてnと一般化した。
const char th = 30;
char hnt = 26;
const char tm = 81;
char cn[th]; //順列を数える変数
char cn1[th]; //順列を数える変数
char sudoku[th][n][n]; //解答用2次元配列(魔方陣の研究から始まったので本体をmとしてきた。
char mondai[th][n][n];
//mondai[th][n][n]は問題用であるが、解いていく過程で空欄が埋められて行って
//最終的にはsudoku[th][n][n]と同じになってしまう。
char gensudoku[th][n][n];
char sng = 1;//1ならば真
void syokika(char a);//初期化
void hyg(char a);//数独をコンソール画面に表示する関数
void hym(char a);//数独に向かう過程をコンソール画面に表示する関数
void hys(char a);//数独解答をコンソール画面に表示する関数
void kyokusyokaiseki(char a, char y, char x);//単セル解析(候補数字探索)
void nextcell(char a, char g);//次に入力するセルを探索する関数
void sudokukaiho(char a, char g);//数独を解くエンジン 部分構造解析を進めながら問題を解いていく
void hitaisyou(char a);//非対称の問題配置
void sayutaisyou(char a);//左右対称
void jyogetaisyou(char a);//上下対称
void tentaisyou(char a);//点対称
void kokoro(char a);
void sayujyogetaisyou(char a);//左右にも上下にも対象 = 線対称にして点対称 = 完全対称
char lst[th][n][n][n];//セルリスト解析によって可能な数字を収容する4次元配列
char lstcp[th][n][n][n];//セルリスト解析によって可能な数字を収容する4次元配列のコピー
char mx[th][n][n];//セルの数字候補の個数
char mxcp[th][n][n];//セルにおける数字候補の個数のコピー
char Y[th][81], X[th][81];//次に入力するセルのy座標とx座標
unsigned u = (unsigned)time(NULL);
//マルチスレッド化した際に、
//ルートスレッドと発生させたスレッドが共有できるようにグローバル変数に変更
void hontai(void* a);
void zahyousakusei(char a);
void ridume(char a);
char onoff[th][n][n][n];
char keizoku;
char A;
char H;
int main() {
  clock_t hj, ow;
  hj = clock();
  hnt = 22;
  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);
  k = 0;
  for (char y = 0; y < n; y++) {
    for (char x = 0; x < n; x++) {
      if (mondai[A][y][x] > 0)k++;
    }
  }
  cout << "予定されたヒント数:" << +hnt << endl;
  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 << endl;
  hym(A);
  int h = 1;
  char hr[n];
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
    for (char x = 0; x < n; x++)hr[mondai[A][y][x] - 1] = 1;
    for (char i = 0; i < n; i++) {
      if (hr[i] == 0) {
        cout << "行異常:" << +y << endl;
        h = 0;
        goto tobi;
      }
    }
  }
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
    for (char x = 0; x < n; x++)hr[mondai[A][x][y] - 1] = 1;
    for (char i = 0; i < n; i++) {
      if (hr[i] == 0) {
        cout << "列異常:" << +y << endl;
        h = 0;
        goto tobi;
      }
    }
  }
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
      for (char x = 0; x < n; x++) {
        hr[mondai[A][3 * (y / 3) + (x / 3)][3 * (y % 3) + (x % 3)] - 1] = 1;
      }
      for (char i = 0; i < n; i++) {
        if (hr[i] == 0) {
          cout << "ブロック異常:" << +i << endl;
          goto tobi;
        }
      }
    }
    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);//数独を解くエンジン 部分構造解析を進めながら問題を解いていく
    for (char y = 0; y < n; y++) {
      for (char x = 0; x < n; x++) {
        if (sudoku[A][y][x] == mondai[A][y][x]) {
          cout << "〇";
        }
        else {
          cout << "×";
          h = 0;
        }
      }
      cout << endl;
    }
  tobi:;
  if (h == 1)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;
  //while (!_kbhit()); //待機させるための命令
  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];
      }
    }
    for (char i = 0; i < 20; i++) {//派生スレッドで実際に配置された数字の個数が81なっているか確かめている
      ridume(a);
      char k = 0;
      for (char y = 0; y < n; y++) {
        for (char x = 0; x < n; x++) {
          if (mondai[a][y][x] > 0)k++;
        }
      }
      if (k == 81) {
        cn1[a] = 1;
        if (H == 1) {
          A = a;
          H = 0;
        }
        keizoku = 0;
        return;
      }
    }

    //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 = 0;
        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 = 0;
        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 = 0;
            char xk = 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) {
                    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;
                }
              }
            }
          }
        }
      }
    }
  }
}

検査している内容は、
  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 << endl;
  hym(A);
  int h = 1;
  char hr[n];
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
    for (char x = 0; x < n; x++)hr[mondai[A][y][x] - 1] = 1;
    for (char i = 0; i < n; i++) {
      if (hr[i] == 0) {
        cout << "行異常:" << +y << endl;
        h = 0;
        goto tobi;
      }
    }
  }
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
    for (char x = 0; x < n; x++)hr[mondai[A][x][y] - 1] = 1;
    for (char i = 0; i < n; i++) {
      if (hr[i] == 0) {
        cout << "列異常:" << +y << endl;
        h = 0;
        goto tobi;
      }
    }
  }
  for (char y = 0; y < n; y++) {
    for (char i = 0; i < n; i++)hr[i] = 0;
      for (char x = 0; x < n; x++) {
        hr[mondai[A][3 * (y / 3) + (x / 3)][3 * (y % 3) + (x % 3)] - 1] = 1;
      }
      for (char i = 0; i < n; i++) {
        if (hr[i] == 0) {
          cout << "ブロック異常:" << +i << endl;
          goto tobi;
        }
      }
    }
    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);//数独を解くエンジン 部分構造解析を進めながら問題を解いていく
    for (char y = 0; y < n; y++) {
      for (char x = 0; x < n; x++) {
        if (sudoku[A][y][x] == mondai[A][y][x]) {
          cout << "〇";
        }
        else {
          cout << "×";
          h = 0;
        }
      }
      cout << endl;
    }
  tobi:;
  if (h == 1)cout << "すべて正常でした。" << endl;

答えの行上・列上・ブロック上に数字の重複がないこと、

sudokukaiho(A, hnt);//数独を解くエンジン 部分構造解析を進めながら問題を解いていく

で解かせた解答と派生スレッドが作った解答と比較しながら、

すべてが一致していることを確認しています。


第3話へ
 第5話へ

トップへ