マルチスレッド版数独自動生成ソフトC++コードを題材とする超初心者のためのVisual Studio C++講義
第8章 ポインタの学習
第17話 4 * n + 2 タイプを普遍版


を実現するコード例
#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 = 14;//具体的な数字を使うのではなく、 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 検査(int(*a)[n]);//各合計が一致していなかったり数字の重複があるときに 0 を返す関数
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と表示担当職員の統率を担当
int k = 検査(a);
if (k == 0) {
cout << "異常あり" << endl;
}
else {
cout << "すべて正常" << endl;
}
}
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列から第n / 2列までの上下交換開始
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n / 4; j++) {
int x = a[i][(i + j + 1) % (n / 2)];
int y = a[n - 1 - i][(i + j + 1) % (n / 2)];
交換係社員(&x, &y);
a[i][(i + j + 1) % (n / 2)] = x;
a[n - 1 - i][(i + j + 1) % (n / 2)] = y;
}
}
//緑の部分の第1列から第4列までの上下交換
//緑の部分の第5列から第8列までの上下交換開始
for (int i = 0; i < n / 2; i++) {
for (int j = 1; j < n / 4; j++) {
int x = a[i][n - 1 - (i + j + 1) % (n / 2)];
int y = a[n - 1 - i][n - 1 - (i + j + 1) % (n / 2)];
交換係社員(&x, &y);
a[i][n - 1 - (i + j + 1) % (n / 2)] = x;
a[n - 1 - i][n - 1 - (i + j + 1) % (n / 2)] = y;
}
}
//緑の部分の第5列から第8列までの上下交換
}
//hの任務は明るい紫部分を線対称移動させることである
void h(int(*a)[n]) {
//明るい紫の部分の第1行から第4行までの左右交換開始
for (int i = 0; i < n / 2; i++) {
for (int j = 0; j < n / 4; j++) {
int x = a[i][((i + j + 1) + (n / 4)) % (n / 2)];
int y = a[i][n - 1 - ((i + j + 1) + (n / 4)) % (n / 2)];
交換係社員(&x, &y);
a[i][((i + j + 1) + (n / 4)) % (n / 2)] = x;
a[i][n - 1 - ((i + j + 1) + (n / 4)) % (n / 2)] = y;
}
}
//明るい紫の部分の第1行から第4行までの左右交換終了
//明るい紫の部分の第5行から第8行までの交換開始
for (int i = 0; i < n / 2; i++) {
for (int j = 1; j < n / 4; j++) {
int x = a[n - 1 - i][((i + j + 1) + (n / 4)) % (n / 2)];
int y = a[n - 1 - i][n - 1 - ((i + j + 1) + (n / 4)) % (n / 2)];
交換係社員(&x, &y);
a[n - 1 - i][((i + j + 1) + (n / 4)) % (n / 2)] = x;
a[n - 1 - i][n - 1 - ((i + j + 1) + (n / 4)) % (n / 2)] = y;
}
}
//明るい紫の部分の第5行から第8行までの交換終了
}
int 検査(int(*a)[n]) {
int 合計;
int gk = 0;
cout << endl;
for (int i = 0; i < n; i++) {//1 + 2 + ・・・ + n * n を計算する
for (int j = 0; j < n; j++) {
gk = gk + n * i + j + 1;
}
}
gk = gk / n;//nで割って魔方陣の行などの合計を計算
for (int i = 0; i < n; i++) {//行合計を計算
合計 = 0;// 0 に初期化
for (int j = 0; j < n; j++) {
合計 = 合計 + a[i][j];
}
cout << 合計 << " ";
if (合計 != gk)return(0);
}
cout << endl;
cout << endl;
for (int i = 0; i < n; i++) {//列合計を計算
合計 = 0;// 0 に初期化
for (int j = 0; j < n; j++) {
合計 = 合計 + a[j][i];
}
cout << 合計 << " ";
if (合計 != gk)return(0);
}
cout << endl;
cout << endl;
合計 = 0;// 0 に初期化
for (int j = 0; j < n; j++) {//対角線合計
合計 = 合計 + a[j][j];
}
cout << 合計 << " ";
if (合計 != gk)return(0);
合計 = 0;// 0 に初期化
for (int j = 0; j < n; j++) {
合計 = 合計 + a[j][n - 1 - j];
}
if (合計 != gk)return(0);
cout << 合計 << " ";
int 配列[n * n];
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
配列[n * i + j] = 0;//すべて0に初期化
}
}
cout << endl;
cout << endl;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
配列[a[i][j] - 1]++;//すべて0に初期化
if (配列[a[i][j] - 1] > 1)return(0);
}
}
return(1);
}