/*
 * File:    AdjacentSide.cpp
 * Author:  S Harry White
 * Created: 2011-04-24
 * Updated: 2020-04-29
 *   Add howMany.
 * Updated: 2020-06-29
 *   Sort output in Frénicle standard form removing duplicates.
 * Updated: 2021-12-05
 *   Tidy code.
 *  Updated: 2021-12-29
 *    Replace & with && in one piece of code.
 */

/*
 * Makes adjacent side paired magic squares of order n>=4.
 * Double borders are repeatedly added to a center 4x4, 5x5, 6x6, or 7x7.
 */

#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>

typedef signed char Sbyte;
int **xSquare=NULL, **bSquare=NULL, **Squares=NULL, *square=NULL, 
    *tSide=NULL, *bSide=NULL, *lSide=NULL, *rSide=NULL;
const bool F=false, T=true;
const int startSize=12, startSquaresSize=1024;
int allocatedSize, allocatedSquaresSize, biggestValue, Sindex, sLen;
//================================ allocate store ==================================

char *storeAllocFail="Storage allocation failed"; bool bell=T;
bool reportError(char *msg) {
//   -----------
  printf("%sError: %s.\n", bell ? "\a\n" : "",  msg);
  if (bell) bell=F; return F;
} // reportError

void freeInts(int **line) { if (*line!=NULL) { free(*line); *line=NULL; }}
//   --------

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 freeStore() {
//   ---------
  freeSquare(&xSquare, allocatedSize); freeSquare(&bSquare, allocatedSize);
  freeSquare(&Squares, allocatedSquaresSize); freeInts(&square); 
  freeInts(&tSide); freeInts(&bSide); freeInts(&lSide); freeInts(&rSide);
  allocatedSize=0;
} // freeStore

bool allocateInts(int **line, const int size) {
//   ------------
  *line=(int*)malloc(size*sizeof(int)); return *line!=NULL;
} // allocateInts

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(const int size) {
//   ---------------
  bool ok; int length=size*size;

  Squares=(int**) malloc(startSquaresSize*sizeof(int*));
  ok=(Squares!=NULL);
  if (ok) {
    int numAllocated=startSquaresSize;
    for(int i=0; i<startSquaresSize; i++) {
      int *p=(int*) malloc(length*sizeof(int)); (Squares)[i]=p;
      if (p==NULL) { numAllocated=i; ok=F; break; }
    }
    if (!ok) freeSquare(&Squares, numAllocated);
  }
  return ok;
} // allocateSquares

bool increaseSquares() {
//   ---------------
  bool ok;
  int length=allocatedSize*allocatedSize,  // of square
      size=allocatedSquaresSize+allocatedSquaresSize,
      **t=(int**) malloc(size*sizeof(int*));
  if (ok=(t!=NULL)) {
    for (int i=0; i<allocatedSquaresSize; i++) t[i]=Squares[i];
    free(Squares); Squares=t; int numAllocated=size;
    for(int i=allocatedSquaresSize; i<size; i++) {
      int *p=(int*) malloc(length*sizeof(int)); (Squares)[i]=p;
      if (p==NULL) { numAllocated=i; ok=F; break; }
    }
    if (!ok) freeSquare(&Squares, numAllocated);
  }
  if (ok) allocatedSquaresSize=size; else reportError(storeAllocFail);
  return ok;
} // increaseSquares

bool allocateStore(int size) {
//   -------------
  bool ok=T;

  if (size<startSize) size=startSize;
  if (size>allocatedSize) {
    freeStore();
    if (ok=allocateSquare(&xSquare, size))
      if (ok=allocateSquare(&bSquare, size))
        if (ok=allocateSquares(size)) {
          allocatedSize=size; allocatedSquaresSize=startSquaresSize;
          if (ok=allocateInts(&square, size*size))
            if (ok=allocateInts(&tSide, size))
              if (ok=allocateInts(&bSide, size))
                if (ok=allocateInts(&lSide, size))
                  ok=allocateInts(&rSide, size); 
    }
    if (!ok) freeStore();
  }
  return ok;
} //allocateStore
//========================================= check squares =======================================

