マルチスレッド版数独自動生成ソフト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);

}








第8章第16話へ 第9章第18話へ

本講義トップへ