マルチスレッド版数独自動生成ソフト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; //anに変更 変更理由は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話課題を提示します。


第10章第2話へ 第10章第4話へ

本講義トップへ