bool isCorrect(int **x, const int n) {
//   ---------
  const int nn=n*n, nnp1=nn+1, big=n%2==0 ? nn/2 : (nn-1)/2;
  if (biggestValue!=big) return F;
  const int chkSum=n%2==0 ? n/2*nnp1 : n*(nnp1/2);
  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 isAdjacentEven(int **x, const int n) {
//   --------------
  const int m=n-1, l=n-2, S2=n*n+1; int v;

  // corners
  v=x[0][0]; if ((v+x[0][1]!=S2)&&(v+x[1][0]!=S2)) return F;
  v=x[0][m]; if ((v+x[0][l]!=S2)&&(v+x[1][m]!=S2)) return F;
  v=x[m][0]; if ((v+x[m][1]!=S2)&&(v+x[l][0]!=S2)) return F;
  v=x[m][m]; if ((v+x[m][l]!=S2)&&(v+x[l][m]!=S2)) return F;

  for (int i=1; i<m; ++i) { // rest of top, bottom, left, right
    v=x[0][i]; if ((v+x[0][i-1]!=S2)&&(v+x[0][i+1]!=S2)&&(v+x[1][i]!=S2)) return F;
    v=x[m][i]; if ((v+x[m][i-1]!=S2)&&(v+x[m][i+1]!=S2)&&(v+x[l][i]!=S2)) return F;
    v=x[i][0]; if ((v+x[i-1][0]!=S2)&&(v+x[i+1][0]!=S2)&&(v+x[i][1]!=S2)) return F;
    v=x[i][m]; if ((v+x[i-1][m]!=S2)&&(v+x[i+1][m]!=S2)&&(v+x[i][l]!=S2)) return F;
  }

  for (int r=1; r<m; ++r) for (int c=1; c<m; ++c) { 
    v=x[r][c];
    if ((v+x[r-1][c]!=S2)&&(v+x[r][c+1]!=S2)&&(v+x[r+1][c]!=S2)&&(v+x[r][c-1]!=S2)) return F;
  }
  return T;
} // isAdjacentEven

bool isAdjacentOdd(int **x, const int n) {
//   -------------
  const int m=n-1, l=n-2, S2=n*n+1, S1=S2/2; int v;

  // corners
  v=x[0][0]; if ((v+x[0][1]!=S2)&&(v+x[1][0]!=S2)) if (v!=S1) return F;
  v=x[0][m]; if ((v+x[0][l]!=S2)&&(v+x[1][m]!=S2)) if (v!=S1) return F;
  v=x[m][0]; if ((v+x[m][1]!=S2)&&(v+x[l][0]!=S2)) if (v!=S1) return F;
  v=x[m][m]; if ((v+x[m][l]!=S2)&&(v+x[l][m]!=S2)) if (v!=S1) return F;

  for (int i=1; i<m; ++i) { // rest of top, bottom, left, right
    v=x[0][i]; if ((v+x[0][i-1]!=S2)&&(v+x[0][i+1]!=S2)&&(v+x[1][i]!=S2)) if (v!=S1) return F;
    v=x[m][i]; if ((v+x[m][i-1]!=S2)&&(v+x[m][i+1]!=S2)&&(v+x[l][i]!=S2)) if (v!=S1) return F;
    v=x[i][0]; if ((v+x[i-1][0]!=S2)&&(v+x[i+1][0]!=S2)&&(v+x[i][1]!=S2)) if (v!=S1) return F;
    v=x[i][m]; if ((v+x[i-1][m]!=S2)&&(v+x[i+1][m]!=S2)&&(v+x[i][l]!=S2)) if (v!=S1) return F;
  }

  for (int r=1; r<m; ++r) for (int c=1; c<m; ++c) { 
    v=x[r][c]; if ((v+x[r-1][c]!=S2)&&(v+x[r][c+1]!=S2)&&(v+x[r+1][c]!=S2)&&(v+x[r][c-1]!=S2))
                    if (v!=S1) return F;
  }
  return T;
} // isAdjacentOdd

bool isAdjacent(int **x, const int n) {
//   ----------
  return ((n&1)==0) ? isAdjacentEven(x, n) : isAdjacentOdd(x, n);
} // isAdjacent
//==================================== output squares ===================================

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

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

bool outputSquares(const int n, FILE *wfp) {
//   -------------
  const int m=n-1, fw0=fieldWidth(n), fw=fw0+1; if (fw>maxFieldWidth) return F;

  for (int i=0; i<Sindex; i++) {
    int *x=Squares[i], j=0, r=n, c;
    while (r--) {
      if (!fprintFW[fw0](wfp, x[j++])) return F;
      c=m; while (c--) if (!fprintFW[fw](wfp, x[j++])) return F;
      if (fputc('\n', wfp)==EOF) return F;
    }
    if (fputc('\n', wfp)==EOF) return F;
  }
  return T;
} // outputSquares
//================================= sort Frénicle ascending =================================

int cmpSquares(int *key, int *s) {
//  ----------
  int i=0;
  while(i++<sLen) if (*key<*s) return -1; else if (*key++>*s++) return 1; return 0;
} // cmpRowPerms

int findSquare(int *key, int *insertPoint) {
//  ----------
  int first=0, last=Sindex-1, middle;

  while (first<=last) {
    middle=(first+last)/2; int cmp=cmpSquares(key,Squares[middle]);
    if (cmp<0) last=middle-1; else if (cmp>0) first=middle+1; else return T;
  }
  *insertPoint=first; return F;
} // findSquare

bool insertSquare(int *sq, const int insertPoint, bool *storeFail) {
//   ------------
  if (Sindex==allocatedSquaresSize) if (!increaseSquares()) { *storeFail=T; return F; }
  int *p=Squares[Sindex];
  for (int i=Sindex; i>insertPoint; --i) Squares[i]=Squares[i-1];
  for (int i=0; i<sLen; ++i) p[i]=sq[i]; Squares[insertPoint]=p; ++Sindex; return T;
} // insertSquare

bool pushSquare(int **x, const int n, bool *storeFail) {
//   ----------
  int i=0, insertPoint;

  for (int r=0; r<n; ++r) for (int c=0; c<n; ++c) square[i++]=x[r][c];
  if (Sindex==0) insertPoint=0; else if (findSquare(square, &insertPoint)) return F;
  return insertSquare(square, insertPoint, storeFail);
} // pushSquare

#define fForm(iX, jX) for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) t[iX][jX]=x[i][j]
#define xCopy() for (int i=0; i<n; ++i) for (int j=0; j<n; ++j) x[i][j]=t[i][j]

void putInFrenicleForm(int **x, const int n) {
//   -----------------
  const int m=n-1, l=n-2; bool inFrenicleForm=F;
  int **t=bSquare, minC=min(min(x[0][0], x[0][m]), min(x[m][0], x[m][m]));

  if (x[0][0]==minC) {
    if (x[0][1]<x[1][0]) inFrenicleForm=T;         else fForm(j,i);     /* YX */
  } else if (x[0][m]==minC) {
    if (x[1][m]<x[0][l]) fForm(m-j,i);   /* -90 */ else fForm(i,m-j);   /* Y  */
  } else if (x[m][m]==minC) {
    if (x[m][l]<x[l][m]) fForm(m-i,m-j); /* 180 */ else fForm(m-j,m-i); /* XY */
  } else { // x[m][0]==minC
    if (x[l][0]<x[m][1]) fForm(j,m-i);   /* 90  */ else fForm(m-i,j);   /* X  */
  }
  if (!inFrenicleForm) xCopy();
} // putInFrenicleForm

bool putSquare(int **x, const int n) {
//   ---------
  bool storeFail=F;
  putInFrenicleForm(x,n); pushSquare(x, n, &storeFail); return !storeFail;
} // putSquare
//======================================= common procedures ======================================

void seed_rand() { srand((unsigned int)time(NULL)); }

int random(const int x) { return rand()%x; }

bool randomBool() { return random(2)==0; }

typedef void (*t_Turn)(int**, int**, const int, const int, const int);
void no_Turn   (int **x, int **b, const int n, const int i, const int j) { x[i][j]    =b[i][j]; };
void rotate_90 (int **x, int **b, const int n, const int i, const int j) { x[j][n-i]  =b[i][j]; };
void rotate_180(int **x, int **b, const int n, const int i, const int j) { x[n-i][n-j]=b[i][j]; };
void rotate_270(int **x, int **b, const int n, const int i, const int j) { x[n-j][i]  =b[i][j]; };
void rotate_Y  (int **x, int **b, const int n, const int i, const int j) { x[i][n-j]  =b[i][j]; };
void rotate_XY (int **x, int **b, const int n, const int i, const int j) { x[n-j][n-i]=b[i][j]; };
void rotate_X  (int **x, int **b, const int n, const int i, const int j) { x[n-i][j]  =b[i][j]; };
void rotate_YX (int **x, int **b, const int n, const int i, const int j) { x[j][i]    =b[i][j]; };
static t_Turn turnCell[]={ no_Turn,  rotate_90, rotate_180, rotate_270,
                             rotate_Y, rotate_XY, rotate_X, rotate_YX };
void Turn(int **x, int **b, const int o, const int n) {
//   ----
  const int numRotations=8, nmo=n-o, npo=n+o, k=random(numRotations); int r, c;

  if (nmo<7) { // turn all 4, 5, 6, 7
    for (r=o; r<=n; r++) for (c=o; c<=n; c++) turnCell[k](x, b, 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](x, b, npo, r, c);
    for (c=o; c<=n; c+=nmo) for (r=p; r<n; ++r)      turnCell[k](x, b, npo, r, c);
    for (r=p; r<=m; r+=(nmo-2)) for (c=p; c<=m; ++c) turnCell[k](x, b, npo, r, c);
    for (c=p; c<=m; c+=(nmo-2)) for (r=p; r<m; ++r)  turnCell[k](x, b, npo, r, c);
  }
} // Turn

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

void complement(int **b, const int o, const int n) {
//   ----------
  if (randomBool()) {
    for (int r=o; r<=n; ++r) for (int c=o; c<=n; ++c) b[r][c]=-b[r][c];
  }
} // complement

void swapBorder(int **b, const int o, const int n) {
//   -----------
  if (randomBool()) {
    const int p=o+1, m=n-1; int t;
    for (int c=o; c<=n; ++c) {
      t=b[o][c]; b[o][c]=b[p][c]; b[p][c]=t; t=b[n][c]; b[n][c]=b[m][c]; b[m][c]=t;
    }
    for (int r=o; r<=n; ++r) {
      t=b[r][o]; b[r][o]=b[r][p]; b[r][p]=t; t=b[r][n]; b[r][n]=b[r][m]; b[r][m]=t;
    }
  }
} // swapBorder

void putBorder(int **x, int **b, const int o, const int n) {
//   ---------
  int *top=tSide, *bot=bSide, *lt=lSide, *rt=rSide;
  const int m=n-1, p=o+1; int length=n-o-3; // remaining choices in top, bot

  for (int c=o+2; c<m; ++c) {
    const int d=c+1; int i=random(length); int v=top[i]; bool pair;
    if (length==1) pair=F;
    else if (i==0) pair=(v==-top[i+1]);
    else if (i==(length-1)) { if (pair=(v==-top[i-1])) v=top[--i];
    } else if (v==-top[i-1]) { pair=T; v=top[--i];
    } else pair=(v==-top[i+1]);
    if (pair) {
      b[o][c]= v; b[o][d]=-v; v=v<0 ? v-2 : v+2; b[p][c]=-v; b[p][d]= v; v=bot[i];
      b[n][c]= v; b[n][d]=-v; v=v<0 ? v-2 : v+2; b[m][c]=-v; b[m][d]= v; ++c;
      for (int j=i; j<length; ++j) { top[j]=top[j+2]; bot[j]=bot[j+2]; } length-=2;
    } else {
      b[o][c]= v; b[p][c]=-v; v=bot[i]; b[n][c]= v; b[m][c]=-v;
      for (int j=i; j<length; ++j) { top[j]=top[j+1]; bot[j]=bot[j+1]; } --length;
    }
  }

  length=n-o-3; // remaining choices in lt, rt
  for (int r=o+2; r<m; ++r) {
    const int s=r+1; int i=random(length); int v=lt[i]; bool pair;
    if (length==1) pair=F;
    else if (i==0) pair=(v==-lt[i+1]);
    else if (i==(length-1)) { if (pair=(v==-lt[i-1])) v=lt[--i];
    } else if (v==-lt[i-1]) { pair=T; v=lt[--i];
    } else pair=(v==-lt[i+1]);
    if (pair) {
      b[r][o]= v; b[s][o]=-v; v=v<0 ? v-2 : v+2; b[r][p]=-v; b[s][p]= v; v=rt[i];
      b[r][n]= v; b[s][n]=-v; v=v<0 ? v-2 : v+2; b[r][m]=-v; b[s][m]= v; ++r;
      for (int j=i; j<length; ++j) { lt[j]=lt[j+2]; rt[j]=rt[j+2]; } length-=2;
    } else {
      b[r][o]=v; b[r][p] =-v; v=rt[i]; b[r][n]=v; b[r][m] =-v;
      for (int j=i; j<length; ++j) { lt[j]=lt[j+1]; rt[j]=rt[j+1]; } --length;
    }
  }
  swapBorder(b, o, n); Turn(x, b, o, n);
} // putBorder
//=========================================== even ========================================

const int num4x4a=48;  //+complements=96
int code4x4a[]={
0x03dfc26b,0x03dfc2a7,0x03efc15b,0x03efc197,0x05bfa46d,0x05bfa4c7,0x05efa13d,0x05efa197,
0x06bf945e,0x06bf94c7,0x06df923e,0x06df92a7,0x097f68ad,0x097f68cb,0x09ef613d,0x09ef615b,
0x0a7f589e,0x0a7f58cb,0x0adf523e,0x0adf526b,0x0c7f389e,0x0c7f38ad,0x0cbf345e,0x0cbf346d,
0x12fed04a,0x12fed086,0x14feb02c,0x14feb086,0x17ae854f,0x17ce832f,0x18fe702c,0x18fe704a,
0x1b6e498f,0x1bce432f,0x1d6e298f,0x1dae254f,0x21fde049,0x21fde085,0x24fdb085,0x279d864f,
0x28fd7049,0x2b5d4a8f,0x2d4e189f,0x2d8e145f,0x41fbe083,0x42fbd083,0x4b8d213f,0x4b8e123f
};

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

void putCenter4x4(int **x, int **b, const int o, const int n) {
//   ------------
  const int Msum=34; // 4*(4*4+1)/2;
  int code=code4x4a[random(num4x4a)];

  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)
  complement(b, o, n); Turn(x, b, o, n);
} // putCenter4x4

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

