/*
 *  File:    SelfComplement.cpp
 *  Author:  S Harry White
 *  Created: 2011-08-02
 *  Updated: 2020-05-18
 *    Added howMany.
 *  Updated 2022-01-21
 *    Tidy code.
 */

/*
 *  Makes non-associative self-complementary even order magic squares.
 *  Double borders are repeatedly added to a center 4x4 or 6x6.
 */

#include "stdafx.h"
#include <assert.h>
#include <conio.h>
#include <direct.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <Windows.h>

const bool F=false, T=true; const int startSize=24;
int **xSquare=NULL, **bSquare=NULL, *tSideO=NULL, *tSideI=NULL,
    *bSideO=NULL, *bSideI=NULL, *rSideO=NULL, *rSideI=NULL, allocatedSize, biggestValue;
//================================================= store ==================================================

void freeSquare(int*** square, const int size) {
//   ----------
  if (*square!=NULL) { for (int i=0; i<size; i++) free((*square)[i]); free(*square);  *square=NULL; }
} // freeSquare

void freeSquares() {
//   -----------
  freeSquare(&xSquare, allocatedSize); freeSquare(&bSquare, allocatedSize);
  free(tSideO); free(tSideI); free(bSideO); free(bSideI);
  free(rSideO); free(rSideI); tSideO=NULL; tSideI=NULL;
  bSideO=NULL; bSideI=NULL; rSideO=NULL; rSideI=NULL; allocatedSize=0;
} // freeSquares

bool allocateSquare(int*** square, const int size) {
//   --------------
  bool ok; *square=(int**) malloc(size*sizeof(int*)); ok=(*square!=NULL);
  if (ok) {
    int numAllocated=size;
    for(int i=0; i<size; i++) {
      int *p=(int*) malloc(size*sizeof(int)); (*square)[i]=p; if (p==NULL) { numAllocated=i; ok=F; break; }
    }
    if (!ok) freeSquare(square, numAllocated);
  }
  return ok;
} // allocateSquare 

bool allocateSquares(int size) {
//   ---------------
  bool ok=T; if (size<startSize) size=startSize;
  if (size>allocatedSize) {
    freeSquares();
    if (ok=allocateSquare(&xSquare, size)) {
      if (ok=allocateSquare(&bSquare, size)) {
        allocatedSize=size;
        tSideO=(int*) malloc(size*sizeof(int)); tSideI=(int*) malloc(size*sizeof(int));
        bSideO=(int*) malloc(size*sizeof(int)); bSideI=(int*) malloc(size*sizeof(int));
        rSideO=(int*) malloc(size*sizeof(int)); rSideI=(int*) malloc(size*sizeof(int));
        ok=(tSideO!=NULL)&&(tSideI!=NULL)&&(bSideO!=NULL)&&(bSideI!=NULL)&&(rSideO!=NULL)&&(rSideI!=NULL);
        if (!ok) freeSquares();
      } else { freeSquare(&xSquare, size); allocatedSize=0; }
    }
  }
  return ok;
} //allocateSquares
//=================================================== input =======================================================

void clearLine(int c) { while (c!='\n') c=getchar(); }
//   ---------

bool getYorOrder(int *n) { // 'y' or 'n' or the order
//   -----------
  bool result=F; int c; *n=0; do { c=getchar(); } while ((c==' ')|(c=='\t')|(c=='\n') );
  if ( (c=='Y')|(c=='y') ) result=T;
  else if ( (c!='N')&(c!='n') )
    if ( ('1'<=c)&(c<='9') ) { int i=c-'0'; while ( ('0'<=(c=getchar()))&&(c<='9') ) i=i*10+c-'0'; *n=i; result=T; }  
  clearLine(c); return result;
} // getYorOrder

int getSize() { int n=0; scanf_s("%d", &n); clearLine(getchar()); return n; }
//  -------
//=================================================== output ========================================================

const int bufSize=1024;
bool openDir() {
//   -------
  int sub=0; char buf[bufSize], msg[bufSize]; const char *baseName="SelfComplementSquares";
  strcpy_s(buf, bufSize, baseName);
  do {
    if (_mkdir(buf)==0) break;
    if (errno!=EEXIST) {  sprintf_s(msg, bufSize, "Can't make folder %s", buf); perror(msg); return F; }
    sprintf_s(buf, bufSize, "%s_%d", baseName, ++sub);
  } while (T);
  if (_chdir(buf)!=0) { sprintf_s(msg, bufSize, "Can't open folder %s", buf); perror(msg); return F; }
  printf("Output files are in folder %s\n\n", buf); return T;
} // openDir

