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

第2話 3次魔方陣自動生成による3次魔方陣全生成


(
2 9 4
7 5 3
6 1 8

2 7 6
9 5 1
4 3 8

4 9 2
3 5 7
8 1 6

4 3 8
9 5 1
2 7 6

6 7 2
1 5 9
8 3 4

6 1 8
7 5 3
2 9 4

8 3 4
1 5 9
6 7 2

8 1 6
3 5 7
4 9 2

生成された3次魔方陣の総数は8です。
)
を実現するプログラム例
#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 = 9;//具体的な数字を使うのではなく、 n を使うと汎用性のあるプログラムになる!

void f(int s);//順列生成関数←引数名をgからsに変更(2026年3月19日)


int a[36]; //将来6次魔方陣まで生成できるように25に変更


int cn = 0; //aをnに変更 変更理由はnuberの頭文字nは整数を表す場合が多いからです


int main() {

  f(0);

  cout << "生成された3次魔方陣の総数は" << cn << "です。" << endl;

  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 == 2) {

          int g = a[0] + a[1] + a[2];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 4) {

          int g = a[3] + a[1] + a[4];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 5) {

          int g = a[0] + a[5] + a[3];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 6) {

          int g = a[0] + a[6] + a[4];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 7) {

          int g = a[6] + a[1] + a[7];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 8) {

          int g = a[4] + a[8] + a[2];

          if (g != 15)h = 0;

        }

      }

      if (h == 1) {

        if (s == 8) {

          int g = a[5] + a[1] + a[8];

          if (g != 15)h = 0;

        }

      }

    }

    if (h == 1) {

      if (s + 1 < n) {

        f(s + 1);

      }

      else {

        cout << a[0] << " " << a[5] << " " << a[3] << endl;

        cout << a[6] << " " << a[1] << " " << a[7] << endl;

        cout << a[4] << " " << a[8] << " " << a[2] << endl;

        cout << endl;

        cn++;

        if (cn % 10 == 0)cout << endl;

      }

    }

  }

}

解説

今まで魔方陣を作り出すことを魔方陣の作成と呼んでいました。

それなのに今回からなぜ魔方陣の自動生成という名称になっているのでしょうか。

それは、今までのプログラムとは次元を異にするからです。

今回のプログラムの方が次元が一つ高いのです。

魔方陣の作成で行っていたことは、

プログラマーが魔方陣のつくり方を教えて、

その命令に従って魔方陣を作っていたのすぎません。

それに対して、今回はコンピュータ自身がすべてのパターンを試行錯誤によって探索してすべての魔方陣を作り出したのです。

たった、8個ですがすべてコンピュータ自身が考えて作ったのです。

4次魔方陣になると総数は7040ですから、

今までとは異なることを心の底から体感することでしょう。


さて、では次に4次魔方陣の自動生成のやり方について説明していきましょう。

これは部屋番号を示したものです。

それぞれの部屋に出席番号で管理された生徒を入れていきます。

そして、色がついているセル(ます)では何らかの合計を計算して、

その合計が4 * (4 * 4 + 1) / 2 = 34 になっているかをチェックしなければなりません。

3は対角線合計、7は逆対角線合計、9は第1行合計、

11は第2行合計、13は第3行合計と第4列合計、

12は第1列合計、14は第2列合計、最後15は第4行合計と共に第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個です。



第10章第1話へ 第10章第3話へ

本講義トップへ