void makeEven4(int **x, int **b, const int size) {
//   ---------
  int v=9; // (4*4+1)/2; (8.5)

  // fill center 4x4
  int 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, rl=0, rr=0;
    o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1;
    b[o][o]=-v; b[p][o]=v++; /* NW */ b[m][n]=-v; b[n][n]=v++; /* SE */
    b[n][m]=-v; b[m][m]=v++; /* SE */ b[p][p]=-v; b[o][p]=v++; /* NW */

    const int k=(i-4)/4; int *top=tSide, *bot=bSide, *lt=lSide, *rt=rSide;
    int j=k; while (j--) {
      top[ct++]= v++; top[ct++]=-v++; bot[cb++]= v++; bot[cb++]=-v++;
      lt[rl++] = v++; lt[rl++] =-v++; rt[rr++] = v++; rt[rr++] =-v++;
      top[ct++]=-v++; top[ct++]= v++; bot[cb++]=-v++; bot[cb++]= v++;
      lt[rl++] =-v++; lt[rl++] = v++; rt[rr++] =-v++; rt[rr++] = v++;
    }
    b[p][m]=-v; b[o][m]=v++; /* NE */ b[n][p]=-v; b[m][p]=v++; /* SW */
    b[m][o]=-v; b[n][o]=v++; /* SW */ b[o][n]=-v; b[p][n]=v++; /* NE */

    putBorder(x, b, o, n);
  } // for (i=8; ...
  biggestValue=v-1;
}  // makeEven4