FILE *open_File(const int n) {
//    ---------
  FILE *wfp=NULL; char buf[bufSize]; sprintf_s(buf, bufSize, "Order%d.txt", n);
  if (fopen_s(&wfp, buf, "a")!=0) {
    char msg[bufSize]; sprintf_s(msg, bufSize, "\a\nCan't open for write %s", buf); perror(msg);
  }
  return wfp; 
} // open_File

int fieldWidth(const int n) { if (n==1) return 1; int i=n*n, width=1; while ((i=i/10)!=0) ++width; return width; }
//  ----------

typedef bool (*t_fprintFW)(FILE *fp, const int i);
bool fprintFW1(FILE *fp, const int i) { return fprintf(fp, "%1d",  i)>0; }
bool fprintFW2(FILE *fp, const int i) { return fprintf(fp, "%2d",  i)>0; }
bool fprintFW3(FILE *fp, const int i) { return fprintf(fp, "%3d",  i)>0; }
bool fprintFW4(FILE *fp, const int i) { return fprintf(fp, "%4d",  i)>0; }
bool fprintFW5(FILE *fp, const int i) { return fprintf(fp, "%5d",  i)>0; }
bool fprintFW6(FILE *fp, const int i) { return fprintf(fp, "%6d",  i)>0; }
bool fprintFW7(FILE *fp, const int i) { return fprintf(fp, "%7d",  i)>0; }
bool fprintFW8(FILE *fp, const int i) { return fprintf(fp, "%8d",  i)>0; }
bool fprintFW9(FILE *fp, const int i) { return fprintf(fp, "%9d",  i)>0; }
bool fprintFWa(FILE *fp, const int i) { return fprintf(fp, "%10d", i)>0; }

static t_fprintFW fprintFW[]={ NULL,
  fprintFW1, fprintFW2, fprintFW3, fprintFW4, fprintFW5,
  fprintFW6, fprintFW7, fprintFW8, fprintFW9, fprintFWa
};
const int maxFieldWidth=10;

bool printSquare(FILE *wfp, const int n) {
//   -----------
  const int fw0=fieldWidth(n), fw=fw0+1; if (fw>maxFieldWidth) return F;
  for (int i=0; i<n; i++) {
    if (!fprintFW[fw0](wfp, xSquare[i][0])) return F;
    for (int j=1; j<n; j++) if (!fprintFW[fw](wfp, xSquare[i][j])) return F;
    if (fputc('\n', wfp)==EOF) return F;
  }
  return fputc('\n', wfp)!=EOF;
} // printSquare
//============================================= check ================================================

bool isCorrect(int **x, const int n) {
//   ---------
  const int nn=n*n, nnp1=nn+1; if (biggestValue!=(nn/2)) return F;
  const int chkSum=(n&1) ? n*(nnp1/2) : n/2*nnp1; int sumX, sumY, sumXY=0, sumYX=0;
  for (int i=0; i<n; i++) {
    sumX=0; sumY=0; for (int j=0; j<n; j++) { sumX+=x[i][j]; sumY+=x[j][i]; }
    if ((sumX!=chkSum)|(sumY!=chkSum)) { return F; } sumXY+=x[i][n-i-1]; sumYX+=x[i][i];
  }
  return ((sumXY==chkSum)&(sumYX==chkSum));
} // isCorrect

bool isSelfComplement(int **x, const int n) {
//   ----------------
  const int m=n-1, mid=n/2, sum2=n*n+1;
  for (int r=0; r<n; ++r) for (int c=0; c<mid; ++c) if ((x[r][c]+x[r][m-c])!=sum2) return F;
  return T;
} // isSelfComplement
//============================================= make ================================================

void seed_rand() { srand((unsigned int)time(NULL)); }
//   ---------
int random(const int x) { return rand()%x; }
//  ------

