マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第6章 6次魔方陣・8次魔方陣の作成
⁂私が2022を使っている間に2026の設定が変わってしまっています。
がUTF‑8になっている場合にはShift-JISに変更して
エンコード付きで保存してください。⁂
第11話 6次魔方陣の小さい順での並び替え

(
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36
111
36 32 4 3 5 31 111
12 29 27 10 26 7 111
19 17 22 21 14 18 111
13 20 16 15 23 24 111
25 11 9 28 8 30 111
6 2 33 34 35 1 111
111 111 111 111 111 111 111
1 2 3 4 5 6
7 8 9 10 11 12
13 14 15 16 17 18
19 20 21 22 23 24
25 26 27 28 29 30
31 32 33 34 35 36
)
を実現するプログラムコード例
#include<iostream>//インクルードファイルiostreamの読み込み
#include<conio.h>//while(!_kbhit());を使うためのお呪い
#include<string> //文字列変数を使えるようにするために組み込む
#include <iomanip> //setprecisionを使えるように組み込む
#include <cmath>//powなどを使うときに必要
#include <ctime>//time()(←現時刻発生する関数)を使うために必要
using namespace std;//coutを使うときに必要なお呪い
void 魔方陣();//横と縦の2方向を持つ2次元for文体験
const int n = 6;//これからは具体的な数字を使わずにnとする。左の6を8などに変更すれば8次魔方陣に対応する
//n = 6 の一か所だけ具体的な数字を使い、他ではすべて n を使ってください。
int main() {//私は社長だ。
魔方陣();
while (!_kbhit());//待機させるための命令
return(0);//int main()終わるためのお呪い
}
void 魔方陣() {
int a[n][n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = n * i + j + 1;//自然配列を生成してaに収納する
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
//自然配列に体裁を整えて表示する。
if (a[i][j] < 10)cout << " ";
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
int u;//a[i][j]などのデータを一時保存する
//対角線部分を交換する
for (int i = 0; i < n / 2; i++) {//2026年2月16日修正 修正内容(3→ n / 2) 修正理由
具体的数字3が入ってしまっている
u = a[i][i];//ごめんなさい。以下にケアレスミスがあり2026年2月18日に訂正しました。ミスをお詫び申し上げます。
//a[i][i]のデータがa[n - 1 - i][n - 1 - i]に上書きされる前に
//のデータに上書きされる前にuに保存
a[i][i] = a[n - 1 - i][n - 1 - i];
//a[i][i]のデータをa[n - 1 - i][n - 1 - i]のデータで上書き
a[n - 1 - i][n - 1 - i] = u;
//a[n - 1 - i][n - 1 - i]のデータをa[i][i]の元データで保存
}
//対角線部分の交換終了
//逆対角線部分を交換する
for (int i = 0; i < n / 2; i++) {//2026年2月17日修正 修正内容(3 → n / 2) 修正理由 具体的数字3が入ってしまっている
u = a[i][n - 1 - i];
//a[i][n - 1 - i]のデータがa[n - 1 - i][i]のデータに上書きされる前にuに保存
a[i][n - 1 - i] = a[n - 1 - i][i];
//a[i][n - 1 - i]のデータをa[n - 1 - i][i]のデータで上書き
a[n - 1 - i][i] = u;
//a[n - 1 - i][i]のデータをa[i][n - 1 - i]の元データで保存
}
//逆対角線部分の交換終了
//明るい紫色の部分の交換
for (int i = 0; i < n / 2; i++) {//2026年2月16日修正 修正内容(3→ n / 2) 修正理由 具体的数字3が入ってしまっている
u = a[i][(2 + i) % (n / 2)];//2026年2月16日修正 修正内容(3→ (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[i][(2 + i) % (n / 2)]のデータがa[i][n - 1 - ((2 + i) % (n / 2))]
// のデータ上書きされる前にuに保存
a[i][(2 + i) % (n / 2)] = a[i][n - 1 - ((2 + i) % (n / 2))];
//2026年2月16日修正 修正内容(3→ (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[i][(2 + i) % (n / 2)]のデータをa[i][n - 1 - ((2 + i) % (n / 2))]のデータで上書き
a[i][n - 1 - ((2 + i) % (n / 2))] = u;
//2026年2月16日修正 修正内容(3→ (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[i][n - 1 - ((2 + i) % (n / 2))]のデータをa[i][(2 + i) % (n / 2)]の元データで上書き
}
//明るい紫色の部分の交換終了
//緑の部分の交換終了
for (int i = 0; i < n / 2; i++) {//2026年2月16日修正 修正内容(3→ n / 2) 修正理由 具体的数字3が入ってしまっている
u = a[i][(1 + i) % (n / 2)];
//2026年2月17日修正 修正内容(% 3→ % (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[i][(1 + i) % (n / 2)]のデータがa[n - 1 - i][(1 + i) % (n / 2)]
// のデータに上書きされる前にuに保存
a[i][(1 + i) % (n / 2)] = a[n - 1 - i][(1 + i) % (n / 2)];
//2026年2月17日修正 修正内容(% 3→ % (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[i][(1 + i) % (n / 2)]のデータをa[n - 1 - i][(1 + i) % (n / 2)]のデータで上書き
a[n - 1 - i][(1 + i) % (n / 2)] = u;
//2026年2月17日修正 修正内容(% 3→ % (n / 2)) 修正理由 具体的数字3が入っていまっている
//a[n - 1 - i][(1 + i) % (n / 2)]のデータをa[i][(1 + i) % (n / 2)]の元データで上書き
}
//緑の部分の交換終了
int g[n] = { 0,0,0,0,0,0 };//gの定義と初期化
int r[n] = { 0,0,0,0,0,0 };//rの定義と初期化
int t[2] = { 0,0 };//tの定義と初期化
//各行の合計計算
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
g[i] = g[i] + a[i][j];
}
}
//各列の合計計算
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
r[i] = r[i] + a[i][j];
}
}
//各対角線の合計計算
for (int i = 0; i < n; i++) {
t[0] = t[0] + a[i][i];
t[1] = t[1] + a[i][n - 1 - i];
}
//6次魔方陣 + 各合計の表示
cout << endl;
for (int i = 0; i < n; i++) {
cout << " ";
}
cout << " " << t[1] << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (a[i][j] < 10)cout << " ";
cout << " " << a[i][j] << " ";
}
cout << " " << g[i];
cout << endl;
}
cout << endl;
for (int i = 0; i < n; i++) {
cout << r[i] << " ";
}
cout << " " << t[0] << " ";
//6次魔方陣 + 各合計の表示終了
//以降魔方陣を小さい順に並べ替える作業
int c[n * n];//魔方陣を複写するための1次元配列
//魔方陣の内容を複写のための1次元配列にコピー
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
c[n * i + j] = a[i][j];
}
}
//c[i][j]の並び替え
for (int i = 0; i < n * n; i++) {
int min = 100;//最小値を表すminと定義して、最小ととしてあり得ない100で初期化
int jk;//最小値になる j を保存するための変数
for (int j = i; j < n * n; j++) {
if (c[j] < min) {
min = c[j];//最小値の更新
jk = j;//その際jの記録
}
}
//c[i]のデータとc[k]のデータを交換する
if (jk > i) {
u = c[i];//上書きされる前にc[i]のデータを保存
c[i] = c[jk];//c[i]のデータをc[k]のデータで上書き
c[jk] = u;//c[k]のデータをc[i]の元データで上書き
}
//c[i]のデータとc[k]のデータを交換する終了
}
//以降魔方陣を小さい順に並べ替える作業終了
//並び変えたデータを体裁を整えて表示
cout << endl << endl;
for (int i = 0; i < n * n; i++) {
if (c[i] < 10)cout << " ";//c[i]のデータが一桁の場合半角スペースを入れる
cout << c[i] << " ";
if (i % n == n - 1)cout << endl;
}
cout << endl;
}
if (i % n == n - 1)cout << endl;
この使い方重要です。
是非忘れる前の反復をやって覚えてください。
次話の課題は8次魔方陣の作成です。
次話で第6章は終了にして、
第7章では関数について学びます。
数学が苦手だった人は関数によい思い出はないかもしれませんが、
次話で関数を学べば関数とはとても魅力的なものであることがわかります。
この世の中は関数関係で成り立っているという分析哲学の主張に、
私は全面的に賛成しております。

黄色を中心の点に対して点対称移動
明るい紫を中央の直線に対して線対称移動
緑を中央の直線に対して線対称移動
によって皆さん8次魔方陣に作成しましょう。

//2026年2月16日修正 修正内容(3→ n / 2) 修正理由 具体的数字3が入ってしまっている
//2026年2月16日修正 修正内容(3→ (n / 2)) 修正理由 具体的数字3が入っていまっている
の修正によって今までと本質的に異なる一歩を進めることができます。
それは、8,12,16,・・・と6,10,14,・・・に一般化です。
つまり、課題は
n = 6 の 6 を10,14,18,・・・と変えるだけで・・・
n = 8 の 8 を12,16,20,・・・と変えるだけで・・・
ということです。
そうです。皆さんは革命前夜にいるのです。
これから革命を体験することになります。
第6章第10話へ 第6章第12話へ
本講義トップへ