void makeEven6(int **x, int **b, const int size) {
//   ---------
  int v=19; // (6*6+1)/2; (18.5)

  // fill center 6x6
  int o=(size-6)/2, n=o+5; putCenter6x6(x, b, o, n); 
  for (int i=10; i<=size; i+=4) {
    int ct=0, cb=0, rl=0, rr=0;
    o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1;
    b[o][o]=-v; b[p][o]=v++; /* NW */ b[m][n]=-v; b[n][n]=v++; /* SE */
    b[n][m]=-v; b[m][m]=v++; /* SE */ b[p][p]=-v; b[o][p]=v++; /* NW */

    const int k=(i-6)/4;
    int *top=tSide, *bot=bSide, *lt=lSide, *rt=rSide;
    top[ct++]=-v; top[ct++]= v++; bot[cb++]= v; bot[cb++]=-v; v+=3;
    lt[rl++] = v; lt[rl++] =-v++; rt[rr++] =-v; rt[rr++] = v; v+=3;
    int j=k; while (j--) {
      top[ct++]= v++; top[ct++]=-v++; bot[cb++]= v++; bot[cb++]=-v++;
      lt[rl++] = v++; lt[rl++] =-v++; rt[rr++] = v++; rt[rr++] =-v++;
      top[ct++]=-v++; top[ct++]= v++; bot[cb++]=-v++; bot[cb++]= v++;
      lt[rl++] =-v++; lt[rl++] = v++; rt[rr++] =-v++; rt[rr++] = v++;
    }
    b[p][m]=-v; b[o][m]=v++; /* NE */ b[n][p]=-v; b[m][p]=v++; /* SW */
    b[m][o]=-v; b[n][o]=v++; /* SW */ b[o][n]=-v; b[p][n]=v++; /* NE */

    putBorder(x, b, o, n);
  } // for (i=10; ...
  biggestValue=v-1;
}  // makeEven6

void makeEven(int **x, int **b, const int n) {
//   --------
  if ((n&3)==0) makeEven4(x, b, n); else makeEven6(x, b, n);
}
//============================================== odd ==========================================