typedef void (*t_Turn)(const int, const int, const int);
void no_Turn   (const int n, const int i, const int j) { xSquare[i][j]    =bSquare[i][j]; };
void rotate_180(const int n, const int i, const int j) { xSquare[n-i][n-j]=bSquare[i][j]; };
void rotate_Y  (const int n, const int i, const int j) { xSquare[i][n-j]  =bSquare[i][j]; };
void rotate_X  (const int n, const int i, const int j) { xSquare[n-i][j]  =bSquare[i][j]; };
static t_Turn turnCell[]={ no_Turn, rotate_180, rotate_Y, rotate_X };

void Turn(const int o, const int n) {
//   ----
  const int numRotations=4; int r, c; const int nmo=n-o, npo=n+o, k=random(numRotations);
  if (nmo<7) { // turn all 4, 5, 6, 7
    for (r=o; r<=n; r++) for (c=o; c<=n; c++) turnCell[k](npo, r, c);
  } else { // turn only 2 border rows and columns
    const int p=o+1, m=n-1;
    for (r=o; r<=n; r+=nmo) for (c=o; c<=n; ++c) turnCell[k](npo, r, c);
    for (c=o; c<=n; c+=nmo) for (r=p; r<n; ++r) turnCell[k](npo, r, c);
    for (r=p; r<=m; r+=(nmo-2)) for (c=p; c<=m; ++c) turnCell[k](npo, r, c);
    for (c=p; c<=m; c+=(nmo-2)) for (r=p; r<m; ++r) turnCell[k](npo, r, c);
  }
} // Turn

void makeActual(const int n) {
//   ----------
  const int pPlus=n*n/2, mPlus=pPlus+1;
  for (int i=0; i<n; i++) for (int j=0; j<n; j++) xSquare[i][j]+=xSquare[i][j]>0 ? pPlus : mPlus;
} // makeActual

