マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第8章 ポインタの学習
第11話 普遍化版の完成
(エクセルには明るい紫はないので、紫で代替)
(エクセルには明るい紫はないので、紫で代替)
を実現するコード例
#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 = 12;//具体的な数字を使うのではなく、 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]; // n 行分のポインタ配列を定義
部長(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 (n > 28) {
if (a[i][j] < 1000)cout << " ";
}
if (a[i][j] < 100)cout << " ";
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 = 1; i < n / 4; i++) {
for (int j = 0; j < n / 2; j++) {
int x = a[j][(2 * i + j) % (n / 2)];
int y = a[n - 1 - j][(2 * i + j) % (n / 2)];
交換係社員(&x, &y);
a[j][(2 * i + j) % (n / 2)] = x;
a[n - 1 - j][(2 * i + j) % (n / 2)] = y;
}
}
//緑の部分の第1列から第4列までの上下交換
//緑の部分の第5列から第8列までの上下交換開始
for (int i = 1; i < n / 4; i++) {
for (int j = 0; j < n / 2; j++) {
int x = a[j][n - 1 - (2 * i + j) % (n / 2)];
int y = a[n - 1 - j][n - 1 - (2 * i + j) % (n / 2)];
交換係社員(&x, &y);
a[j][n - 1 - (2 * i + j) % (n / 2)] = x;
a[n - 1 - j][n - 1 - (2 * i + j) % (n / 2)] = y;
}
}
//緑の部分の第5列から第8列までの上下交換
}
//hの任務は明るい紫部分を線対称移動させることである
void h(int(*a)[n]) {
//明るい紫の部分の第1行から第4行までの左右交換開始
for (int i = 1; i < n / 4; i++) {
for (int j = 0; j < n / 2; j++) {
int x = a[j][(2 * i + 1 + j) % (n / 2)];
int y = a[j][n - 1 - ((2 * i + 1 + j) % (n / 2))];
交換係社員(&x, &y);
a[j][(2 * i + 1 + j) % (n / 2)] = x;
a[j][n - 1 - ((2 * i + 1 + j) % (n / 2))] = y;
}
}
//明るい紫の部分の第1行から第4行までの左右交換終了
//明るい紫の部分の第5行から第8行までの交換開始
for (int i = 1; i < n / 4; i++) {
for (int j = 0; j < n / 2; j++) {
int x = a[n - 1 - j][(2 * i + 1 + j) % (n / 2)];
int y = a[n - 1 - j][n - 1 - ((2 * i + 1 + j) % (n / 2))];
交換係社員(&x, &y);
a[n - 1 - j][(2 * i + 1 + j) % (n / 2)] = x;
a[n - 1 - j][n - 1 - ((2 * i + 1 + j) % (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 65 66 67 68 69 70 71 72
73 74 75 76 77 78 79 80 81 82 83 84
85 86 87 88 89 90 91 92 93 94 95 96
97 98 99 100 101 102 103 104 105 106 107 108
109 110 111 112 113 114 115 116 117 118 119 120
121 122 123 124 125 126 127 128 129 130 131 132
133 134 135 136 137 138 139 140 141 142 143 144
144 2 3 4 5 6 7 8 9 10 11 133
13 131 15 16 17 18 19 20 21 22 122 24
25 26 118 28 29 30 31 32 33 111 35 36
37 38 39 105 41 42 43 44 100 46 47 48
49 50 51 52 92 54 55 89 57 58 59 60
61 62 63 64 65 79 78 68 69 70 71 72
73 74 75 76 77 67 66 80 81 82 83 84
85 86 87 88 56 90 91 53 93 94 95 96
97 98 99 45 101 102 103 104 40 106 107 108
109 110 34 112 113 114 115 116 117 27 119 120
121 23 123 124 125 126 127 128 129 130 14 132
12 134 135 136 137 138 139 140 141 142 143 1
144 2 135 4 137 6 7 140 9 142 11 133
13 131 15 124 17 126 127 20 129 22 122 24
109 26 118 28 113 30 31 116 33 111 35 120
37 98 39 105 41 102 103 44 100 46 107 48
85 50 87 52 92 54 55 89 57 94 59 96
61 74 63 76 65 79 78 68 81 70 83 72
73 62 75 64 77 67 66 80 69 82 71 84
49 86 51 88 56 90 91 53 93 58 95 60
97 38 99 45 101 42 43 104 40 106 47 108
25 110 34 112 29 114 115 32 117 27 119 36
121 23 123 16 125 18 19 128 21 130 14 132
12 134 3 136 5 138 139 8 141 10 143 1
144 2 135 9 137 7 6 140 4 142 11 133
24 131 15 124 20 126 127 17 129 22 122 13
109 35 118 28 113 31 30 116 33 111 26 120
48 98 46 105 41 102 103 44 100 39 107 37
85 59 87 57 92 54 55 89 52 94 50 96
61 74 70 76 68 79 78 65 81 63 83 72
73 62 82 64 80 67 66 77 69 75 71 84
49 95 51 93 56 90 91 53 88 58 86 60
108 38 106 45 101 42 43 104 40 99 47 97
25 119 34 112 29 115 114 32 117 27 110 36
132 23 123 16 128 18 19 125 21 130 14 121
12 134 3 141 5 139 138 8 136 10 143 1
)
結果が正しいか

と毎回突き合わせていたのでは大変です。
そこで、12話への課題はすべての行合計・すべての列合計・2本の対角線合計がすべて同じなっていること、
1から n * n までの数字が漏れなく重複なしに揃っていることを確認する作業を加えます。
数字が漏れなく重複なしに揃っていることを確認するには1次元配列を用意して、
int 配列[n * n];//1次元配列
を定義してすべて 0 に初期化しておきます。
n * n この数字について順にみていき
配列[数字 - 1]++;
をやっていてもし配列[数字 - 1] > 1 となれば、
重複ありでこのときは検査を中止して
重複がありと結果を打ち出します。
最後まで重複がなければ1:1対応の原理から漏れもないことも判明します。

