マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第11章 マルチスレッドプログラミング
第13話 第9話Ⅳの答え合わせ
Ⅳ Ⅲで入れた強制終了に関する項目はいったん外してください。
魔方陣の条件を付け加えましょう。
ⅰ 対角線が埋まったら対角線合計を計算して魔方陣の合計に一致しなければ h = 0; とすることによってそれ以降の処理を止めて
関数fの最初のfor文が進むようにしましょう。
ⅱ 行が埋まったら行合計を計算して魔方陣の合計に一致しなければ h = 0; とすることによってそれ以降の処理を止めて
関数fの最初のfor文が進むようにしましょう。
ⅲ 列が埋まったら列合計を計算して魔方陣の合計に一致しなければ h = 0; とすることによってそれ以降の処理を止めて
関数fの最初のfor文が進むようにしましょう。
の実現
#pragma warning(disable: 4996)//第2編のために必要
#include<iostream>//インクルードファイルiostreamの読み込み
#include<conio.h>//while(!_kbhit());を使うためのお呪い
#include<string> //文字列変数を使えるようにするために組み込む
#include <iomanip> //setprecisionを使えるように組み込む
#include <cmath>//powなどを使うときに必要
#include <ctime>//time()(←現時刻発生する関数)を使うために必要
using namespace std;//coutを使うときに必要なお呪い
#include <process.h>//_beginthreadを使うために必要
void 変身の術関数(void* aa);//スレッドを派生させる関数
const size_t n = 4;
const size_t th = n * n;
void f(int p, int s);//魔方陣生成関数
void 2次座標生成();
size_t 継続[th];
size_t m[100][th][n][n];//魔方陣を収納する4次元配列
size_t a[th][n][n];//魔方陣を形成するための作業用3次元配列
size_t cn[th];//それぞれのスレッドにおける魔方陣をカウントする1次元配列
size_t y[th];//縦座標
size_t x[th];//横座標
size_t b[n][n];//y座標・x座標形成のための2次元配列
size_t mg = n * (th + 1) / 2;//魔方陣の対角線または行または列の合計
int main() {
clock_t hj, ow;
hj = clock();
for (size_t i = 0; i < th; i++) {
継続[i] = 1;
cn[i] = 0;
}
2次座標生成();
size_t ii[th];
for (size_t i = 0; i < th; i++) {
ii[i] = i;
_beginthread(変身の術関数, 0, &ii[i]); //新しいスレッドを起動して、そのスレッド上で変身の術関数を展開せよの命令
}
while (1) {
size_t 合計 = 0;
for (size_t i = 0; i < th; i++)合計 += 継続[i];
if (合計 == 0)break;
}
ow = clock();
cout << "魔方陣生成時間は" << (double)(ow - hj) / CLOCKS_PER_SEC << "秒です。" << endl;
cout << "全課程修了" << endl;
while (!_kbhit());//待機させるための命令
return(0);
}
void 変身の術関数(void* aa) {//異世界番号aaホテル
size_t p = *(size_t*)aa;//異世界番号をpに変更
a[p][y[0]][x[0]] = p + 1;//部屋番号0の部屋に入れる生徒の出席番号は p +
1 に固定されている。
f(p, 1);//f(p,s)の s は異世界pホテルの部屋番号を表し、その部屋に入れる生徒の出席番号は
//のsより若い部屋番号の生徒の出席番号と重複しなければ1~16の範囲で任意である。
//部屋番号0のみが入れる生徒の出席番号が p + 1 に固定されている。
//したがって、異世界番号 p と直に出席番号が関係しているのは部屋番号0の部屋のみである。
継続[p] = 0;//この世界はしょうめつするので、この世界の存在を理由にルートスレッドが待機しないように 0 を入力している。
}
void f(int p, int s) {//魔方陣生成関数
for (size_t i = 0; i < th; i++) {
size_t h = 1;
for (size_t j = 0; j < s; j++) {
if (a[p][y[j]][x[j]] == i + 1) {
h = 0;
break;
}
}
if (h == 1) {
a[p][y[s]][x[s]] = i + 1;
}
if (h == 1) {
if (y[s] == n - 1 && x[s] == n - 1) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][j][j];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] == n - 1 && x[s] == 0) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][j][n - 1 - j];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] == 0 && x[s] == n - 2) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][y[s]][j];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] > 0 && y[s] < n - 1 && x[s] == n - 1) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][y[s]][j];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] == n - 2 && x[s] == 0) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][j][x[s]];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] == n - 1 && x[s] > 0 && x[s] < n - 1) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][j][x[s]];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (y[s] == n - 1 && x[s] == n - 2) {
size_t 合計 = 0;
for (size_t j = 0; j < n; j++) {
合計 += a[p][y[s]][j];
}
if (合計 != mg)h = 0;
}
}
if (h == 1) {
if (s + 1 < th) {
f(p, s + 1);
}
else {
cn[p]++;
if (cn[p] == 100) {
a[p][y[s]][x[s]] = 0;
return;
}
}
}
if (cn[p] == 100) {
a[p][y[s]][x[s]] = 0;
return;
}
a[p][y[s]][x[s]] = 0;
}
}
void 2次座標生成() {//y横座標とx縦座標生成
int i, j, c;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
b[i][j] = -1;
}
}
for (i = 0; i < n; i++) {
b[i][i] = i;
}
c = n - 1;
for (i = 0; i < n; i++) {
if (b[i][n - 1 - i] == -1) {
c++;
b[i][n - 1 - i] = c;
}
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (b[i][j] == -1) {
c++;
b[i][j] = c;
}
}
}
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
x[b[i][j]] = j;
y[b[i][j]] = i;
}
}
}
Ⅴ 魔方陣が完成する度に、int m[100][th][n][n]に保存します。
冒頭に用意する配列は
int a[th][n][n];//作業用3次元配列
int m[100][th][n][n];//保存用4次元配列
初心者には2次元配列でさえ重い課題なのに3次元配列、4次元配列が出てきただけで拒絶反応が起きると思いますが、
とりあえずm[魔方陣番号][異世界番号][行][列]であると理解してください。
ただし、普通の世界では1からカウントしますが、プログラミングの世界では0からカウントすることに注意してください。
m[p][q][r][s]なら異世界番号の q + 1 の異世界が p + 1 番目に作り出した魔方陣の r + 1 行 s + 1 列を意味します。
それぞれに1加えてある理由は普通の世界のカウントに直すためです。
0からカウントすることに慣れている人は
m[p][q][r][s]なら異世界番号の q の異世界が p 番目に作り出した魔方陣の r 行 s 列を意味すると思ってください。
ここまでついてきた皆さんはすでに初心者ではありません。
ですから、0からカウントとすることになれてください。
の条件を加えましょう。