const int num4x4ss=304;
int code4x4ss[]={
  0x01ebd2c9,0x01ecd2b9,0x02d9c3ea,0x02dbc3e8,0x02dec39a,0x02dec3b8,0x03c7d2eb,0x03c7e1db,
  0x03cbd2e7,0x03cbe1d7,0x03cde17b,0x03cde1b7,0x03ced27b,0x03ced2b7,0x04b9a5ec,0x04bda5e8,
  0x04bea59c,0x04bea5d8,0x05a6e1dc,0x05a7b4ed,0x05a7e1bd,0x05ab96cd,0x05abe17d,0x05abe1d7,
  0x05ac96bd,0x05adb4e7,0x05ade16c,0x05ade1b7,0x05aeb47d,0x05aeb4d7,0x0697b4de,0x0697d2be,
  0x069b87ec,0x069bd27e,0x069bd2e7,0x069d87ea,0x069db47e,0x069db4e7,0x069e87bc,0x069e87da,
  0x069eb4d7,0x069ed2b7,0xba5d1e63,0xb5ad3c61,0xb78d1e63,0x078dc36e,0xc5ab2d71,0xc69b1e72,
  0xa3cd4b71,0xa69d1e74,0x93ce4b72,0x95ae2d74,0x087de16c,0x096b78ed,0x096bc3e8,0x096be17d,
  0x096d78eb,0x096da5e8,0x096de17b,0x096e78bd,0x096e78db,0x096ea5d8,0x096ec3b8,0x72de5a93,
  0x74be3c95,0x0a5b78de,0x0a5bd27e,0x0a5bd2c9,0x0a5cd2b9,0x0a5d78be,0x0a5d78eb,0x0a5dc36e,
  0x0a5e78db,0x0a5ed27b,0x0b4d87ea,0x0b4e87da,0x0b4ec39a,0x75ac2db6,0x6a5d1eb8,0x596e2db8,
  0x569e3cb7,0x0c3d78be,0x0c3db47e,0x0c3e78bd,0x0c3eb47d,0x75ab2dc6,0x0d2e87bc,0x0d2ea59c,
  0x10fac3d8,0x10fdc3a8,0x12d6c3fa,0x12d6f0ca,0x12d7f0ab,0x12dac3f6,0x12daf07b,0x12daf0c6,
  0x12dcf06a,0x12dcf0a6,0x12dfc36a,0x12dfc3a6,0x14b6a5fc,0x14b6f0ac,0x14ba87dc,0x14baf06c,
  0x14baf0c6,0x14bca5f6,0x14bcf0a6,0x14bd87ac,0x14bfa56c,0x14bfa5c6,0x1697b4af,0x169ab47f,
  0xdb4a0f63,0xd4ba3c60,0xd78a0f63,0xbd2c0f65,0xb2dc5a60,0xb78c0f65,0x82df5a63,0x84bf3c65,
  0x178ac36f,0x178ac3f6,0x178ca56f,0x178ca5f6,0x178fa5c6,0x178fc3a6,0xc2da4b70,0xc69a0f74,
  0x187a69fc,0x187af06c,0x187c69fa,0x187cf06a,0x187f69ac,0x187f69ca,0x196af07b,0xd7860fa3,
  0xc6970fa4,0x7d2c0fa9,0x7b4c0fa9,0x60fd78a3,0x64bd3ca7,0x487f3ca9,0x1b4c69af,0x1b4c69fa,
  0x1b4dc3a8,0x1b4f69ca,0x1b4fc36a,0xb7860fc5,0x7b4a0fc9,0x1d2f69ac,0x1d2fa56c,0x64ba3cd7,
  0x21e5c3f9,0x21e5f0c9,0x21e9c3f5,0x21e9f0c5,0x21ecf059,0x21ecf095,0x21efc359,0x21efc395,
  0x23c5f0e7,0x23cef057,0x24b596fc,0x24b5f0e7,0x24b9f0c5,0x24bcf095,0x24bef057,0x24bf965c,
  0xbe1c0f56,0xb1ec6950,0xb78c0f56,0x9c3e0f58,0x9b4e0f58,0x81ef6953,0x84bf3c56,0x2789c3f5,
  0x278c965f,0x278fc395,0x28795afc,0x287cf059,0x287f5a9c,0x7e1c0f9a,0x7b4c0f9a,0x487f3c9a,
  0x2b4c5a9f,0x2b4e785f,0x2b4fc359,0x2c3e785f,0xb7850fc6,0x7b490fca,0x2e1f5a9c,0x2e1f965c,
  0x30f4d2e8,0x30f4e1d8,0x30f5b4e9,0x30f8d2e4,0x30f8e1d4,0x30fde148,0x30fde184,0x30feb459,
  0x30fed248,0x30fed284,0x31e4f0d7,0x31e6f0d5,0x31edf047,0x31edf065,0x32d4e1f6,0x32d596eb,
  0x32de965b,0x32dfe146,0x34b6f0d5,0x34bdf065,0xaf0d1e47,0xa1ed8740,0xae1d0f48,0xa0fd7841,
  0xa96d0f48,0xa69d1e47,0x9f0e2d47,0x90fe7842,0x95ae2d47,0x82df9641,0x8d2f1e49,0x8a5f1e49,
  0x35a8e1d4,0x35ade184,0x35ae874d,0x35afe146,0x80fe6954,0x82de4b56,0x3698d2e4,0x369d874e,
  0x369df047,0x369ed284,0x8e1d0f6a,0x8b4d0f6a,0x6f0d1e8b,0x6a5d1e8b,0x5f0e2d8b,0x596e2d8b,
  0x396d784f,0x396de148,0x396e4b8d,0x3a5d4b8e,0x3a5ed248,0x3a5f694e,0x3b4d5a6f,0x3d2eb459,
  0x3d2f694e,0xa9640fd8,0xa6941ed7,0x8b460fda,0x6a581edb,0x95a42de7,0x82d54be6,0x59682deb,
  0x41e2c3f8,0x41e3a5f9,0x41e9f0a3,0x41eaf093,0x41efa539,0x41efc328,0x42d396fa,0x42d9f0a3,
  0x42daf093,0x42df963a,0x9e1f3c27,0x91ef7823,0x95af3c27,0x81ef6935,0x82df5a36,0x45af872c,
  0x7e1a0f9c,0x7d2a0f9c,0x4a5fc328,0x7e190fac,0x7d290fac,0x4d2fa539,0x4e1f872c,0x4e1f963a,
  0x50f2b4e8,0x50f8e1b2,0x50fbe182,0x50feb428,0x51e6f0b3,0x51ebf063,0x52d6f0b3,0x52dbf063,
  0x9f0e4b27,0x90fe7824,0x93ce4b27,0x53c8e1b2,0x53cbe182,0x53ce872b,0x8e1b0f6c,0x8d2b0f6c,
  0x6f0b1e8d,0x6c3b1e8d,0x8e160fbc,0x8d260fbc,0x6f081ebd,0x6c381ebd,0x5c3eb428,0x93c24be7
};