const int num5x5a=50;
Sbyte code5x5a[][5*5]={
  {0,-4,4,-2,2,-1,-8,8,6,-5,1,12,-12,-6,5,-7,-3,10,11,-11,7,3,-10,-9,9},
  {0,-4,4,-2,2,-1,-8,8,6,-5,1,12,-12,-6,5,-7,-3,10,11,-11,7,3,-10,-9,9},
  {7,2,-9,5,-5,-7,-2,9,3,-3,6,-6,-12,1,11,-10,10,12,-1,-11,4,-4,0,-8,8},
  {0,-2,2,-4,4,1,-9,9,-6,5,-1,11,-11,6,-5,-10,3,7,12,-12,10,-3,-7,-8,8},
  {0,5,-5,-10,10,-12,1,11,3,-3,12,-1,-11,7,-7,6,4,-4,2,-8,-6,-9,9,-2,8},
  {3,-3,0,8,-8,-10,-1,11,4,-4,10,1,-11,-12,12,-9,9,-5,7,-2,6,-6,5,-7,2},
  {0,-1,1,-5,5,-8,-9,9,-3,11,8,10,-10,3,-11,-6,2,4,12,-12,6,-2,-4,-7,7},
  {0,-4,4,3,-3,-11,1,10,6,-6,11,-1,-10,-9,9,5,12,-12,2,-7,-5,-8,8,-2,7},
  {8,-8,0,-7,7,3,-3,10,2,-12,-11,11,-10,-2,12,4,5,-9,6,-6,-4,-5,9,1,-1},
  {0,2,-2,-4,4,5,-11,11,1,-6,-5,9,-9,-1,6,-7,-3,10,12,-12,7,3,-10,-8,8},
  {0,-10,10,-4,4,-11,1,-1,3,8,11,9,-9,-3,-8,-7,-5,12,6,-6,7,5,-12,-2,2},
  {3,4,-7,5,-5,-3,-4,7,6,-6,12,-12,-9,1,8,-10,10,9,-1,-8,-2,2,0,-11,11},
  {0,-3,3,-1,1,4,-12,8,-5,5,-4,12,-8,6,-6,-2,10,-10,11,-9,2,-7,7,-11,9},
  {5,1,10,-10,-6,-5,-1,-7,7,6,11,-11,-8,-4,12,-9,9,8,4,-12,-2,2,-3,3,0},
  {6,-6,0,10,-10,-9,1,8,2,-2,9,-1,-8,-12,12,-11,11,-7,4,3,5,-5,7,-4,-3},
  {0,5,-5,-3,3,-2,-12,12,-4,6,2,7,-7,4,-6,-9,-1,10,11,-11,9,1,-10,-8,8},
  {-1,1,-11,9,2,-5,5,11,-9,-2,12,-8,-7,7,-4,-12,8,-3,3,4,6,-6,10,-10,0},
  {8,-8,0,6,-6,3,-3,7,5,-12,-11,11,-7,-5,12,1,9,-10,-2,2,-1,-9,10,-4,4},
  {-12,12,5,-5,0,2,-2,6,1,-7,10,-10,-6,-1,7,3,8,-9,9,-11,-3,-8,4,-4,11},
  {5,2,12,-12,-7,-5,-2,-4,4,7,11,-11,-6,-3,9,-10,10,6,3,-9,-1,1,-8,8,0},
  {-1,1,-12,10,2,-8,8,12,-10,-2,11,-5,-6,7,-7,-11,5,6,-4,4,9,-9,0,-3,3},
  {-4,12,-8,3,-3,4,-12,8,7,-7,2,5,-5,-11,9,-2,1,-1,11,-9,0,-6,6,-10,10},
  {-3,3,-10,11,-1,-6,6,10,-11,1,12,-8,-5,5,-4,-12,8,-2,2,4,9,-9,7,-7,0},
  {-4,6,-2,11,-11,4,-6,2,-3,3,1,-1,-5,-7,12,-10,10,5,7,-12,9,-9,0,-8,8},
  {-12,1,11,5,-5,12,-1,-11,3,-3,2,4,-4,-9,7,-2,6,-6,9,-7,0,-10,10,-8,8},
  {-3,3,10,-10,0,-8,8,4,-9,5,11,-11,-4,9,-5,-6,7,2,-2,-1,6,-7,-12,12,1},
  {-6,6,0,9,-9,5,-5,4,7,-11,1,-1,-4,-7,11,2,8,-10,3,-3,-2,-8,10,-12,12},
  {0,10,-10,-5,5,9,-12,3,-1,1,-9,12,-3,6,-6,-7,-8,8,11,-4,7,-2,2,-11,4},
  {-4,4,-8,8,0,-12,2,11,-11,10,12,-2,-3,3,-10,-5,5,7,-1,-6,9,-9,-7,1,6},
  {-5,5,-11,12,-1,-4,4,11,-12,1,10,-7,-3,-8,8,-10,7,3,6,-6,9,-9,0,2,-2},
  {-7,12,-5,1,-1,7,-12,5,9,-9,3,2,-2,-11,8,-3,-6,6,11,-8,0,4,-4,-10,10},
  {-4,4,-10,10,0,-7,1,12,-12,6,7,-1,-2,2,-6,-5,5,11,-3,-8,9,-9,-11,3,8},
  {-5,5,0,-7,7,-6,6,2,-12,10,11,-11,-2,12,-10,-8,-1,9,4,-4,8,1,-9,3,-3},
  {-12,8,4,7,-7,12,-8,-4,3,-3,2,1,-1,-11,9,-2,5,-5,11,-9,0,-6,6,-10,10},
  {-4,4,-7,7,0,-6,6,1,-12,11,10,-10,-1,12,-11,-8,5,-2,2,3,8,-5,9,-9,-3},
  {-9,9,2,5,-7,6,-6,-2,-5,7,11,-10,-1,-8,8,-11,10,1,12,-12,3,-3,0,-4,4},
  {-12,1,11,-10,10,12,-1,-11,6,-6,-2,2,0,4,-4,9,-9,-3,8,-5,-7,7,3,-8,5},
  {-11,3,8,-10,10,11,-3,-8,-2,2,-6,6,0,12,-12,7,-7,4,5,-9,-1,1,-4,-5,9},
  {-10,3,7,-8,8,10,-3,-7,6,-6,-4,4,0,2,-2,9,-9,-11,12,-1,-5,5,11,-12,1},
  {-9,-2,11,4,-4,9,2,-11,8,-8,10,-10,0,-12,12,-3,3,5,1,-6,-7,7,-5,-1,6},
  {-8,-4,12,6,-6,8,4,-12,-1,1,-11,11,0,-5,5,2,-2,-10,7,3,9,-9,10,-7,-3},
  {-7,6,1,-12,12,7,-6,-1,2,-2,-8,8,0,10,-10,11,-11,5,4,-9,-3,3,-5,-4,9},
  {-6,-2,8,1,-1,6,2,-8,-12,12,-5,5,0,11,-11,-4,4,10,-3,-7,9,-9,-10,3,7},
  {-5,-1,6,-11,11,5,1,-6,2,-2,-7,7,0,9,-9,10,-10,12,-4,-8,-3,3,-12,4,8},
  {-4,4,-12,11,1,9,-9,12,-11,-1,-5,5,0,7,-7,-2,8,-6,3,-3,2,-8,6,-10,10},
  {-3,3,-12,10,2,11,-11,12,-10,-2,-8,8,0,-4,4,-7,1,6,9,-9,7,-1,-6,-5,5},
  {-2,-6,8,-9,9,2,6,-8,4,-4,-11,11,0,5,-5,12,-12,10,-7,-3,-1,1,-10,7,3},
  {-1,1,-10,7,3,6,-6,10,-7,-3,-5,5,0,11,-11,-8,-4,12,-2,2,8,4,-12,-9,9},
  {1,-6,5,-8,8,-1,6,-5,-4,4,-10,10,0,12,-12,7,-7,11,-9,-2,3,-3,-11,9,2},
  {2,-2,-10,7,3,9,-9,10,-7,-3,-11,11,0,5,-5,-8,-4,12,1,-1,8,4,-12,-6,6}
};

