マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第10章 関数の再帰的使用によって魔方陣を自動生成する
第3話 4次魔方陣自動生成による4次魔方陣全生成

(
11 7 2 14
6 10 15 3
16 1 7 10
4 13 11 6
9 8 2 15
5 12 14 3
16 4 9 5
1 13 8 12
6 10 3 15
11 7 14 2
16 1 10 7
4 13 6 11
5 12 3 14
9 8 15 2
16 4 5 9
1 13 12 8
10 6 3 15
7 11 14 2
16 1 6 11
4 13 10 7
9 8 3 14
5 12 15 2
16 3 9 6
2 13 7 12
5 10 4 15
11 8 14 1
16 2 9 7
3 13 6 12
5 11 4 14
10 8 15 1
16 3 5 10
2 13 11 8
9 6 4 15
7 12 14 1
16 2 5 11
3 13 10 8
9 7 4 14
6 12 15 1
生成された4次魔方陣総数は7040個です。
)
を実現するコード例←2026年3月24日 ミスがありました。申し訳ありません。謝罪申し上げます。
#include<iostream>//インクルードファイルiostreamの読み込み
#include<conio.h>//while(!_kbhit());を使うためのお呪い
#include<string> //文字列変数を使えるようにするために組み込む
#include <iomanip> //setprecisionを使えるように組み込む
#include <cmath>//powなどを使うときに必要
#include <ctime>//time()(←現時刻発生する関数)を使うために必要
using namespace std;//coutを使うときに必要なお呪い
const int n = 16;//具体的な数字を使うのではなく、 n を使うと汎用性のあるプログラムになる!
void f(int s);//順列生成関数←引数名をgからsに変更(2026年3月19日)
int a[25]; //将来5次魔方陣まで生成できるように25に変更
int cn = 0; //aをnに変更 変更理由はnuberの頭文字nは整数を表す場合が多いからです。
int main() {
f(0);
cout << endl << "生成された4次魔方陣総数は" << cn << "個です。" << endl;//←2026年3月19日訂正
while (!_kbhit());//待機させるための命令
return(0);
}
void f(int s) {
int h;
for (int i = 0; i < n; i++) {
if (s == 0)a[s] = i + 1;
h = 1;
if (s > 0) {
for (int j = 0; j < s; j++) {
if (a[j] == i + 1) {
h = 0;
break;
}
}
if (h == 1) {
a[s] = i + 1;
}
if (h == 1) {
if (s == 3) {
int g = a[0] + a[1] + a[2] + a[3];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 7) {
int g = a[4] + a[5] + a[6] + a[7];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 11) {
int g = a[10] + a[1] + a[5] + a[11];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 12) {
int g = a[0] + a[10] + a[12] + a[7];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 13) {
int g = a[4] + a[11] + a[13] + a[3];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 13) {
int g = a[12] + a[6] + a[2] + a[13];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 14) {
int g = a[8] + a[1] + a[6] + a[14];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 15) {
int g = a[7] + a[14] + a[15] + a[3];
if (g != 34) {
h = 0;
}
}
}
if (h == 1) {
if (s == 15) {
int g = a[9] + a[5] + a[2] + a[15];
if (g != 34) {
h = 0;
}
}
}
}
if (h == 1) {
if (s + 1 < n) {
f(s + 1);
}
else {
int b[16] = { 0,8,9,4,10,1,5,11,12,6,2,13,7,14,15,3 };
for (int j = 0; j < 16; j++) {
if (a[b[j]] < 10) {
cout << " " << a[b[j]] << " ";
}
else {
cout << a[b[j]] << " ";
}
if (j > 0 && (j + 1) % 4 == 0)cout << endl;
}
cout << endl;
cn++;
}
}
}
}
読者の仮屋崎さんから一般化のための天才的なアイデアが2010年ごろに寄せられました。



(
0 8 9 4
10 1 5 11
12 6 2 13
7 14 15 3
)

(
0 9 10 11 5
12 1 13 6 14
15 16 2 17 18
19 7 20 3 21
8 22 23 24 4
)

(
0 12 13 14 15 6
16 1 17 18 7 19
20 21 2 8 22 23
24 25 9 3 26 27
28 10 29 30 4 31
11 32 33 34 35 5
)

(
0 13 14 15 16 17 7
18 1 19 20 21 8 22
23 24 2 25 9 26 27
28 29 30 3 31 32 33
34 35 10 36 4 37 38
39 11 40 41 42 5 43
12 44 45 46 47 48 6
)

(
0 16 17 18 19 20 21 8
22 1 23 24 25 26 9 27
28 29 2 30 31 10 32 33
34 35 36 3 11 37 38 39
40 41 42 12 4 43 44 45
46 47 13 48 49 5 50 51
52 14 53 54 55 56 6 57
15 58 59 60 61 62 63 7
)
仮屋崎さんの方法ではn次魔方陣の n が偶数でも奇数でも1次元と2次元を関係づけることができます。
第4話ではその方法を実現するコードをお見せして、
そのコードを第5話・第6話・第8話で解説して、
第8話で魔方陣の普遍化 = 一般化 = 汎用化せよという第9話課題を提示します。