typedef signed char Sbyte; const int num6x6a=50;
Sbyte code6x6a[][18]={
  {2,6,-3,-15,-8,-18,13,-5,9,-11,-4,10,12,-7,-14,-1,17,16},
  {10,1,2,-18,16,4,-7,9,-13,-8,-17,-5,11,6,-3,12,-14,15},
  {10,1,2,-18,16,-3,-7,9,-13,-8,-17,-5,11,6,4,12,-14,15},
  {3,2,-10,-15,-18,4,6,13,17,-14,7,1,9,-11,5,12,8,-16},
  {15,4,-7,-14,-1,11,-13,-8,12,-2,16,3,-5,6,-10,18,-17,-9},
  {15,4,-10,-14,-1,11,-13,-8,12,-2,16,3,-5,6,-9,18,-17,-7},
  {5,4,18,9,1,-3,6,-16,-17,7,15,-8,-12,10,-2,-14,-13,11},
  {-14,-4,17,-3,7,-5,1,-16,-2,18,10,-13,9,15,-6,-11,-12,8},
  {-7,-2,9,6,8,5,16,14,-18,1,-17,11,-3,-15,-10,-13,12,4},
  {-7,-2,5,6,8,4,16,14,-18,1,-17,11,-3,-15,9,-13,12,-10},
  {-2,-11,-4,1,9,17,10,-7,-3,13,5,18,-16,-8,-14,-6,12,-15},
  {-8,9,-15,17,1,-4,3,14,-5,-13,7,16,11,-18,2,-10,-12,6},
  {-8,9,-4,17,1,6,3,14,-5,-13,7,16,11,-18,2,-10,-12,-15},
  {-14,16,-3,17,2,-12,4,-7,-5,9,-13,-10,-1,8,18,-15,-6,11},
  {-14,16,18,17,2,11,4,-7,-5,9,-13,-10,-1,8,-12,-15,-6,-3},
  {-9,-11,7,-5,14,-16,8,18,3,-2,-1,12,-6,-17,-15,13,-4,10},
  {-12,17,-2,10,8,3,-14,-16,-6,9,-13,-4,18,5,15,-11,-1,-7},
  {-11,1,13,14,6,10,4,-9,-15,16,8,-17,-18,2,-3,-5,-7,12},
  {13,-17,-4,-15,1,-8,-10,-9,18,-3,7,11,-2,5,-6,16,14,-12},
  {-5,-17,-13,8,-12,-2,16,18,15,-14,3,10,6,-1,-4,-11,9,-7},
  {-7,-1,2,-15,14,-16,6,-3,-9,4,-10,-8,17,11,13,-5,-12,18},
  {5,-2,-7,-3,4,-18,-15,-8,11,9,-6,17,14,12,13,-10,-1,-16},
  {5,8,18,-4,-14,-13,15,-9,-1,-2,-11,-17,-12,10,7,-3,16,6},
  {3,18,-13,16,2,-1,-17,-14,8,-12,7,10,5,-4,11,6,-9,-15},
  {14,-16,8,-13,-2,18,-7,12,-15,-3,-6,-5,17,11,-10,-9,1,4},
  {-7,17,10,5,-6,-13,-4,15,11,16,-8,-3,-12,-1,-14,2,-18,9},
  {-7,17,9,5,-6,10,-4,15,11,16,-8,-3,-12,-1,-14,2,-18,-13},
  {-10,-15,16,-4,14,6,18,-13,2,1,12,5,3,9,-17,-8,-7,-11},
  {-1,-8,18,-6,5,-14,12,9,-13,-2,4,-17,-15,-3,10,11,-7,16},
  {-1,-8,-7,-6,5,9,12,16,-13,-2,4,-17,-15,-3,10,11,-14,18},
  {15,-17,-13,8,3,-2,11,-5,-14,-12,10,7,-18,1,16,-4,9,6},
  {1,8,5,-18,13,7,9,-10,-17,11,-2,-6,-16,-12,-4,14,3,15},
  {-11,-18,-15,16,1,-8,-4,12,9,-14,-2,-13,6,5,17,7,3,10},
  {-11,-4,17,16,1,14,8,-10,9,-18,3,-13,-2,5,-12,7,6,-15},
  {-11,-4,-12,16,1,17,8,-10,9,-18,3,-13,-2,5,14,7,6,-15},
  {12,-16,-5,-18,1,-4,-11,2,15,6,13,17,9,8,-10,3,-7,-14},
  {9,-12,6,-15,-16,14,18,13,5,2,11,1,-4,7,-8,-10,-3,-17},
  {4,-5,-10,-1,17,2,15,-9,6,-16,-8,-3,-13,18,12,11,-14,-7},
  {4,-5,-7,-1,17,2,15,-9,6,-16,-8,-3,-13,18,-10,11,-14,12},
  {15,-10,-11,3,4,8,17,-13,-9,-16,2,5,-18,6,14,-1,12,-7},
  {-18,2,9,3,-14,-1,7,11,5,17,-8,-10,4,-6,13,-12,15,-16},
  {-18,2,-1,3,-14,13,7,11,5,17,-8,-10,4,-6,9,-12,15,-16},
  {-18,2,-16,3,-14,13,7,11,5,17,-8,-10,4,-6,-1,-12,15,9},
  {11,8,-12,-18,-5,-16,-1,-17,14,4,10,6,3,13,-7,2,-9,15},
  {-5,3,13,15,-2,-18,11,-9,7,-17,14,16,-1,-12,-8,-4,6,-10},
  {7,5,-16,-15,-18,6,2,-10,17,-3,-4,-8,9,13,12,1,14,-11},
  {-3,-11,-8,-4,6,16,-12,17,-7,-9,-1,-15,14,-2,-5,13,-10,18},
  {-3,-11,-5,-4,6,16,-12,17,-7,-9,-1,-15,14,-2,18,13,-10,-8},
  {-2,18,-16,17,-12,13,-10,-9,15,-7,-14,-8,-3,6,1,4,11,-5},
  {-2,18,13,17,-12,-5,-10,-9,15,-7,-14,-8,-3,6,-16,4,11,1}
};