const int num7x7a=25;
Sbyte code7x7a[][16]={
  {1,22,2,-3,-18,-4,-12,-5,-16,10,17,6,-15,24,19,-23},
  {1,3,23,-4,-5,-18,-6,-20,-10,9,8,19,-7,-12,-15,17},
  {2,3,22,-4,-5,-18,-6,-20,-11,8,10,19,-7,-12,-16,17},
  {3,1,23,-4,-5,-18,-6,-20,-10,9,8,19,-7,-12,-15,17},
  {4,1,19,-2,-5,-17,-6,-21,-11,8,7,23,-9,-13,-14,18},
  {5,1,15,-2,-3,-16,-6,-23,-8,11,7,19,9,-14,-10,18},
  {6,1,13,-2,-3,-15,-4,-21,-14,9,7,23,11,-8,-10,18},
  {7,1,11,-3,-2,-14,-4,-19,-13,8,5,23,10,-9,-16,17},
  {8,1,9,-2,-3,-13,-4,-21,-14,11,6,22,15,-5,-12,18},
  {9,1,7,-3,-2,-12,-4,-19,-11,6,5,23,14,-13,-16,17},
  {10,1,7,-2,-4,-12,-3,-18,-22,6,13,24,16,5,-14,19},
  {11,1,5,-2,-3,-12,-4,-17,-22,7,15,21,19,8,-16,18},
  {12,1,3,-2,-4,-10,-5,-18,-14,8,7,22,17,-9,-16,19},
  {13,1,2,-3,-4,-9,-6,-20,-15,10,7,24,16,-8,-11,19},
  {14,1,2,-3,-4,-10,-5,-16,-17,8,9,21,18,-7,-15,19},
  {15,1,2,-3,-4,-11,-5,-22,-8,6,10,19,21,-12,-18,13},
  {16,1,2,-3,-4,-12,-5,-18,-14,9,11,17,22,-7,-10,20},
  {17,1,2,-3,-4,-13,-5,-15,-11,7,6,18,22,-8,-14,20},
  {18,1,2,-3,-4,-14,-5,-11,-23,12,7,20,22,8,-9,16},
  {19,1,2,-3,-4,-15,-5,-12,-21,6,9,23,22,8,-10,17},
  {20,1,2,-3,-4,-16,-5,-11,-23,10,8,21,22,9,-7,15},
  {21,1,2,-3,-4,-17,-5,-11,-24,10,7,23,12,9,-8,19},
  {22,1,2,-3,-4,-18,-5,-12,-16,10,6,17,13,-8,-9,20},
  {23,1,2,-3,-4,-19,-5,-13,-11,6,7,16,12,-10,-18,17},
  {24,1,2,-3,-4,-20,-5,-11,-21,9,10,18,17,7,-13,12}
};

