マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第8章 ポインタの学習
第9話 8行分のポインタ配列を送って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 = 8;//具体的な数字を使うのではなく、 n を使うと汎用性のあるプログラムになる!
//部長の任務は社長の仕事の一部を引き受け、
//社員(部の社員)に仕事を命令することです。
void 部長(int(*a)[n]);
void 課長1(int(*a)[n]);//自然配列担当社員と表示担当社員の統率を担当
void 課長2(int(*a)[n]);//対角線部分交換社員fと表示担当職員の統率を担当
void 課長3(int(*a)[n]);//緑部分交換社員gと表示担当職員の統率を担当
void 課長4(int(*a)[n]);//明るい紫部分交換社員fと表示担当職員の統率を担当
void 自然配列担当社員(int(*a)[n]);
void 表示担当社員(int(*a)[n]);
void 交換係社員(int* x, int* y);
//fの任務は各対角線部分を点対称移動させることである
void f(int(*a)[n]);
//gの任務は緑の部分を上下線対称移動させることである
void g(int(*a)[n]);
//hの任務は明るい紫部分を左右線対称移動させることである
void h(int(*a)[n]);
int main() {//私は社長だ。
int a[n][n]; //8行分のポインタ配列を定義
部長(a);//部長に統率を依頼
while (!_kbhit());//待機させるための命令
return 0;//int main() を終わるためのお呪い
}
void 部長(int(*a)[n]) {
課長1(a);//自然配列担当社員と表示担当社員の統率を担当
課長2(a);//対角線部分交換社員fと表示担当職員の統率を担当
課長3(a);//緑部分交換社員gと表示担当職員の統率を担当
課長4(a);//明るい紫部分交換社員fと表示担当職員の統率を担当
}
void 課長1(int(*a)[n]) {
自然配列担当社員(a);
表示担当社員(a);
}
void 課長2(int(*a)[n]) {
f(a);//対角線部分交換
cout << endl;
表示担当社員(a);
}
void 課長3(int(*a)[n]) {
g(a);//緑部分交換
cout << endl;
表示担当社員(a);
}
void 課長4(int(*a)[n]) {
h(a);//明るい紫部分交換
cout << endl;
表示担当社員(a);
}
void 自然配列担当社員(int(*a)[n]) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
a[i][j] = n * i + j + 1;//自然配列を2次元配列に収納
}
}
}
void 表示担当社員(int(*a)[n]) {
//自然配列を体裁を整えてコンソール画面に表示する
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;
}
}
void 交換係社員(int* x, int* y) {
int u;//交換のための受け皿
u = *x;//xから間接参照されるデータがyから間接参照されるデータに上書きされる前にuにxの間接参照されるデータを保存
*x = *y;//yから間接参照されるデータでxから間接参照されるデータを上書きする
*y = u;//xから間接参照される元データでyから間接参照されるデータを上書き
}
//fの任務は対角線部分を点対称移動させることである
void f(int(*a)[n]) {
//対角線点対称移動
for (int i = 0; i < n / 2; i++) {
int x = a[i][i];
int y = a[n - 1 - i][n - 1 - i];
交換係社員(&x, &y);
a[i][i] = x;
a[n - 1 - i][n - 1 - i] = y;
}
//対角線点対称移動終了
//逆対角線点対称移動
for (int i = 0; i < n / 2; i++) {
int x = a[i][n - 1 - i];
int y = a[n - 1 - i][i];
交換係社員(&x, &y);
a[i][n - 1 - i] = x;
a[n - 1 - i][i] = y;
}
//逆対角線点対称移動終了
}
void g(int(*a)[n]) {
//緑の部分の第1列から第4列までの上下交換開始
for (int i = 0; i < n / 2; i++) {
int x = a[i][(2 + i) % (n / 2)];
int y = a[n - 1 - i][(2 + i) % (n / 2)];
交換係社員(&x, &y);
a[i][(2 + i) % (n / 2)] = x;
a[n - 1 - i][(2 + i) % (n / 2)] = y;
}
//緑の部分の第1列から第4列までの上下交換
//緑の部分の第5列から第8列までの上下交換開始
for (int i = 0; i < n / 2; i++) {
int x = a[i][n - 1 - (2 + i) % (n / 2)];
int y = a[n - 1 - i][n - 1 - (2 + i) % (n / 2)];
交換係社員(&x, &y);
a[i][n - 1 - (2 + i) % (n / 2)] = x;
a[n - 1 - i][n - 1 - (2 + i) % (n / 2)] = y;
}
//緑の部分の第5列から第8列までの上下交換
}
//hの任務は明るい紫部分を線対称移動させることである
void h(int(*a)[n]) {
//明るい紫の部分の第1行から第4行までの左右交換開始
for (int i = 0; i < n / 2; i++) {
int x = a[i][(3 + i) % (n / 2)];
int y = a[i][n - 1 - ((3 + i) % (n / 2))];
交換係社員(&x, &y);
a[i][(3 + i) % (n / 2)] = x;
a[i][n - 1 - ((3 + i) % (n / 2))] = y;
}
//明るい紫の部分の第1行から第4行までの左右交換終了
//明るい紫の部分の第5行から第8行までの交換開始
for (int i = 0; i < n / 2; i++) {
int x = a[n - 1 - i][(3 + i) % (n / 2)];
int y = a[n - 1 - i][n - 1 - ((3 + i) % (n / 2))];
交換係社員(&x, &y);
a[n - 1 - i][(3 + i) % (n / 2)] = x;
a[n - 1 - i][n - 1 - ((3 + i) % (n / 2))] = y;
}
//明るい紫の部分の第5行から第8行までの交換終了
}
実行結果