void putCenter4x4(int **x, int **b, const int o, const int n) {
//   ------------
  int code=code4x4ss[random(num4x4ss)]; const int Msum=34; // 4*(4*4+1)/2;
  x[2][2]=(code&0xf)+1; code>>=4; x[2][0]=(code&0xf)+1; code>>=4;
  x[1][2]=(code&0xf)+1; code>>=4; x[1][1]=(code&0xf)+1; code>>=4;
  x[1][0]=(code&0xf)+1; code>>=4; x[0][2]=(code&0xf)+1; code>>=4;
  x[0][1]=(code&0xf)+1; code>>=4; x[0][0]=(code&0xf)+1;
  x[0][3]=Msum-x[0][0]-x[0][1]-x[0][2]; x[1][3]=Msum-x[1][0]-x[1][1]-x[1][2];
  x[3][0]=Msum-x[0][0]-x[1][0]-x[2][0]; x[3][2]=Msum-x[0][2]-x[1][2]-x[2][2];
  x[3][3]=Msum-x[0][0]-x[1][1]-x[2][2]; x[3][1]=Msum-x[3][0]-x[3][2]-x[3][3];
  x[2][1]=Msum-x[0][1]-x[1][1]-x[3][1]; x[2][3]=Msum-x[2][0]-x[2][1]-x[2][2];
  for (int i=0; i<4; i++) for (int j=0; j<4; j++) b[i+o][j+o]=x[i][j]-(x[i][j]>8 ? 8 : 9); // (4*4+1)/2) (8.5)
  Turn(o, n);
} // putCenter4x4

void putCenter6x6(int **b, const int o, const int n) {
//   ------------
  const Sbyte *code=code6x6a[random(num6x6a)]; int i=0; const int upb=o+n, mid=upb/2;
  for (int r=o; r<=n; ++r) for (int c=o; c<=mid; ++c) { const int v=code[i++]; b[r][c]=v; b[r][upb-c]=-v; }
  Turn(o, n);
} // putCenter6x6