const int num7x7b=2;
Sbyte code7x7b[][49]={
  {-21,6,-10,10,15,-1,1,21,-6,-9,9,-15,4,-4,-12,12,8,2,-2,14,-22,13,-24,-8,0,11,
   -14,22,-13,24,19,-19,-11,-3,3,17,-17,-16,-20,20,23,-7,-5,5,16,18,-18,-23,7},
  {-12,5,-15,15,7,-1,1,12,-5,13,-13,-7,22,-22,-14,14,10,3,-3,9,-19,8,-24,-10,0,
   16,-9,19,-8,24,2,-2,-16,-21,21,18,-18,-11,-23,23,17,-6,-4,4,11,20,-20,-17,6}
};

void putCenter5x5(int **x, int **b, const int o, const int n) {
//   ------------
  const Sbyte *code=code5x5a[random(num5x5a)]; int i=0;
  for (int r=o; r<=n; ++r) for (int c=o; c<=n; ++c) b[r][c]=code[i++];
  complement(b, o, n); Turn(x, b, o, n);
} // putCenter5x5

void putCenter7x7(int **x, int **b, const int o, const int n) {
//   ------------
  int i=0;
  if (random(num7x7a+num7x7b)<num7x7b) {
    const Sbyte *code=code7x7b[random(num7x7b)];
    for (int r=0; r<7; ++r) for (int c=0; c<7; ++c) b[o+r][o+c]=code[i++];
  } else {
    const Sbyte *code=code7x7a[random(num7x7a)];
    b[o][o]    =code[i++];  b[o+1][o+1]=code[i++];
    b[o+2][o+2]=code[i++];  b[o+4][o+4]=code[i++];
    b[o+5][o+5]=code[i++];  b[n][n]    =code[i++];

    b[o][n]    =code[i++];  b[o+1][o+5]=code[i++];
    b[o+2][o+4]=code[i++];  b[o+4][o+2]=code[i++];
    b[o+5][o+1]=code[i++];  b[n][o]    =code[i++];

    b[o][o+2]  =code[i++];  b[o+2][o+5]=code[i++];
    b[o+3][o]  =code[i++];  b[o+5][o+3]=code[i++];
    b[o][o+1]  =-b[o][o];   b[o][o+3]  =-b[o][o+2];

    b[o][o+4]  =b[o+1][o+5]-b[o][n]; b[o][o+5]=-b[o+1][o+5];
    b[o+1][o]  =-b[o+1][o+1]; b[o+1][o+2]=-b[o][o+2]-b[o+2][o+2];
    b[o+1][o+3]=-b[o+1][o+2]; b[o+1][o+4]=-b[o][o+4];
    
    b[o+1][n]  =-b[o][n];   b[o+2][o]  =b[o+1][o+1]-b[o][o];
    b[o+2][o+1]=-b[o+2][o]; b[o+2][o+3]=-b[o+2][o+2];
    b[o+2][n]  =-b[o+2][o+4]-b[o+2][o+5]; b[o+3][o+1]=-b[o+3][o]+b[o+4][o+2];

    b[o+3][o+2]=-b[o+4][o+2]; b[o+3][o+3]=0; b[o+3][o+4]=-b[o+2][o+4];
    b[o+3][o+5]=-b[o+2][o+5]; b[o+3][n]  =-b[o+2][n];
    b[o+4][o]  =-b[o+3][o];   b[o+4][o+1]=-b[o+3][o+1];

    b[o+4][o+3]=-b[o+4][o+4]; b[o+4][o+5]=b[n][n]-b[o+5][o+5];
    b[o+4][n]  =-b[o+4][o+5]; b[o+5][o]  =-b[n][o];
    b[o+5][o+2]=b[n][o]-b[o+5][o+1]; b[o+5][o+4]=-b[o+5][o+3];

    b[o+5][n]=-b[o+5][o+5]; b[n][o+1]=-b[o+5][o+1];
    b[n][o+2]=-b[o+5][o+2]; b[n][o+3]=b[o+4][o+4]-b[o+5][o+3];
    b[n][o+4]=-b[n][o+3];   b[n][o+5]=-b[n][n];
  }
  complement(b, o, n); Turn(x, b, o, n);
} // putCenter7x7

void makeOdd5(int **x, int **b, const int size) {
//   --------
  int v=13; // (5*5+1)/2;

  // fill center 5x5
  int o=(size-5)/2, n=o+4; putCenter5x5(x, b, o, n); 
  for (int i=9; i<=size; i+=4) {
    int ct=0, cb=0, rl=0, rr=0, k=(i-5)/4;
    o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1;
    int *top=tSide, *bot=bSide, *lt=lSide, *rt=rSide;

    b[p][o]=-v; b[p][p]=v++; /* NW */ b[m][m]=-v; b[m][n]=v++; /* SE */
    b[n][p]=-v; b[m][p]=v++; /* SW */ b[p][m]=-v; b[o][m]=v++; /* NE */

    top[ct++]= v++; top[ct++]=v;   top[ct++]=-v++; bot[cb++]=-v; v+=2; rt[rr++]=v++;
    bot[cb++]=-v;   bot[cb++]=v++; lt[rl++] =-v; v+=2; lt[rl++]=v; lt[rl++]=-v++;
    rt[rr++] =-v;   rt[rr++] =v; v+=3;

    top[ct++]=-v++; bot[cb++]=v++; rt[rr++] =-v++; lt[rl++]=v++;
    top[ct++]= v++; bot[cb++]=-v++; rt[rr++]= v++; lt[rl++]=-v++;

    int j=k; while (--j) {
      top[ct++]= v++; rt[rr++] = v++;  bot[cb++]=-v++; lt[rl++] =-v++;
      top[ct++]=-v;   top[ct++]= v++; bot[cb++] = v;   bot[cb++]=-v; v+=3;
      lt[rl++] = v;   lt[rl++] =-v++; rt[rr++]  =-v;   rt[rr++] = v; v+=3;
    }
    j=k; while (--j) {
      top[ct++]=-v++; rt[rr++]=-v++; bot[cb++]= v++; lt[rl++]= v++;
    }

    b[o][n]=-v; b[p][n]= v++; /* NE */ b[n][o]= v; b[m][o]=-v++; /* SW */
    b[n][n]=-v; b[n][m]= v++; /* SE */ b[o][o]= v; b[o][p]=-v++; /* NW */

    putBorder(x, b, o, n);
  } // for (i=9; ...
  biggestValue=v-1;
}  // makeOdd5