(
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 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
64 2 3 4 5 6 7 57
9 55 11 12 13 14 50 16
17 18 46 20 21 43 23 24
25 26 27 37 36 30 31 32
33 34 35 29 28 38 39 40
41 42 22 44 45 19 47 48
49 15 51 52 53 54 10 56
8 58 59 60 61 62 63 1
64 2 59 4 5 62 7 57
9 55 11 52 53 14 50 16
41 18 46 20 21 43 23 48
25 34 27 37 36 30 39 32
33 26 35 29 28 38 31 40
17 42 22 44 45 19 47 24
49 15 51 12 13 54 10 56
8 58 3 60 61 6 63 1
64 2 59 5 4 62 7 57
16 55 11 52 53 14 50 9
41 23 46 20 21 43 18 48
25 34 30 37 36 27 39 32
33 26 38 29 28 35 31 40
17 47 22 44 45 19 42 24
56 15 51 12 13 54 10 49
8 58 3 61 60 6 63 1
)
皆さんどうでしたか。難しかったでしょう。
ですから、つい答を見てしまった人は悲観することはありません。
おそらく、あなただけでなく4/5ぐらいの人は第9話を見てしまっていると思います。
さて、第8章の課題です。12次魔方陣に挑戦しましょう。
(エクセルには明るい紫はないので、紫で代替)
(エクセルには明るい紫はないので、紫で代替)
黄色は中心の点に対して点対称移動
緑は中央の直線に対して上下線対称移動
紫は中央の直線に対して左右線対称移動
今回もヒントとして

1/4を載せておきます。緑も紫も2系列があります。
まず、緑の動きを追うと
系列1 a[0][2] → a[1][3] → a[2][4] → a[3][5] → a[4][0] → a[5][1] 一般化すると a[i][w]
系列2 a[0][4] → a[1][5] → a[2][0] → a[3][1] → a[4][2] → a[5][3] 一般化すると a[i][x]
次に、紫の動きを追うと
系列1 a[0][3] → a[1][4] → a[2][5] → a[3][0] → a[4][1] → a[5][2] 一般化すると a[i][y]
系列2 a[0][5] → a[1][0] → a[2][1] → a[3][2] → a[4][3] → a[5][4] 一般化すると a[i][z]
共通点は右下がりになっている点です。
w,x,y.z を i で表せば問題解決です。