void putBorder(int **b, const int o, const int n) {
//   ---------
  const int m=n-1, p=o+1, upb=o+n, mid=upb/2; int i=0, v,
            length=(n-o-1)/2; // remaining choices in tSideO, etc.
  while (T) {
    i=random(length);
    if (tSideO[i]<0) {
       v=tSideO[i]; tSideO[i]=tSideO[0]; b[o][p]=v; b[o][m]=-v;
       v=bSideO[i]; bSideO[i]=bSideO[0]; b[n][p]=v; b[n][m]=-v; break;
    }
  }
  for (int j=0; j<length; ++j) { tSideO[j]=tSideO[j+1]; bSideO[j]=bSideO[j+1]; } --length;
  for (int c=p+1; c<=mid; ++c) {
    i=random(length);
    v=tSideO[i]; b[o][c]=v; b[o][upb-c]=-v; v=bSideO[i]; b[n][c]=v; b[n][upb-c]=-v;
    v=tSideI[i]; b[p][c]=v; b[p][upb-c]=-v; v=bSideI[i]; b[m][c]=v; b[m][upb-c]=-v;
    for (int j=i; j<length; ++j) {
      tSideO[j]=tSideO[j+1]; bSideO[j]=bSideO[j+1]; tSideI[j]=tSideI[j+1]; bSideI[j]=bSideI[j+1];
    } --length;
  }
  length=n-o-1; // remaining choices in rSideO
  for (int r=p; r<n; ++r) {
    i=random(length); v=rSideO[i]; b[r][o]=v; b[r][n]=-v;
    for (int j=i; j<length; ++j) { rSideO[j]=rSideO[j+1]; } --length;
  }
  length=n-o-3; // remaining choices in rSideI
  for (int r=p+1; r<m; ++r) {
    i=random(length); v=rSideI[i]; b[r][p]=v; b[r][m]=-v;
    for (int j=i; j<length; ++j) { rSideI[j]=rSideI[j+1]; } --length;
  }
  Turn(o, n);
} // putBorder

void makeEven4(int **x, int **b, const int size, FILE *wfp) {
//   ---------
  int v=9, /* 8.5 (4*4+1)/2 */ o=(size-4)/2, n=o+3; putCenter4x4(x, b, o, n); 
  for (int i=8; i<=size; i+=4) {
    int ct=0, cb=0, rr=0; o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1; const int k=(i-8)/4;
    int *tO=tSideO, *bO=bSideO, *rO=rSideO, *tI=tSideI, *bI=bSideI, *rI=rSideI;
    tO[ct++]=-v++; bO[cb++]=v++; rO[rr++]=v++; rO[rr++]=-v++;
    tO[ct++]=v++; bO[cb++]=-v++; rO[rr++]=v++; rO[rr++]=-v++; tO[ct++]=-v++; bO[cb++]=v++;
    b[o][o]=-v; b[o][n]=v++; /* NW, NE out */ b[m][p]=-v; b[m][m]=v++; // SW, SE in
    b[p][p]=v; b[p][m]=-v++; /* NW, NE in */ b[n][o]=v; b[n][n]=-v++;  // SW, SE out
    rO[rr++]=v++; rO[rr++]=-v++;
    int j=k; while (j--) {
      tO[ct++]=-v++; bO[cb++]=v++; rO[rr++]=v++; rO[rr++]=-v++;
      tO[ct++]=v++; bO[cb++]=-v++; rO[rr++]=-v++; rO[rr++]=v++;
    }
    ct=0, cb=0, rr=0; tI[ct++]=-v++; bI[cb++]=v++; rI[rr++]=v++; rI[rr++]=-v++;
    tI[ct++]=v++; bI[cb++]=-v++; rI[rr++]=v++; rI[rr++]=-v++; j=k;
    while (j--) {
      tI[ct++]=v++; bI[cb++]=-v++; rI[rr++]=-v++; rI[rr++]=v++;
      tI[ct++]=-v++; bI[cb++]=v++; rI[rr++]=v++; rI[rr++]=-v++;
    }
    putBorder(b, o, n);
  } // for (i=8; ...
  biggestValue=v-1;
}  // makeEven4