void makeOdd7(int **x, int **b, const int size) {
//   --------
  int v=25; // (7*7+1)/2;

  // fill center 7x7
  int o=(size-7)/2, n=o+6; putCenter7x7(x, b, o, n); 
  for (int i=11; i<=size; i+=4) {
    int ct=0, cb=0, rl=0, rr=0; const int k=(i-7)/4;
    o=(size-i)/2;  n=o+i-1; const int p=o+1, m=n-1;
    int *top=tSide, *bot=bSide, *lt=lSide, *rt=rSide;

    b[p][o]=-v; b[p][p]=v++; /* NW */ b[m][m]=-v; b[m][n]=v++; /* SE */
    b[n][p]=-v; b[m][p]=v++; /* SW */ b[p][m]=-v; b[o][m]=v++; /* NE */

    top[ct++]= v++; top[ct++]=v; top[ct++]=-v++; bot[cb++]=-v; v+=2;  rt[rr++] = v++;
    bot[cb++]=-v;   bot[cb++]= v++; lt[rl++] =-v; v+=2; lt[rl++] = v; lt[rl++]=-v++;
    rt[rr++] =-v;   rt[rr++] =v; v+=3;

    int j=k; while (--j) { top[ct++]=v++; rt[rr++]=v++; bot[cb++]=-v++; lt[rl++]=-v++; }

    j=2; while (j--) {
      top[ct++]=-v; top[ct++]= v++; bot[cb++]= v; bot[cb++]=-v; v+=3;
      lt[rl++] = v; lt[rl++] =-v++; rt[rr++] =-v; rt[rr++] = v; v+=3;
    }
    j=k; while (--j) {
      top[ct++]=-v++; rt[rr++]=-v++;  bot[cb++]= v++; lt[rl++]= v++;
      top[ct++]=-v;   top[ct++]= v++; bot[cb++]= v;   bot[cb++]=-v; v+=3;
      lt[rl++] = v;   lt[rl++] =-v++; rt[rr++] =-v;   rt[rr++] = v; v+=3;
    }

    b[o][n]=-v; b[p][n]= v++; /* NE */ b[n][o]= v; b[m][o]=-v++; /* SW */
    b[n][n]=-v; b[n][m]= v++; /* SE */ b[o][o]= v; b[o][p]=-v++; /* NW */

    putBorder(x, b, o, n);
  } // for (i=11; ...
  biggestValue=v-1;
}  // makeOdd7

void makeOdd(int **x, int **b, const int n) {
//   -------
  if ((n-1)%4==0) makeOdd5(x, b, n); else makeOdd7(x, b, n);
} // makeOdd
//========================================== odd, even ==================================

const char *notMagic =
  "\a\nERROR: Square is NOT magic! Please report by email\n";
const char *notAdjacent =
  "\a\nERROR: Square is NOT adjacent paired! Please report by email\n";

bool makeSquare(const int n) {
//   ----------
  int **x=xSquare, **b=bSquare;
  if ((n&1)==0) makeEven(x, b, n); else makeOdd(x, b, n); makeActual(x, n);
  if (isCorrect(x, n)) { if (!isAdjacent(x, n)) printf(notAdjacent);
  } else printf(notMagic); return putSquare(x, n);
} // makeOdd
//======================================== input ========================================

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

bool getY() {
//   ----
  int c;  do { c=getchar(); } while ((c==' ')|(c=='\t')|(c=='\n'));
  clearLine(c);  return (c=='Y')|(c=='y');
}

bool getYorOrder(int *n) {
//   -----------
  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 getInt() { 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="AdjacentSideSquares"; 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
//================================================= main =================================================

bool validOrder(const int n) {
//   ----------
  switch (n) {
  case 1: case 3:
    printf("\aThere is no adjacent paired magic square of order %i.\n", n); return F;
  case 2:
    printf("\aERROR: There is no magic square of order 2.\n"); return F;
  default:
    if (n<=0) {
      printf("\aERROR: N must be a positive integer.\n"); return F;
    } else return T;
  }
}// validOrder

int main() {
//  ----
  bool ok=F;
  if (openDir()) {
    bool another=T, inputSize=T, writeError=F; int n=0; seed_rand(); 
    do {     
      if (inputSize) { printf("\nInput the order of the square: "); n=getInt(); }
      if (validOrder(n)) {
	      if (allocateStore(n)) {
	        FILE *wfp=NULL;
	        if ( (wfp=open_File(n))!=NULL) {
            Sindex=0; sLen=n*n;
            printf("\nHow many? "); int howMany=getInt(), loop=max(howMany,1000000); 
            while (loop--) {
              ok=makeSquare(n); if (!ok) break; if (Sindex==howMany) break;
            }
            if (ok) writeError=!outputSquares(n, wfp); fclose(wfp);
	        }
	      } else printf("\a\nERROR: Storage allocation failed.\n");
      }
      if (writeError) { perror("\a\nError writing file"); another=F;
      } else {
        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);
    freeStore(); 
  }
  printf("\nPress a key to close the console.");
  while (!_kbhit()) Sleep(250); return ok?EXIT_SUCCESS:EXIT_FAILURE;
} // main