第3講 試行錯誤法でヒント数0数独の解答を作る(2)
第7話 疑似乱数を使い毎回異なる数独が生成されるようにする
・
・
・
を実現するプロジェクト例
#include<iostream>
#include<conio.h> //while (!_kbhit()); を使うためのお呪い。
using namespace std;
void f(int s); //sは次元番号=部屋番号
int n; //次元数(部屋数)をキーボードから指定
int cn = 0; //順列を数える変数
int m[9][9];//本体2次元配列(魔方陣の研究から始まったので本体をmとしてきた
int sng = 1;//1ならば真
int main() {
//cout << "n = ";
//scanf_s("%d", &n); //キーボードからnの値を取得
n = 9;
clock_t hj, ow;
hj = clock();
f(0);
ow = clock();
if (sng == 1)cout << endl << "すべて正常でした。" <<
endl;
cout << "計算時間は" << (double)(ow - hj) / CLOCKS_PER_SEC
<< "秒です。" << endl;
cout << "順列の場合の数は" << cn << "です。"
<< endl;
cout << "プロジェクト成功" << endl;
while (!_kbhit()); //待機させるための命令
return(0);
}
void f(int s) {
int y = s / 9; //縦座標
int x = s % 9; //横座標
unsigned u = (unsigned)time(NULL);
srand(u); //シード値を現在の時刻から取得
int ii = rand() % 9; //始まりをランダムにする
for (int i = 0; i < n; i++) {
m[y][x] = (i + ii) % n + 1; //2次元配列に1から9までの整数を入力
if (x > 0) {
for (int j = 0; j < x; j++) {
if (m[y][x] == m[y][j])goto tobi; //行の重複を防ぐ
}
}
if (y > 0) {
for (int j = 0; j < y; j++) {
if (m[j][x] == m[y][x])goto tobi; //列の重複を防ぐ
}
}
if (y % 3 == 1) {
for (int j = 0; j < 3; j++) {
if ((x / 3) * 3 + j != x) {
if (m[y][x] == m[y - 1][(x / 3) * 3 + j])goto tobi; //ブロックの重複を防ぐ
}
}
}
if (y % 3 == 2) {
for (int j = 0; j < 3; j++) {
if ((x / 3) * 3 + j != x) {
if (m[y][x] == m[y - 2][(x / 3) * 3 + j])goto tobi; //ブロックの重複を防ぐ
if (m[y][x] == m[y - 1][(x / 3) * 3 + j])goto tobi; //ブロックの重複を防ぐ
}
}
}
if (s + 1 < n * n)f(s + 1); //1つ奥の部屋に入室
if (cn == 100)return; //数独が100個で来た時点で止める
if (sng == 0)return; //異常があった時点でプロジェクトを止める
if (s == n * n - 1) { //一番奥に部屋に到達
cout << endl;
for (int j = 0; j < 17; j++)cout << " -"; //最初の横線
cout << endl;
for (int j = 0; j < n; j++) {
cout << "|";//縦線
for (int k = 0; k < n; k++) {
cout << " " << m[j][k] << "
"; //2次元配列を2次元に並べる
if (k % 3 == 2)cout << "|";//縦線
}
if (j % 3 == 2) {
cout << endl;
for (int k = 0; k < 17; k++)cout << " -";
//横線
}
cout << endl;
}
int p[9];//重複検査のための配列
int kr;
for (int j = 0; j < n; j++) {
for (int k = 0; k < n; k++)p[k] = 0;//初期化
kr = 1; //初期化
for (int k = 0; k < n; k++) {
p[m[j][k] - 1] = 1;
}
for (int k = 0; k < n; k++) {
if (p[k] == 0) {
cout << "×";
kr = 0;
sng = 0;
goto tobi1;
}
}
for (int k = 0; k < n; k++)p[k] = 0;//初期化
kr = 1; //初期化
for (int k = 0; k < n; k++) {
p[m[k][j] - 1] = 1;
}
for (int k = 0; k < n; k++) {
if (p[k] == 0) {
cout << "×";
kr = 0;
sng = 0;
goto tobi1;
}
}
for (int k = 0; k < n; k++)p[k] = 0;//初期化
kr = 1; //初期化
for (int k = 0; k < n; k++) {
p[m[3 * (j / 3) + (k / 3)][3 * (j % 3) + (k % 3)] - 1] = 1;
}
for (int k = 0; k < n; k++) {
if (p[k] == 0) {
cout << "×";
kr = 0;
sng = 0;
goto tobi1;
}
}
}
tobi1:;
if (kr == 1)cout << "〇";
cn++;
if (cn == 100)return; //数独が100個できた時点でとめる
}
tobi:;
}
}
変更場所は
unsigned u = (unsigned)time(NULL);
srand(u); //シード値を現在の時刻から取得
int ii = rand() % 9; //始まりをランダムにする
for (int i = 0; i < n; i++) {
m[y][x] = (i + ii) % n + 1; //2次元配列に1から9までの整数を入力
の部分だけです。
シード値を現在時刻から得ているために、
毎回異なったものとなります。
第6話へ 第8話へ
トップ