void makeEven6(int **b, const int size, FILE *wfp) {
//   ---------
  int v=19, /* 18.5 (6*6+1)/2 */ o=(size-6)/2, n=o+5; putCenter6x6(b, o, n); 
  for (int i=10; i<=size; i+=4) {
    int ct=0, cb=0, rr=0; o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1; const int k=(i-10)/4;    
    int *tO=tSideO, *bO=bSideO, *rO=rSideO, *tI=tSideI, *bI=bSideI, *rI=rSideI;
    tO[ct++]=-v++; bO[cb++]=v++; rO[rr++]=v++; rO[rr++]=-v++;
    tO[ct++]=v++; bO[cb++]=-v++; rO[rr++]=-v++; rO[rr++]=v++;
    tO[ct++]=-v++; bO[cb++]=v++; rO[rr++]=v++; rO[rr++]=-v++; tO[ct++]=v++; bO[cb++]=-v++;
    b[o][o]=-v; b[o][n]=v++;  /* NW, NE out */ b[p][p]=v; b[p][m]=-v++;  // NW, NE in
    rO[rr++]=v++; b[m][p]=-v; b[m][m]=v++;  /* SW, SE in */ b[n][o]=v; b[n][n]=-v++;  // SW, SE out
    rO[rr++]=-v++;
    int j=k; while (j--) {
      tO[ct++]=-v++; bO[cb++]=v++; rO[rr++]=v++; rO[rr++]=-v++;
      tO[ct++]=v++; bO[cb++]=-v++; rO[rr++]=-v++; rO[rr++]=v++;
    }
    ct=0, cb=0, rr=0; tI[ct++]=-v++; bI[cb++]=v++; rI[rr++]=v++; rI[rr++]=-v++;
    tI[ct++]=v++; bI[cb++]=-v++; rI[rr++]=-v++; rI[rr++]=v++;
    tI[ct++]=-v++; bI[cb++]=v++; rI[rr++]=-v++; rI[rr++]=v++; j=k;
    while (j--) {
      tI[ct++]=v++; bI[cb++]=-v++; rI[rr++]=-v++; rI[rr++]=v++;
      tI[ct++]=-v++; bI[cb++]=v++; rI[rr++]=v++; rI[rr++]=-v++;
    }
    putBorder(b, o, n);
  } // for (i=10; ...
  biggestValue=v-1;
}  // makeEven6

const char *notMagic="\a\nERROR: Square is NOT magic! Please report by email\n";
const char *notSelfComplement="\a\nERROR: Square is NOT self-complementary! Please report by email\n";

bool makeEven(const int n, FILE *wfp) {
//   --------
  if (n%4==0) makeEven4(xSquare, bSquare, n, wfp); else makeEven6(bSquare, n, wfp); makeActual(n);
  if (isCorrect(xSquare, n)) { if (!isSelfComplement(xSquare, n)) printf(notSelfComplement); }
  else printf(notMagic); return !printSquare(wfp, n);
} // makeEven
//=================================================== main ================================================

bool validOrder(const int n) {
//   ----------
  if (n<=0) { printf("\aERROR: N must be a positive integer.\n"); return F; }
  else if (n%2) {
    printf("\aERROR: There are no non-associative self-complementary "
           "magic squares of odd order.\n"); return F;
  } else if (n==2) { printf("\aERROR: There is no magic square of order 2.\n"); return F; } else return T;
}// validOrder

int main() {
//  ----
  bool ok=F;
  if (openDir()) {
    int n=0; bool another=T, inputSize=T, writeError=F; seed_rand();
    do {     
      if (inputSize) { printf("\nInput the order of the square: "); n=getSize(); }
      if (validOrder(n)) {
	      if (allocateSquares(n)) {
	        FILE *wfp=NULL;
          if ( (wfp=open_File(n))!=NULL) {
            printf("\nHow many? "); int howMany=getSize();
            while (howMany--) { writeError=makeEven(n, wfp); if (writeError) break; } fclose(wfp);
	        }
	      } else printf("\a\nERROR: Storage allocation failed.\n");
      } // if (validOrder
      if (writeError) { perror("\a\nError writing file"); another=F; }
      else { ok=T;
        printf("\nMake another square? input y (yes) or n (no) or the order of the square: ");
        if (getYorOrder(&n)) inputSize=(n==0); else another=F;
      }
    } while (another);
    freeSquares();
  }
  printf("\nPress a key to close the console.");
  while (!_kbhit()) Sleep(250); return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} // main