/*
 *  File:    LatinSquares.cpp
 *  Author:  S Harry White
 *  Created: 2018-11-14
 *  Updated: 2022-01-09
 *    Replace & with && where necessary. Tidy code.
 *  Updated: 2023-01-18
 *    Change to compile with g++ for macOS.
 */

/*
 * Uses backtracking to make small order Latin squares, LS, and diagonal Latin squares, DLS,
 * of various types:
 *
 *   LS: LS, axial symmetric, double axial symmetric, center symmetric, orthogonal,
 *       self-orthogonal, natural order first row and first column, self-transpose
 *           
 *  DLS: DLS, axial symmetric, double axial symmetric, center symmetric,
 *        orthogonal, self-orthogonal, associative, pandiagonal
 *
 * Here LS exclude DLS, and axial symmetric exclude double axial symmetric.
 *
 * All squares, except associative and pandiagonal, are made with natural order first row,
 * (NFR), 0 1 2 ... n-1. Associative are natural order \diagonal. For DLS, the center symmetric
 * squares equate to the NFR permutation of the associative squares.
 *
 * Symmetric means that there is one-to-one correspondence between all opposite pairs of
 * elements. Axial symmetric means opposite in each row or in each column. Double axial
 * symmetric means opposite in each row and in each column.
 *
 * Orthogonal refers to two adjacent squares.
 *
 * Self-transpose means that the LS is equal to its transpose, (symmetric matrix).
 *
 * Some weakly pandiagonal are Latin squares; some are diagonal Latin. 
 *
 */

#include <ctype.h>
#include <curses.h>
#include <errno.h>
#include <fcntl.h>
//#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
//#include <sys/types.h>
#include <time.h>
#include <unistd.h>

typedef unsigned int Uint;

const int maxN=31, maxH=16, trn=100000,
          B[]={ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
                16384, 32768, 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22,
                1<<23, 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30, 1<<31 };

int N, M, L, NN, Nd2, Nd2m1, N3d4, N3m2d2, BM, A, // (1<<N)-1
    Q[maxN][maxN], R[maxN][maxN], O[maxN][maxN], S[maxN], U[maxN], rU[maxN], cU[maxN], bU, fU,
    opp[maxN], qrU[maxN], squareBytes, numSquares, outSquares, outBytes;

typedef struct { Uint c[maxH]; } t_tr;
t_tr tr[maxH][trn];      // transversals
int  ltr[maxH];          // tr lengths
const int square10Bytes=201, num10Squares=200000,
outBufferSize=num10Squares*square10Bytes;
char outBuffer[outBufferSize], *outPointer=NULL; const bool F=false, T=true; bool odd, writeError;

int P(const int b) {
  if (b<(1<<Nd2)) { for (int i=0; i<Nd2; ++i) if ((1<<i)==b) return i; }
  else for (int i=Nd2; i<N; ++i) if ((1<<i)==b) return i; return -1;
} // P

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

int random_(int x) { return rand()%x; }
//  -------

void printElapsedTime(time_t startTime, const int c) {
//   ---------------- 
  int et=(int)difftime(time(NULL), startTime);
  if (et>0) printf("%celapsed time %d:%02d:%02d\n", c, et/3600, et%3600/60, et%60);
} // printElapsedTime

void initGlobals() {
//   -----------
  M=N-1; L=M-1; NN=N*N; Nd2=N/2; Nd2m1=Nd2-1; N3d4=3*N/4; N3m2d2=(3*N-2)/2;
  A=(N==32)? -1 : B[N]-1; BM=B[M]; squareBytes=((N<11) ? 2 : 3)*NN+1; outSquares=0; odd=N&1;
  writeError=F; numSquares=outBufferSize/squareBytes; outBytes=numSquares*squareBytes;
} // initGlobals
//============================================== input ==============================================

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

int getInt() { int n=0; scanf("%d", &n); clearLine(getchar()); return n; }
//  -------

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

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
//================================================ output ================================================

const int bufSize=1024, outSize=bufSize+50;
char dirName[bufSize]; char outputFile[bufSize];
bool openDir(const char *name) {
//   -------
  char buf[bufSize], msg[bufSize+50]; strcpy(buf, name); int sub=0;
  do {
    if (mkdir(buf, 0775)==0) break;
    if (errno!=EEXIST) {
      snprintf(msg, bufSize+50, "Can't make folder %s", buf); perror(msg); return F;
    }
    snprintf(buf, bufSize, "%s_%d", name, ++sub);
  } while (T); 
  if (chdir(buf)!=0) {
    snprintf(msg, bufSize+50, "Can't open folder %s", buf); perror(msg); return F;
  }
  strcpy(dirName, buf); printf("Output files are in folder %s\n", buf); return T;
} // openDir

int openOutput(const char *which) {
//  ----------
  int wfd=-1; char buf[outSize]; int sub=0; const int baseSize=bufSize+25; char baseName[baseSize];
  snprintf(baseName, bufSize, "./%s%d", which, N); snprintf(buf, outSize, "%s.txt", baseName);
  do {
    if (access(buf, F_OK)!=0) break; snprintf(buf, outSize, "%s_%d.txt", baseName, ++sub);
  } while (T);
  if ((wfd=open(buf, O_CREAT|O_WRONLY))==-1) {
    char msg[outSize+50]; snprintf(msg, outSize+50, "\a\nCan't open for write %s", buf); perror(msg);
  } else {
    printf(".. output file is %s\n", buf); snprintf(outputFile, bufSize, "%s", buf);
    chmod(buf, 0644);
  }
  return wfd;
} // openOutput

//FILE *openOutputFP(const char *fname) {
////    ------------
//  char buf[outSize]; snprintf(buf, outSize, "%s.txt", fname);
//  FILE *wfp=NULL; wfp=fopen(buf, "w"); return wfp;
//} // openOutputFP

bool printLSx1(int Q[maxN][maxN], FILE *wfp) {
//   ---------
  for (int i=0; i<N; i++) {
    if (Q[i][0]<0) { if (!fprintf(wfp, " .")) return F; }
    else { if (!fprintf(wfp, "%2d", Q[i][0])) return F; }
    for (int j=1; j<N; j++)
      if (Q[i][j]<0) { if (!fprintf(wfp, "  .")) return F; }
      else { if (!fprintf(wfp, " %2d", Q[i][j])) return F; }
      if (fputc('\n', wfp)==EOF) return F;
  }
  bool ok=fputc('\n', wfp)!=EOF; fflush(wfp); return ok;
} // printLSx1

bool printLSx(int Q[maxN][maxN], FILE *wfp) {
//   --------
  if (N>10) return printLSx1(Q, wfp);
  for (int i=0; i<N; i++) {
    if (Q[i][0]<0) { if (!fprintf(wfp, ".")) return F; }
    else { if (!fprintf(wfp, "%d", Q[i][0])) return F; }
    for (int j=1; j<N; j++)
      if (Q[i][j]<0) { if (!fprintf(wfp, " .")) return F; }
      else { if (!fprintf(wfp, " %d", Q[i][j])) return F; }
      if (fputc('\n', wfp)==EOF) return F;
  }
  bool ok=fputc('\n', wfp)!=EOF; fflush(wfp); return ok;
} // printLSx

bool printLSLT40(int Q[maxN][maxN], int wfd) {
//   -----------
  char *s=outPointer;
  for (int r=0; r<N; ++r) {
    for (int c=0; c<N; ++c) { int v=Q[r][c];
      if (v<10) { *s++=' '; *s++='0'+v; } else if (v<20) { *s++='1'; *s++='0'-10+v; }
      else if (v<30) { *s++='2'; *s++='0'-20+v; } else { *s++='3'; *s++='0'-30+v; }
      if (c==M) *s++='\n'; else *s++=' ';
    }
  }
  *s++='\n'; outPointer=s;
  if (++outSquares==numSquares) {
    if (write(wfd, outBuffer, outBytes)!=outBytes) { writeError=T; return F; }
    outPointer=outBuffer; outSquares=0;
  }
  return T;
} // printLSLT40

bool printLSLT30(int Q[maxN][maxN], int wfd) {
//   -----------
  char *s=outPointer;
  for (int r=0; r<N; ++r) {
    for (int c=0; c<N; ++c) { int v=Q[r][c];
      if (v<10) { *s++=' '; *s++='0'+v; } else if (v<20) { *s++='1'; *s++='0'-10+v; }
      else { *s++='2'; *s++='0'-20+v; } if (c==M) *s++='\n'; else *s++=' ';
    }
  }
  *s++='\n'; outPointer=s;
  if (++outSquares==numSquares) {
    if (write(wfd, outBuffer, outBytes)!=outBytes) { writeError=T; return F; }
    outPointer=outBuffer; outSquares=0;
  }
  return T;
} // printLSLT30

bool printLSLT20(int Q[maxN][maxN], int wfd) {
//   -----------
  char *s=outPointer;
  for (int r=0; r<N; ++r) {
    for (int c=0; c<N; ++c) { int v=Q[r][c];
      if (v<10) { *s++=' '; *s++='0'+v; } else { *s++='1'; *s++='0'-10+v; }
      if (c==M) *s++='\n'; else *s++=' ';
    }
  }
  *s++='\n'; outPointer=s;
  if (++outSquares==numSquares) {
    if (write(wfd, outBuffer, outBytes)!=outBytes) { writeError=T; return F; }
    outPointer=outBuffer; outSquares=0;
  }
  return T;
} // printLSLT20

bool printLS(int Q[maxN][maxN], int wfd) {
//   -------
  if (N>10) return (N>30)?printLSLT40(Q,wfd):(N>20)?printLSLT30(Q,wfd):printLSLT20(Q,wfd);
  char *s=outPointer;
  for (int r=0; r<N; ++r) {
    *s++='0'+Q[r][0]; for (int c=1; c<N; ++c) { *s++=' '; *s++='0'+Q[r][c]; } *s++='\n';
  }
  *s++='\n'; outPointer=s;
  if (++outSquares==numSquares) {
    if (write(wfd, outBuffer, outBytes)!=outBytes) { writeError=T; return F; }
    outPointer=outBuffer; outSquares=0;
  }
  return T;
} // printLS

bool outputLast(int wfd) {
//   ----------
  if (outSquares>0) {
    int lastBytes=outSquares*squareBytes;
    if (write(wfd, outBuffer, lastBytes)!=lastBytes) { writeError=T; return F; }
  }
  return T;
} // outputLast
//============================================= make =============================================

bool isNotDLS(int Q[maxN][maxN]) {
//   --------
  const bool odd=N&1; const int G=Nd2; int t=odd?B[Q[G][G]]:0;
  for (int i=0; i<G; ++i) t|=(B[Q[i][i]]|B[Q[M-i][M-i]]); if (t!=A) return T;
  t=odd?B[Q[G][G]]:0; for (int i=0; i<G; ++i) t|=(B[Q[i][M-i]]|B[Q[M-i][i]]);
  return t!=A;
} // isNotDLS

bool isNotSymRows(int Q[maxN][maxN]) {
//   ------------
  for (int r=1; r<N; ++r) for (int c=0; c<Nd2; ++c) if (Q[r][c]!=M-Q[r][M-c]) return T;
  return F;
} // isNotSymRows

bool isNotSymCols(int Q[maxN][maxN]) {
//   ------------
  for (int v=0; v<=N; ++v) opp[v]=-1;
  for (int c=0; c<N; ++c)
    if (opp[Q[0][c]]>=0) { if (opp[Q[0][c]]!=Q[M][c]) return T;
    } else { opp[Q[0][c]]=Q[M][c]; opp[Q[M][c]]=Q[0][c]; }
  for (int r=1; r<Nd2; ++r) for (int c=0; c<N; ++c) if (Q[r][c]!=opp[Q[M-r][c]]) return T; return F;
} // isNotSymCols

void initLS(const bool first) { // nfr
//   ------
  if (first) { for (int i=0; i<N; i++) { Q[0][i]=i; rU[i]=0; cU[i]=B[i]; } rU[0]=A; }
  else for (int i=0; i<N; i++) { rU[i]=A; cU[i]=A; }
} // initLS

int makeLS(int Q[maxN][maxN], const int v0, const bool first, const int howMany, int wfd) { // nfr
//  ------
  const bool out=(wfd!=-1); bool next=first; int count=0, r=1, c=0; Uint v=v0; initLS(first);
  if (first) { r=1; c=0; } else { r=M; c=M; }
  do {
    if (next) {
      if ((r==1)&(c==0)&(N>6)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (c==0) { if (r==1) break; --r; c=M; } else --c; next=F;
      } else { // check value used
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if ((r==1)&(c==0)&(N>6)&(v>v0)) break;
        if (v<=M) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v];
          if ((r==M)&(c==M)) { // end square
            if (isNotDLS(Q)) {
              ++count;
              if (out) { printLS(Q,wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }}
              if (count==howMany) {
                if (out&(count!=1)) { printf("last:\n"); printLSx(Q, stdout); }
                if (out&&!outputLast(wfd)) return 0; return count;
              } else { if ((count&0xffff)==0) printf("%d\n", count); next=F; }
            } else next=F;
          } else { ++c; if (c>M) { ++r; c=0; } v=0; }
        }
      }
    } else { v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; ++v; next=T; }
  } while (T);
  if (out&&!outputLast(wfd)) return 0; return count;
} // makeLS

void initDLS(const bool first) { // nfr
//   -------
  if (first) { for (int i=0; i<N; i++) { Q[0][i]=i; rU[i]=0; cU[i]=B[i]; } rU[0]=A; bU=1; fU=BM; }
  else { for (int i=0; i<N; i++) { rU[i]=A; cU[i]=A; } bU=A; fU=A; }
} // initDLS

int makeDLS(int Q[maxN][maxN], const Uint v0, const bool first, const int howMany, int wfd) { // nfr
//  -------
  const int H=Nd2; const bool out=(wfd!=-1); int r, c, count=0; Uint v=v0;
  enum { bf, ff, rf, bb, fb, rb} next; bool doBreak=F; initDLS(first);
  if (first) { r=1; next=bf; } else { r=M; c=L; next=rb; }
  do {
    switch (next) {
    case bf:
      if ((r==1)&((v>M)|((N>6)&(v>v0)))) { doBreak=T; break; }
      if (v>M) { --r; next=bb; }
      else {
        while (v<=M) { if (!((bU&B[v])|(cU[r]&B[v])|((v==M)&(r==(M-r))))) break; ++v; }
        if (v<=M) {
          Q[r][r]=v; bU|=B[v]; rU[r]=B[v]; cU[r]|=B[v];
          if (r==M) { r=1; c=L; if (odd) fU=BM|B[Q[H][H]]; next=ff; } else ++r; v=0;
        }
      }
      break;
    case ff:
      if (v>M) { if (r==1) { r=M; next=bb; } else { --r; if (odd&(r==H)) --r; c=M-r; next=fb; }}
      else {
        while (v<=M) { if (!((fU&B[v])|(rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<=M) {
          Q[r][c]=v; fU|=B[v]; rU[r]|=B[v]; cU[c]|=B[v];
          if (r==M) { r=1; next=rf; } else { ++r; if (odd&(r==H)) ++r; c=M-r; } v=0;
        }
      }
      break;
    case rf:
      if (v>M) {
        if ((r==1)&(c==0)) { r=M; next=fb; }
        else {
          if ((c==0)|((r==M)&(c==1))) { --r; c=M; }
          else { --c; if ((r==c)|(r==(M-c))) --c; if ((r==c)|(r==(M-c))) --c; } next=rb;
        }
      } else {
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<=M) {
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v];
          if ((r==M)&(c==L)) { // end square
            ++count;
            if (out) { printLS(Q,wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }}
            if (count==howMany) {
              if (out) {
                if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
                if (!outputLast(wfd)) return 0;
              }
              return count;
            } else { if ((count&0xffff)==0) printf("%d\n", count); next=rb; }
          } else {
            ++c; if ((r==c)|(r==(M-c))) ++c; if ((r==c)|(r==(M-c))) ++c;
            if (c>M) { ++r; c=(r==M)?1:0; } v=0;
          }
        }
      }
      break;
    case bb:
      v=Q[r][r]; bU^=B[v]; rU[r]=0; cU[r]^=B[v]; ++v; next=bf; break;
    case fb:
      v=Q[r][c]; fU^=B[v]; rU[r]^=B[v]; cU[c]^=B[v]; ++v; next=ff; break;
    case rb:
      v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; ++v; next=rf; break;
    default: printf("\aProgram error: bad case %d in makeDLS\n", next); return 0;
    }
    if (doBreak) break;
  } while (T);
  if (out&&!outputLast(wfd)) return 0; return count;
} // makeDLS

void permuteToNFR(int Q[maxN][maxN], int O[maxN][maxN]) { // natural order first row
//   ------------
  for (int C=0; C<N; ++C) { O[0][C]=C; U[Q[0][C]]=C; }
  for (int r=1; r<N; ++r) for (int c=0; c<N; ++c) O[r][c]=U[Q[r][c]];
} // permuteToNFR

void reverseRowsRightHalf(int X[maxN][maxN]) {
//    -------------------
  for (int r=0; r < N; ++r) for (int c=Nd2; c < N3d4; ++c) {
    int t=X[r][c]; X[r][c]=X[r][N3m2d2-c]; X[r][N3m2d2-c]=t;
  }
} // reverseRowsRightHalf

void  reverseColumnsBottomHalf(int X[maxN][maxN]) {
//    ------------------------
  for (int c=0; c < N; ++c) for (int r=Nd2; r < N3d4; ++r) {
    int t=X[r][c]; X[r][c]=X[N3m2d2-r][c]; X[N3m2d2-r][c]=t;
  }
} // reverseColumnsBottomHalf

void XformA_D(int Q[maxN][maxN], int O[maxN][maxN]) {
//   --------
  for (int r=0; r < N; ++r) for (int c=0; c < N; ++c) O[r][c]=Q[r][c];
  reverseColumnsBottomHalf(O); reverseRowsRightHalf(O);
} // XformA_D

void initAssoc(int Q[maxN][maxN], const bool first) { // nbd
//   ---------
  if (first) { for (int r=0; r<N; r++) { Q[r][r]=r; rU[r]=B[r]; cU[r]=B[r]; } bU=A; fU=odd?B[Nd2]:0; }
  else { for (int i=0; i<N; i++) { rU[i]=A; cU[i]=A; } bU=A; fU=A; }
} // initAssoc

int makeAssoc(int Q[maxN][maxN], const int v0, const bool nfr, const bool first,
//  ---------
              const bool wpls, const int howMany, const int wfd) { // nbd
  const bool out=(wfd!=-1), outO=nfr|wpls; bool next=first; int count=0, r, c, v, t, ta;
  initAssoc(Q, first); if (first) { r=0; c=1; v=v0; } else { r=L; c=M; }
  do {
    if (next) {
      if ((N>6)&(r==0)&(c==1)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (r==(c-1)) { if (r==0) break; --r; c=M; } else --c; next=F;
      } else { // check value used
        if (r==(M-c)) while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t)|(fU&t))) break; ++v; }
        else while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t))) break; ++v; }
        if ((N>6)&(r==0)&(c==1)&(v>v0)) break;
        if (v<=M) { // good, use, go
          Q[r][c]=v; t=B[v]; ta=B[M-v]; rU[r]|=t; cU[c]|=t;
          rU[M-r]|=ta; cU[M-c]|=ta; if (r==(M-c)) fU|=(t|ta);
          if (r==L) { // end square
            for (int R=0; R<M; ++R) for (int C=R+1; C<N; ++C) Q[M-R][M-C]=M-Q[R][C];
            if (nfr) permuteToNFR(Q, O); if (wpls) XformA_D(Q,O);
            if (out) printLS(outO?O:Q,wfd); next=F;
            if (out&((++count)==1)) { printf("First:\n"); printLSx(outO?O:Q, stdout); }
            if (count==howMany) {
              if (out) {
                if (howMany!=1) { printf("Last:\n"); printLSx(outO?O:Q, stdout); }
                if (!outputLast(wfd)) return 0;
              }
              return count;
            }
            if ((count&0xfff)==0) printf("%d\n", count);
          } else { ++c; if (c>M) { ++r; c=r+1; } v=0; }
        }
      }
    } else {
      v=Q[r][c]; t=B[v]; ta=B[M-v]; rU[r]^=t; cU[c]^=t; if (r==(M-c)) fU^=(t|ta);
      rU[M-r]^=ta; cU[M-c]^=ta; ++v; next=T;
    }
  } while (T);
  if (out&&!outputLast(wfd)) return 0; return count;
} // makeAssoc

int makeNearAssoc(int Q[maxN][maxN], const int v0, const bool nfr,
//  -------------
              const int howMany, const int wfd) { // nbd
  bool next=T; const int G=Nd2, G_=G-1; int count=0, r=0, c=1, v=v0, t, ta; initAssoc(Q,T);
  do {
    if (next) {
      if ((r==0)&(c==1)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (r==(c-1)) { if (r==0) break; --r; c=M; } else --c; next=F;
      } else { // check value used
        if ((c==M)&((r==G_)|(r==G))) {
          while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t)|(rU[r]&B[M-v]))) break; ++v; }
        } else if (r==G) {
          while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t)|(rU[G_]&B[M-v]))) break; ++v; }
        } else {
          if (r==(M-c)) while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t)|(fU&t))) break; ++v; }
          else while (v<=M) { t=B[v]; if (!((rU[r]&t)|(cU[c]&t))) break; ++v; }
        }
        if ((r==0)&(c==1)&(v>v0)) break;
        if (v<=M) { // good, use, go
          Q[r][c]=v; t=B[v]; ta=B[M-v]; rU[r]|=t; cU[c]|=t; if (r==(M-c)) fU|=(t|ta);
          if ((c==M)&((r==G_)|(r==G))) rU[r]|=ta; else rU[M-r]|=ta; cU[M-c]|=ta;
          if (r==L) { // end square
            for (int R=0; R<M; ++R) for (int C=R+1; C<N; ++C) Q[M-R][M-C]=M-Q[R][C];
            t=Q[G_][0]; Q[G_][0]=Q[G][0]; Q[G][0]=t;
            if (nfr) permuteToNFR(Q, O); printLS(nfr?O:Q,wfd); next=F;
            if (++count==1) { printf("First:\n"); printLSx(nfr?O:Q, stdout); }
            if (count==howMany) {
              if (howMany!=1) { printf("Last:\n"); printLSx(nfr?O:Q, stdout); }
              if (!outputLast(wfd)) return 0; return count;
            }
            if ((count&0xfff)==0) printf("%d\n", count);
          } else { ++c; if (c>M) { ++r; c=r+1; } v=0; }
        }
      }
    } else {
      v=Q[r][c]; t=B[v]; ta=B[M-v]; rU[r]^=t; cU[c]^=t; if (r==(M-c)) fU^=(t|ta);
      if ((c==M)&((r==G_)|(r==G))) rU[r]^=ta; else rU[M-r]^=ta; cU[M-c]^=ta;
      ++v; next=T;
    }
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeNearAssoc

int makeSymLSrows(int Q[maxN][maxN], const int v0,
//  -------------
                  const int howMany, int count, const int wfd) { // nfr
  const int G=Nd2, G_=G-1; bool next=T; int r=1, c=0, v=v0, vs; initLS(T);
  do {
    if (next) {
      if ((N>6)&(r==1)&(c==0)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (c==0) { if (r==1) break; --r; c=G_; } else --c; next=F;
      } else { // check value used
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<=M) { // good, use, go
          Q[r][c]=v; vs=M-v; rU[r]|=B[v]; cU[c]|=B[v]; rU[r]|=B[vs];
          if ((r==M)&(c==G_)) { // end square
            for (int i=1; i<N; ++i) for (int j=0; j<G; ++j) Q[i][M-j]=M-Q[i][j];
            if (isNotDLS(Q)&&isNotSymCols(Q)) {
              if (!printLS(Q, wfd)) break;
              if ((++count)==1) { printf("First:\n"); printLSx(Q, stdout); }
              if (count==howMany) {
                if (howMany!=1) { printf("Last:\n"); printLSx(Q, stdout); } return count;
              }
              if ((count&0xffff)==0) printf("%d\n", count);
            }
            next=F;
          } else { ++c; if (c>G_) { ++r; c=0; } v=0; }
        }
      }
    } else {
      v=Q[r][c]; vs=M-v; rU[r]^=B[v]; cU[c]^=B[v]; rU[r]^=B[vs]; ++v; next=T;
    }
  } while (T);
  return count;
} // makeSymLSrows

int makeSymLScols(int Q[maxN][maxN], const int v0,
//  -------------
                  const int howMany, int count, const int wfd) { // nfr
  const int G=Nd2, G_=G-1; int r=M, c=0, v=v0; bool doBreak=F, cSym[maxN];
  enum { rowf, rowMf, rowb, rowMb, rgo, rMgo, out } next=rowMf;
  for (int i=0; i<N; ++i) S[i]=-1; for (int i=0; i<N; ++i) cSym[i]=F; initLS(T);
  do {
    switch (next) {
    case rowf:
      if (v>M) { // back up 
        if (c==0) { if (r==1) { r=M; c=M; next=rowMb; } else { --r; c=M; next=rowb; }}
        else { --c; next=rowb; }
      } else { // check v used
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; } if (v<=M) next=rgo;
      } break;
    case rowMf: // r==M
      { int t=S[c];
      if (t>=0) { if (cU[c]&B[t]) { --c; next=rowMb; } else { v=t; cSym[c]=T; next=rMgo; }}
      else {
        if (v>M) { /* back up */ if (c==0) { doBreak=T; break; } else { --c; next=rowMb; }}
        else { // check v used
           while (v<=M) { if (!((v==c)|(rU[r]&B[v]))) break; ++v; }
          if (v<=M) {
            if ((N>6)&(c==0)&(v>v0)) { doBreak=T; break; } if (S[v]>=0) ++v; else next=rMgo;
          }
        }
      }} break;
    case rowb:
      v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; cU[c]^=B[S[v]]; ++v; next=rowf; break;
    case rowMb:
      v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; if (cSym[c]) { cSym[c]=F; --c; }
      else { S[v]=-1; S[c]=-1; ++v; next=rowMf; } break;
    case rgo:
      Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; cU[c]|=B[S[v]]; ++c; v=0;
      if (c==N) { if (r==G_) next=out; else { ++r; c=0; next=rowf; }} else next=rowf; break;
    case rMgo:
      Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; if (!cSym[c]) { S[v]=c; S[c]=v; } ++c; v=0;
      if (c==N) { r=1; c=0; next=rowf; } else next=rowMf; break;
    default: // case out
      for (int i=G; i<M; ++i) for (int j=0; j<N; ++j) Q[i][j]=S[Q[M-i][j]];
      if (isNotDLS(Q)&&isNotSymRows(Q)) {
        if (!printLS(Q, wfd)) { doBreak=T; break; }
        if ((++count)==1) { printf("First:\n"); printLSx(Q, stdout); }
        if (count==howMany) { if (howMany!=1) { printf("Last:\n"); printLSx(Q, stdout); } return count; }
        if ((count&0xffff)==0) printf("%d\n", count);
      }
      r=G_, c=M; next=rowb; break;
    }
    if (doBreak) break;
  } while (T);
  return count;
} // makeSymLScols

int makeSymLS(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  ---------
  int count=0;
  if (random_(2)) {
    count=makeSymLSrows(Q, v0, howMany, count, wfd);
    if (count!=howMany) count=makeSymLScols(Q, v0, howMany, count, wfd);
  } else {
     count=makeSymLScols(Q, v0, howMany, count, wfd);
     if (count!=howMany) count=makeSymLSrows(Q, v0, howMany, count, wfd);
  }
  if (!outputLast(wfd)) return 0; return count;
} // makeSymLS

void initDSymLS(int Q[maxN][maxN]) { // nfr
//   ----------
  for (int i=0; i<N; ++i) { rU[i]=0; cU[i]=0; } for (int c=0; c<Nd2; ++c) { Q[0][c]=c; cU[c]=B[c]; }
} // initDSymDLS

int makeDSymLS(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  ----------
  if (N==2) return makeLS(Q,v0,T,howMany,wfd);
  const int G=Nd2, G_=G-1; int count=0, r=M, c=0, v=v0, vs=0, t=0; bool doBreak=F, cSym[maxN/2];
  enum { rowf, rowMf, rowb, rowMb, rgo, rMgo, out } next=rowMf;
  for (int i=0; i<N; ++i) S[i]=-1; for (int i=0; i<G; ++i) cSym[i]=F; initDSymLS(Q);
  do {
    switch (next) {
    case rowf:
      if (v>M) { // back up
        if (c==0) { if (r==1) { r=M; c=G_; next=rowMb; } else { --r; c=G_; next=rowb; }}
        else { --c; next=rowb; }
      } else { // check v used
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; } if (v<=M) next=rgo;
      }
      break;
    case rowMf: // r==M
      t=S[c];
      if (t>=0) { if (cU[c]&B[t]) { --c; next=rowMb; } else { v=t; cSym[c]=T; next=rMgo; }}
      else {
        if (v>M) { /* back up */ if (c==0) { doBreak=T; break; } else { --c; next=rowMb; }}
        else { // check v used
          while (v<=M) { if (!((v==c)|(rU[r]&B[v]))) break; ++v; }
          if (v<=M) { if ((N>6)&(c==0)&(v>v0)) { doBreak=T; break; } if (S[v]>=0) ++v; else next=rMgo; }
        }
      }
      break;
    case rowb:
      v=Q[r][c]; t=S[v]; rU[r]^=B[v]; cU[c]^=B[v]; cU[c]^=B[t]; rU[r]^=B[M-v]; ++v; next=rowf;
      break;
    case rowMb:
      v=Q[r][c]; vs=M-v; rU[r]^=B[v]; cU[c]^=B[v]; rU[r]^=B[vs];
      if (cSym[c]) { cSym[c]=F; --c; } else { S[v]=-1; S[c]=-1; S[vs]=-1; S[M-c]=-1; ++v; next=rowMf; }
      break;
    case rgo:
      vs=M-v; Q[r][c]=v; t=S[v]; rU[r]|=B[v]; cU[c]|=B[v]; cU[c]|=B[t]; rU[r]|=B[vs]; ++c; v=0;
      if (c==G) { if (r==G_) next=out; else { ++r; c=0; next=rowf; }} else next=rowf;
      break;
    case rMgo:
      vs=M-v; Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; rU[r]|=B[vs];
      if (!cSym[c]) { S[v]=c; S[c]=v; S[vs]=M-c; S[M-c]=vs; } ++c; v=0;
      if (c==G) { r=1; c=0; v=0; next=rowf; } else next=rowMf;
      break;
    default: // case out
      for (int i=G; i<M; ++i) for (int j=0; j<G; ++j) Q[i][j]=S[Q[M-i][j]];
      for (int i=0; i<N; ++i) for (int j=0; j<G; ++j) Q[i][M-j]=M-Q[i][j];
      if (isNotDLS(Q)) {
        if (!printLS(Q, wfd)) { doBreak=T; break; }
        if ((++count)==1) { printf("First:\n"); printLSx(Q, stdout); }
        if (count==howMany) {
          if (howMany!=1) { printf("Last:\n"); printLSx(Q, stdout); }
          if (!outputLast(wfd)) return 0; return count;
        }
        if ((count&0xffff)==0) printf("%d\n", count);
      }
      r=G_, c=G_; next=rowb;
      break;
    }
    if (doBreak) break;
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeDSymLS

int makeSymDLSrows(int Q[maxN][maxN], const int v0, bool first,
//  --------------
                   const int howMany, int count, const int wfd) { // nfr
  const int G=Nd2, G_=G-1; const bool out=(wfd!=-1); bool next=first;
  int r, c, v, vs; if (first) { r=1; c=0; v=v0; } else { r=M; c=G_; } initDLS(first);
  do {
    if (next) {
      if ((N>6)&(r==1)&(c==0)&(v>v0)) break;
      if (v>M) { /* value too big, back up */ if (c==0) { if (r==1) break; --r; c=G_; } else --c; next=F; }
      else { // check value used
        if (r==c) while (v<=M) { if (!((rU[r]&B[v])||(cU[c]&B[v])||(bU&B[v]))) break; ++v; }
        else if (r==(M-c)) while (v<=M) { if (!((rU[r]&B[v])||(cU[c]&B[v])||(bU&B[M-v]))) break; ++v; }
        else while (v<=M) { if (!((rU[r]&B[v])||(cU[c]&B[v]))) break; ++v; }
        if (v<=M) { // good, use, go
          Q[r][c]=v; vs=M-v; rU[r]|=B[v]; cU[c]|=B[v]; rU[r]|=B[vs];
          if (r==c) bU|=B[v]; else if (r==(M-c)) bU|=B[vs];
          if ((r==M)&(c==G_)) { // end square
            for (int i=1; i<N; ++i) for (int j=0; j<G; ++j) Q[i][M-j]=M-Q[i][j];
            if (isNotSymCols(Q)) {
              ++count;
              if (out) {
                if (!printLS(Q, wfd)) break; if (count==1) { printf("First:\n"); printLSx(Q, stdout); }
              }
              if (count==howMany) {
                if (out&(howMany!=1)) { printf("Last:\n"); printLSx(Q, stdout); } return count;
              }
              if ((count&0xffff)==0) printf("%d\n", count);
            }
            next=F;
          } else { ++c; if (c==G) { ++r; c=0; } v=0; }
        }
      }
    } else {
      v=Q[r][c]; vs=M-v; rU[r]^=B[v]; cU[c]^=B[v]; rU[r]^=B[vs];
      if (r==c) bU^= B[v]; else if (r==(M-c)) bU^=B[vs]; ++v; next=T;
    }
  } while (T);
  return count;
} // makeSymDLSrows

int makeSymDLScols(int Q[maxN][maxN], const int v0, bool first,
//  --------------
                   const int howMany, int count, const int wfd) { // nfr
  const int G=Nd2, G_=G-1; int r, c, v, t; const bool qout=(wfd!=-1); bool doBreak=F, cSym[maxN];
  if (first) { r=M; c=0; v=v0; for (int i=0; i<N; ++i) { S[i]=-1; cSym[i]=F; }}
  else { r=G_; c=M; for (int i=0; i<N; ++i) { t=Q[M][i]; S[i]=t; cSym[i]=(t<i); }}
  enum { rowf, rowMf, rowb, rowMb, rgo, rMgo, out } next=first?rowMf:rowb; initDLS(first);
  do {
    switch (next) {
    case rowf:
      if (v>M) { // back up
        if (c==0) { if (r==1) { r=M; c=M; next=rowMb; } else { --r; c=M; next=rowb; }}
        else { --c; next=rowb; }
      } else { // check v used
        if (r==c)  while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[v])|(fU&B[S[v]]))) break; ++v; }
        else if (r==(M-c)) while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[S[v]])|(fU&B[v]))) break; ++v; }
        else  while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<=M) next=rgo;
      }
      break;
    case rowMf: // r==M
      t=S[c];
      if (t>=0) { if (cU[c]&B[t]) { --c; next=rowMb; } else { v=t; cSym[c]=T; next=rMgo; }}
      else {
        if (v>M) { /* back up */ if (c==0) { doBreak=T; break; } else { --c; next=rowMb; }
        } else { // check v used
          if ((c==0)|(c==M)) { while (v<=M) { if (!((v==0)|(v==M)|(rU[r]&B[v]))) break; ++v; }}
          else while (v<=M) { if (!((v==c)|(rU[r]&B[v]))) break; ++v; }
          if (v<=M) { if ((N>6)&(c==0)&(v>v0)) { doBreak=T; break; } if (S[v]>=0) ++v; else next=rMgo; }
        }
      }
      break;
    case rowb:
      v=Q[r][c]; t=S[v]; rU[r]^=B[v]; cU[c]^=B[v]; cU[c]^=B[t];
      if (r==c) { bU^=B[v]; fU^=B[t]; } else if (r==(M-c)) { bU^=B[t]; fU^=B[v]; } ++v; next=rowf;
      break;
    case rowMb:
      v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; if (c==0) fU^=B[v]; else if (c==M) bU^=B[v];
      if (cSym[c]) { cSym[c]=F; --c; } else { S[v]=-1; S[c]=-1; ++v; next=rowMf; }
      break;
    case rgo:
      Q[r][c]=v; t=S[v]; rU[r]|=B[v]; cU[c]|=B[v]; cU[c]|=B[t];
      if (r==c) { bU|=B[v]; fU|=B[t]; } else if (r==(M-c)) { bU|=B[t]; fU|=B[v]; } ++c; v=0;
      if (c==N) { if (r==G_) next=out; else { ++r; c=0; next=rowf; }} else next=rowf;
      break;
    case rMgo:
      Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; if (c==0) fU|=B[v]; else if (c==M) bU|=B[v];
      if (!cSym[c]) { S[v]=c; S[c]=v; } ++c; v=0;
      if (c==N) { r=1; c=0; v=0; next=rowf; } else next=rowMf;
      break;
    default: // case out
      for (int i=G; i<M; ++i) for (int j=0; j<N; ++j) Q[i][j]=S[Q[M-i][j]];
      if (isNotSymRows(Q)) {
        if (qout) {
          if (!printLS(Q, wfd)) { doBreak=T; break; }
          if (count==0) { printf("First:\n\n"); printLSx(Q, stdout); }
        }
        if (++count==howMany) {
          if (qout&(howMany!=1)) { printf("Last:\n"); printLSx(Q, stdout); } doBreak=T; break;
        }
        if ((count&0xffff)==0) printf("%d\n", count);
      }
      c=M; next=rowb;
      break;
    }
    if (doBreak) break;
  } while (T);
  return count;
} // makeSymDLScols

int makeSymDLS(int Q[maxN][maxN], const int v0, bool first, const int howMany, const int wfd) { // nfr
//  ----------
  int count=0; const bool out=(wfd!=-1);
  if (out) {
    if (random_(2)) {
      count=makeSymDLSrows(Q, v0, first, howMany, count, wfd);
      if (count!=howMany) count=makeSymDLScols(Q, v0, first, howMany, count, wfd);
    } else {
      count=makeSymDLScols(Q, v0, first, howMany, count, wfd);
      if (count!=howMany) count=makeSymDLSrows(Q, v0, first, howMany, count, wfd);
    }
    if (!outputLast(wfd)) return 0;
  } else {
    if (first) {
      if (random_(2)) count=makeSymDLSrows(Q, v0, first, howMany, count, wfd);
      else count=makeSymDLScols(Q, v0, first, howMany, count, wfd);
    } else {
      if (isNotSymRows(Q)) count=makeSymDLScols(Q, v0, first, howMany, count, wfd);
      else count=makeSymDLSrows(Q, v0, first, howMany, count, wfd);
    }
  }
  return count;
} // makeSymDLS

void initDSymDLS(int Q[maxN][maxN]) { // nfr
//   ---------
  for (int i=0; i<N; ++i) { rU[i]=0; cU[i]=0; }
  for (int c=0; c<Nd2; ++c) { Q[0][c]=c; cU[c]=B[c]; } bU=1; fU=BM;
} // initDSymDLS

int makeDSymDLS(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  -----------
  const int G=Nd2, G_=G-1; int count=0, r=M, c=0, v=v0, vs=0, t=0; bool doBreak=F, cSym[maxN/2];
  enum { rowf, rowMf, rowb, rowMb, rgo, rMgo, out } next=rowMf;
  for (int i=0; i<N; ++i) S[i]=-1; for (int i=0; i<G; ++i) cSym[i]=F; initDSymDLS(Q);
  do {
    switch (next) {
    case rowf:
      if (v>M) { // back up
        if (c==0) { if (r==1) { r=M; c=G_; next=rowMb; } else { --r; c=G_; next=rowb; }}
        else { --c; next=rowb; }
      } else { // check v used
        if (r==c) while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[v])|((M-S[v])==v))) break; ++v; }
        else while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; } if (v<=M) next=rgo;
      }
      break;
    case rowMf: // r==M
      t=S[c];
      if (t>=0) { if (cU[c]&B[t]) { --c; next=rowMb; } else { v=t; cSym[c]=T; next=rMgo; }}
      else {
        if (v>M) { /* back up */ if (c==0) { doBreak=T; break; } else { --c; next=rowMb; }}
        else { // check v used
          if (c==0) { if (v==0) ++v; } else while (v<=M) { if (!((v==c)|(rU[r]&B[v]))) break; ++v; }
          if (((c==0)&(v<M))|(v<=M)) {
            if ((N>6)&(c==0)&(v>v0)) { doBreak=T; break; } if (S[v]>=0) ++v; else next=rMgo;
          }
        }
      }
      break;
    case rowb:
      v=Q[r][c]; t=S[v]; rU[r]^=B[v]; cU[c]^=B[v]; cU[c]^=B[t]; rU[r]^=B[M-v];
      if (r==c) { bU^=B[v]; bU^=B[M-t]; }; ++v; next=rowf;
      break;
    case rowMb:
      v=Q[r][c]; vs=M-v; rU[r]^=B[v]; cU[c]^=B[v]; rU[r]^=B[vs]; if (c==0) bU^=B[vs];
      if (cSym[c]) { cSym[c]=F; --c; } else { S[v]=-1; S[c]=-1; S[vs]=-1; S[M-c]=-1; ++v; next=rowMf; }
      break;
    case rgo:
      vs=M-v; Q[r][c]=v; t=S[v]; rU[r]|=B[v]; cU[c]|=B[v]; cU[c]|=B[t]; rU[r]|=B[vs];
      if (r==c) { bU|=B[v]; bU|=B[M-t]; } ++c; v=0;
      if (c==G) { if (r==G_) next=out; else { ++r; c=0; next=rowf; }} else next=rowf;
      break;
    case rMgo:
      vs=M-v; Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; rU[r]|=B[vs]; if (c==0) bU|=B[vs];
      if (!cSym[c]) { S[v]=c; S[c]=v; S[vs]=M-c; S[M-c]=vs; } ++c; v=0;
      if (c==G) { r=1; c=0; v=0; next=rowf; } else next=rowMf;
      break;
    default: // case out
      for (int i=G; i<M; ++i) for (int j=0; j<G; ++j) Q[i][j]=S[Q[M-i][j]];
      for (int i=0; i<N; ++i) for (int j=0; j<G; ++j) Q[i][M-j]=M-Q[i][j];
      if (!printLS(Q, wfd)) { doBreak=T; break; }
      if (count==0) { printf("First DSymDLS:\n\n"); printLSx(Q, stdout); }
      ++count; if (count==howMany) { doBreak=T; break; }
      if ((count&0xffff)==0) printf("%d\n", count); r=G_, c=G_; next=rowb;
      break;
    }
    if (doBreak) break;
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeDSymDLS

void initCSym(int Q[maxN][maxN]) {
//   -----------
  for (int i=0; i<N; i++) { Q[0][i]=i; rU[i]=0; cU[i]=B[i]; } bU=B[0]; fU=B[M]; rU[0]=A;
} // initCSym

bool getCsym(const bool first, const int v0) {
//   -------
  bool u[maxN], next=first; const int G=Nd2; int c=first?0:M, v=v0;
  for (int i=0; i<N; ++i) u[i]=!first; u[U[M]]=F;
  do {
    if (next) {
      if (v>M) next=F;
      else {
        while (u[v]|(v==c)) { ++v; if (v>M) break; }
        if (v<=M) { U[c]=v; u[v]=T;
          if (c==M) {
            bool ok=T;
            for (int i=0; i<N; ++i) { if (((M-U[i])!=i)&(U[M-U[i]]!=(M-i))) { ok=F; break; }}
            if (ok) {
              for (int i=0; i<N; ++i) { Q[M][i]=U[i]; S[i]=U[M-i]; }
              int selfi=-1;
              if (odd) { int self=0;
                for (int i=0; i<N; ++i) { if (S[i]==i) { ++self; if (self>1) { ok=F; break; } selfi=i; }}
              }
              if (ok) {
                cU[0]=B[0]|B[U[0]]; cU[M]=B[M]|B[U[M]];
                if (odd) { Q[G][G]=selfi; cU[G]=B[G]|B[selfi]|B[U[G]]; rU[G]=B[selfi]; } return T;
              }
            }
            u[U[c]]=F; next=F;
          } else { ++c; v=0; }
        } else next=F;
      }
    } else {
      if (c==0) return F; --c; if ((N>6)&(c==0)) return F; u[U[c]]=F; v=U[c]+1; next=T;
    }
  } while (T);
  return F;
} // getCsym

bool BDandMrowLS() {
//   -----------
  bool next=T; const int G=Nd2, G_=G-1; int c=G_, v=Q[c][c]+1;
  do {
    do {
      if (next) {
        if (v>M) { v=Q[c][c]; Q[c][c]=-1; next=F; } 
        else if (v==c) { ++v; } else { Q[c][c]=v; if (c==G_) break; ++c; v=0; }
      } else { --c; if (c==0) return F; v=Q[c][c]; Q[c][c]=-1; ++v; next=T; }
    } while (T);
    bool ok=T;
    for (int i=1; i<=G_; ++i) {
      int t=S[Q[i][i]];
      if (t==(M-i)) { ok=F; for (int j=i+1; j<=G_; ++j) Q[j][j]=-1; c=i; v=Q[i][i]; break; }
      Q[M-i][M-i]=t;
    } // BD
    if (ok) {  
      for (int i=1; i<M; ++i) { if (odd&(i==G)) continue; int t=Q[i][i]; cU[i]=B[i]|B[U[i]];
        if (cU[i]&B[t]) { ok=F; break; } cU[i]|=B[t]; rU[i]=B[t]; 
      }
      if (ok) return T;
    }
    ++v;
  } while (T);
  return F;
} // BDandMrowLS

bool CSymBDandMrowLS(const int v0, const bool first) {
//   ---------------
  const int G_=Nd2-1; if (!first) if (BDandMrowLS()) return T;
  do {
    if (!getCsym(first, v0)) return F;
    for (int c=1; c<G_; ++c) Q[c][c]=0; Q[G_][G_]=-1; if (BDandMrowLS()) return T;
  } while (T);
  return F;
} // CSymBDandMrowLS

bool CSymBDandMrowDLS(const int v1, const bool first) {
//   ----------------
  const int G=Nd2; int count=0, c, v; bool next=T;
  if (first) { U[0]=0; U[1]=v1; c=2; bU|=B[v1]; for (int c=2; c<N; ++c) U[c]=-1; v=1; }
  else { c=M; v=Q[M][M]; bU^=B[v]; U[M]=-1; ++v; }
  do {
    do {
      if (next) {
        if (v>M) { v=U[c]; if (v>=0) { bU^=B[v]; U[c]=-1; } next=F; }
        else if ((v==c)|(odd&(c==G)&(v==M))|(bU&B[v])) { ++v; } else { U[c]=v; bU|=B[v];
       if (c==M) break; ++c; v=0; }
      } else { --c; v=U[c]; if ((c==1)&((v==M)|(N>6))) return F; bU^=B[v]; U[c]=-1;  ++v; next=T; }
    } while (T);
    bool ok=T;
    for (int c=0; c<N; ++c) { S[U[c]]=U[M-c]; cU[c]=B[c]|B[U[c]]; }
    for (int c=0; c<M; ++c) if (cU[c]&B[S[M-c]]) { ok=F; break; }
    if (ok) { for (int c=0; c<N; ++c) {
      Q[c][c]=U[c]; Q[M][c]=S[M-c]; rU[c]=B[U[c]]; cU[c]|=B[Q[M][c]]; }
      fU=B[M]|B[S[M]]; if (odd) fU|=B[U[G]]; return T;
    }
    ++v;
  } while (T);
  return F;
} // CSymBDandMrowDLS

int makeCSym(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) {
//  --------
  if (N<4) return makeLS(Q, v0, T, -1, wfd);
  const int G=Nd2; bool doBreak=F, first=T, ok=F; int count=0, r=M, c=0, v=v0, t=0;
  enum { bDia, rowf, rowb, rgo, out } next=bDia; for (int i=0; i<N; ++i) S[i]=-1; initCSym(Q);
  do {
    switch (next) {
    case bDia: // \ diagonal
      ok=CSymBDandMrowLS(v0, first); first=F; if (!ok) { doBreak=T; break; } r=1; c=2; v=0; next=rowf;
      break;
    case rowf:
      if (v>M) { // back up
        if (c==(r+1)) { if (r==1) next=bDia; else { --r; c=M; next=rowb; }} else { --c; next=rowb; }
      } else { // check v used
        while (v<=M) { t=S[v]; if (!((rU[r]&B[v])|(odd&(r==G)&(rU[G]&B[t]))|
                                    (cU[c]&B[v])|(odd&(c==G)&(cU[G]&B[t])))) break; ++v; }
        if (v<=M) { if (odd&(v==t)&((r==G)^(c==G))) ++v; else next=rgo; }
      }
      break;
    case rowb:
      v=Q[r][c]; t=S[v]; rU[r]^=B[v]; cU[c]^=B[v]; rU[M-r]^=B[t]; cU[M-c]^=B[t]; ++v; next=rowf;
      break;
    case rgo:
      Q[r][c]=v; t=S[v]; rU[r]|=B[v]; cU[c]|=B[v]; rU[M-r]|=B[t]; cU[M-c]|=B[t];
      if (c==M) { if (r==L) next=out; else { ++r; c=r+1; next=rowf; }} else { ++c; next=rowf; } v=0;
      break;
    default: // case out
      for (int i=0; i<M; ++i) for (int j=i+1; j<N; ++j) Q[M-i][M-j]=S[Q[i][j]];
      if (isNotDLS(Q)) {
        if (!printLS(Q, wfd)) { doBreak=T; break; }
        if (count==0) { printf("First:\n\n"); printLSx(Q, stdout); } 
        if (++count==howMany) {
          if (howMany!=1) { printf("Last:\n\n"); printLSx(Q, stdout); } doBreak=T; break;
        }
        if ((count&0xffff)==0) printf("%d\n", count);
      }
      next=rowb;
      break;
    }
    if (doBreak) break;
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeCSym

int getOrt(int Q[maxN][maxN], int R[maxN][maxN], int count, const int howMany, int wfd) {
//  ------  // Find disjoint transversals.
  int c=0, j[maxH]; bool next=T; t_tr r, *q; j[0]=0;
  do {
    if (next) {
      if (c==0) { q=&tr[0][j[0]]; r=*q; c=1; j[1]=0; }
      else {
        q=&tr[c][j[c]]; bool ok=T; for (int i=1; i<N; ++i) if (r.c[i]&q->c[i]) { ok=F; break; }
        if (ok) {
          if (c==M) {
            for (int k=0; k<N; ++k) {
              t_tr *p=&tr[k][j[k]]; R[0][k]=k; for (int l=1; l<N; ++l) R[l][P(p->c[l])]=k;
            }
            printLS(Q, wfd); printLS(R, wfd);
            if ((count)==1) { printf("First:\n"); printLSx(Q, stdout); printLSx(R, stdout); }
            if (++count==howMany) {
              if (howMany!=1) { printf("Last:\n"); printLSx(Q, stdout); printLSx(R, stdout); } return count;
            }
            if ((count&0xfff)==0) printf("%d\n", count); ++j[c]; next=F;
          } else { for (int i=1; i<N; ++i) r.c[i]|=q->c[i]; /* good, go next c */ ++c; j[c]=0; }
        } else { ++j[c]; next=F; }
      }
    } else {
      if (j[c]==ltr[c]) { // all tried for this c
        if (c==0) break; --c; q=&tr[c][j[c]];
        for (int i=1; i<N; ++i) r.c[i]^=q->c[i]; ++j[c]; // back out prev c and advance it
      } else next=T;
    }
  } while (T);
  return count;
} // getOrt

void getTransLS(const int t) { // search for transversals starting at col t
//   ----------
  int count=0, c[maxH], r=1, vU=B[Q[0][t]], cU=B[t]; ltr[t]=0; bool next=T; c[0]=t; c[1]=(t==0)?1:0;
  do {
    if (next) {
      if (r==M) { int x=A^cU; for (int i=0; i<N; ++i) if ((1<<i)==x) { c[r]=i; break; }
        if (vU&B[Q[r][c[r]]]) { if (r==1) break; --r; next=F;
        } else {
          if (count==trn) { /* printf("Transversals overflow.\n"); */ ltr[t]=count; return; }
          t_tr *p=&tr[t][count++]; for (int i=1; i<N; ++i) p->c[i]=B[c[i]]; --r; next=F;
        }
      } else {
        while ((cU&B[c[r]])|(vU&B[Q[r][c[r]]])) { ++c[r]; if (c[r]==N) break; }
        if (c[r]<N) { cU|=B[c[r]]; vU|=B[Q[r][c[r]]]; ++r; c[r]=0; } else { if (r==1) break; --r; next=F; }
      }
    } else { // back
      cU^=B[c[r]]; vU^=B[Q[r][c[r]]]; ++c[r]; if (c[r]==N) { if (r==1) break; --r; } else next=T;
    }
  } while (T);
  ltr[t]=count;
} // getTransLS

void getTransDLS(int Q[maxN][maxN], const int t) { // search for transversals starting at col t
//   -----------
  int count=0, c[maxH], r=1, vU=B[Q[0][t]], cU=B[t]; ltr[t]=0;
  bool next=T, bU=(t==0), fU=(t==M); c[0]=t; c[1]=(t==0)?1:0;
  do {
    if (next) {
      if (r==M) { int x=A^cU; for (int i=0; i<N; ++i) if ((1<<i)==x) { c[r]=i; break; }
        if ((vU&B[Q[r][c[r]]])|(bU&(c[r]==r))|(fU&(c[r]==(M-r)))) { --r; next=F; }
        else {
          if (count==trn) { printf("Transversals overflow.\n"); ltr[t]=count; return; }
          t_tr *p=&tr[t][count++]; for (int i=1; i<N; ++i) p->c[i]=B[c[i]]; --r; next=F;
        }
      } else {
        while ((cU&B[c[r]])|(vU&B[Q[r][c[r]]])) { ++c[r]; if (c[r]==N) break; }
        if (c[r]<N) {
          bool ok=T; if (c[r]==r) { if (bU) ok=F; else bU=T;}
          if (ok&(c[r]==(M-r))) { if (fU) { ok=F; if (c[r]==r) bU=F; } else if (ok) fU=T; }
          if (ok) { cU|=B[c[r]]; vU|=B[Q[r][c[r]]];  ++r; c[r]=0; }
          else { ++c[r]; if (c[r]==N) { if (r==1) break; --r; next=F; }}
        } else { if (r==1) break; --r; next=F; }
      }
    } else { // back
      cU^=B[c[r]]; vU^=B[Q[r][c[r]]]; if (c[r]==r) { bU=F; } if (c[r]==(M-r)) fU=F;
      ++c[r]; if (c[r]==N) { if (r==1) break; --r; } else next=T;
    }
  } while (T);
  ltr[t]=count;
} // getTransDLS

int makeOLS(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  -------
  int count=0; 
  if (makeLS(Q, v0, T, 1, -1)==1) do {
    bool ok=T; for (int t=0; t<N; ++t) { getTransLS(t); if (ltr[t]==0) { ok=F; break; } }
    if (ok) { count=getOrt(Q, R, count, howMany, wfd); if (count==howMany) break; }
    if (makeLS(Q, v0, F, 1, -1)==0) break; 
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeOLS

int makeODLSa(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  ---------
  int count=0;
  if (makeDLS(Q, v0, T, 1, -1)==1) do {
    bool ok=T; for (int t=0; t<N; ++t) { getTransDLS(Q,t); if (ltr[t]==0) { ok=F; break; } }
    if (ok) { count=getOrt(Q,R,count, howMany, wfd); if (count==howMany) break; }
    if (makeDLS(Q, v0, F, 1, -1)==0) break; 
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeODLSa

int makeODLSb(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  ---------
  int count=0;
  if (makeAssoc(Q, v0, T, T, F, random_(10)+1, -1)>0) do {
    bool ok=T; for (int t=0; t<N; ++t) { getTransDLS(O,t); if (ltr[t]==0) { ok=F; break; } }
    if (ok) { count=getOrt(O,R,count, howMany, wfd); if (count==howMany) break; }
    if (makeAssoc(Q, v0, T, F, F, random_(10)+1, -1)==0) break; 
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeODLSb

int makeODLSc(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  ---------
  int count=0;
  if (makeSymDLS(Q, v0, T, (N>8)?random_(10)+1:1, -1)>0) do {
    bool ok=T; for (int t=0; t<N; ++t) { getTransDLS(Q,t); if (ltr[t]==0) { ok=F; break; }}
    if (ok) { count=getOrt(Q,R,count, howMany, wfd); if (count==howMany) break; }
    if (makeSymDLS(Q, v0, F, (N>8)?random_(10)+1:1, -1)==0) break; 
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeODLSc

int makeODLS(int Q[maxN][maxN], const int v0, const int howMany, const int wfd) { // nfr
//  --------
  return (N<8) ? makeODLSa(Q, v0, howMany, wfd) :
         (N&1) ? makeODLSb(Q, v0, howMany, wfd) : makeODLSc(Q, v0, howMany, wfd);
} // makeODLS

void initSOLS() {
//   --------
  for (int i=0; i<N; ++i) { for (int j=0; j<N; ++j) Q[i][j]=-1; rU[i]=0; cU[i]=0; qrU[i]=0; }
  for (int c=0; c<N; ++c) { Q[0][c]=c; cU[c]|=B[c]; } rU[0]=A; bU=1; qrU[0]=1;
} // initSOLS

int makeSOLS(int Q[maxN][maxN], const int v0, const int howMany, int wfd) { // nfr
//  --------
  time_t startTime=time(NULL); enum { row, col, bd } next=bd;
  const int H=(N&1)?Nd2+1:Nd2; int count=0, r=1, c=1, v=v0, vq, t; initSOLS();
  do {
    if (next==row) {
      if (v>M) {
        if (c==(r+1)) { c=r-1; r=M; } else { t=r; r=c; c=t; --r; }
        vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
        if (r==M) { v=Q[c][r]; cU[r]^=B[v]; --r; 
          vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; } cU[c]^=B[v]; ++v; next=col;
      } else {
        if (c==M) {
          v=P(A^rU[r]);
          if (cU[M]&B[v]) {
            if (c==(r+1)) { c=r-1; r=M; } else { t=r; r=c; c=t; --r; }
            vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
            if (r==M) { v=Q[c][r]; cU[r]^=B[v]; --r;
              vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
            }
            cU[c]^=B[v]; ++v; next=col;
          } else { Q[r][c]=v; cU[c]|=B[v]; next=col; t=r; r=c; c=t; v=0; }
        } else {
          while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
          if (v<N) { Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; next=col; t=r; r=c; c=t; v=0; }
        }
      }
    } else if (next==col) { 
      if (v>M) {
        if (c==0) {
          if (r==1) { r=M, c=M;
            v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[v]; --r; --c;
            v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[v]; bU^=B[v]; ++v; next=bd;
          } else { --r; vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
                   cU[c]^=B[v]; ++v; next=col;
          }
        } else { t=r; r=c; c=t; v=Q[r][c]; cU[c]^=B[v]; rU[r]^=B[v]; ++v; next=row; }
      } else {
        vq=Q[c][r];
        if (r==M) {
          v=P(A^cU[c]);
          if ((rU[r]&B[v])|(qrU[v]&B[vq])) {
            if (c==0) {
               --r; vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; cU[c]^=B[v]; ++v; next=col;
            } else {
              t=r; r=c; c=t; v=Q[r][c]; cU[c]^=B[v];
              if (c==(r+1)) { c=r-1; r=M; } else { t=r; r=c; c=t; --r; }
              vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
              if (r==M) { v=Q[c][r]; cU[r]^=B[v]; --r; 
                vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; }
              cU[c]^=B[v]; ++v; next=col;
            }
          } else {
            Q[r][c]=v; rU[r]|=B[v]; qrU[v]|=B[vq]; qrU[vq]|=B[v];
            if (c==L) {
              bool ok; t=BM; for (int i=1; i<N; ++i) t|=B[Q[i][M-i]]; ok=(t!=A); // no SODLS
              if (ok) {
                ++count; printLS(Q, wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
                if (count==howMany) {
                  if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
                  if (!outputLast(wfd)) return 0; return count;
                } else if ((N>8)|((count&0xf)==0)) {
                  printf("%d%s", count, N>9?"":"\n"); if (N>9) printElapsedTime(startTime, ' ');
                } 
              }
              rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; v=Q[L][M]; cU[M]^=B[v]; --c;
              vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; v=Q[c][r]; cU[r]^=B[v]; --r;
              vq=Q[c][r]; v=Q[r][c]; rU[r]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; cU[c]^=B[v]; ++v; next=col;
            } else { t=r; r=c; c=t; ++r; c=r+1; v=0; next=row; }
          }
        } else {
          while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(qrU[v]&B[vq]))) break; ++v; }
          if (v<N) {
            Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; qrU[v]|=B[vq]; qrU[vq]|=B[v];
            if (c==0) ++r; else { t=r; r=c; c=t; ++c; next=row; } v=0;
          }
        }
      }
   } else { // next==bd:
      if ((r==1)&((v>M)|((N>6)&(v>v0)))) break;
      if (v>M) {  --r; --c; v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[v]; bU^=B[v]; ++v; }
      else { 
        if (r==M) {
          v=P(A^bU);
          if (v==M) { r=L; c=L; v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[v]; bU^=B[v]; ++v; }
          else { Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; qrU[v]|=B[v]; next=col; r=1; c=0; v=0; }
        } else {
          while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[v]))) break; ++v; }
          if (v<N) { Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; bU|=B[v]; qrU[v]|=B[v]; ++r; ++c; v=0; }
        }
      }
    }    
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeSOLS

void initSODLS(bool nfr) { // nfr natural first row; otherwise natural \diagonal
//   ---------
  for (int i=0; i<N; ++i) { for (int j=0; j<N; ++j) Q[i][j]=-1; rU[i]=0; cU[i]=0; qrU[i]=0; }
  bU=0; fU=0;
  if (nfr) {
    for (int c=0; c<N; ++c) { Q[0][c]=c; rU[0]|=B[c]; cU[c]|=B[c]; } bU=1; fU=BM; qrU[0]=1;
  } else {
    for (int r=0; r<N; ++r) { Q[r][r]=r; rU[r]|=B[r]; cU[r]|=B[r]; bU|=B[r]; qrU[r]|=B[r]; }
    if (odd) fU|=B[Nd2];
  }
} // initSODLS

// todo last of row, col; also for SODLSeven, etc
int SODLSodd(int Q[maxN][maxN], const int v0, const int howMany, int wfd) { // nfr
//  --------
  time_t startTime=time(NULL); enum { row, col, bd, fd } next=bd;
  const int G=Nd2, R0=1; int count=0, R=R0, C=R, v=v0; initSODLS(T);
  do {
    int r=R, c=C, ov=Q[r][c]; Q[r][c]=-1;
    if (next==row) {
      if (ov>=0) { rU[r]^=B[ov]; cU[c]^=B[ov]; } // clear old
      if (v>M) { // value too big
        if (C==(M-R)+1) if (R!=G) --C;
        if (C==(R+1)) { /* start of row, all tried for this row */ next=col; C=R-1; R=(C==0)?L:M; }
        else { /* backup in col */ next=col; int t=R; R=C; C=t; --R; }
        v=Q[R][C]+1;
      } else { // check value used
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<N) { // good, use, go to col
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; next=col; int t=R; R=C; C=t; v=0;
        }
      }
    } else if (next==col) {
      int vq=Q[c][r];
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; qrU[ov]^=B[vq]; qrU[vq]^=B[ov]; }
      if (v>M) { // value too big, back to row with incr value
        if (C==0) { /* backup in col */ if (R==R0) { R=M, C=0; next=fd; } else --R; v=Q[R][C]+1; }
        else { next=row; int t=R; R=C; C=t; v=Q[R][C]+1; }
      } else { // check value used
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(qrU[v]&B[vq]))) break; ++v; }
        if (v<N) { // good, use, go to row, or advance on col 0
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; qrU[v]|=B[vq]; qrU[vq]|=B[v]; next=row; int t=R; R=C; C=t;
          if ((C==M)|((R==0)&(C==L))) { // col limit
            if (R==L) { // row limit
              ++count; printLS(Q, wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
              if (count==howMany) {
                if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
                if (!outputLast(wfd)) return 0; return count;
              } else if ((N>7)|((count&0xf)==0)) {
                printf("%d%s", count, N>9?"":"\n"); if (N>9) printElapsedTime(startTime, ' ');
              } 
              // clear and go back to row with incr value
              rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v]; Q[C][R]=-1; v=Q[R][C]+1;
            } else { /* to start of next row */ ++R; C=R+1; if (C==(M-R)) ++C; v=0; }
          } else { // advance in col 0 or go to row, next col
            if (R==0) { R=C+1; C=0; next=col; } else { ++C; if (C==(M-R)) ++C; } v=0;
          }
        }
      }
    } else if (next==fd) {
      if (ov>=0) { // clear old
        rU[r]^=B[ov]; cU[c]^=B[ov]; fU^=B[ov];
        if (R>G) { int ovr=Q[c][r]; qrU[ov]^=B[ovr]; qrU[ovr]^=B[ov]; }
      }
      if (v>M) { // all possible tried
        if (r==R0) { next=bd; R=M; C=R; } // start of fd, back to bd
        else { --R; ++C; if (R==G) { --R; ++C; } } /* go back on fd */ v=Q[R][C]+1;
      } else { // used ?
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(fU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fU|=B[v];
          if (R>G) { int vr=Q[c][r]; qrU[v]|=B[vr]; qrU[vr]|=B[v]; }
          if (R==M) { next=col; R=1; C=0; }  // fd complete, go to col
          else { ++R, --C; if (R==G) { ++R, --C; } } /* advance on fd */ v=0;
        }
      }
    } else { //if (next==bd) {
      if (R==R0) { if ((v>M)|((N>5)&(v>v0))) break; } // make only for start value for N==7+
      if (ov>=0) { // clear old
        rU[r]^=B[ov]; cU[c]^=B[ov]; bU^=B[ov]; qrU[ov]^=B[ov]; if (odd&(r==G)) fU^=B[ov];
      }
      if (v>M) { /* all possible tried */ C=--R; v=Q[R][C]+1; } // go back on bd
      else { // used ?
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[v])|((r==G)&(v==M)))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; bU|=B[v]; qrU[v]|=B[v]; if (r==G) fU|=B[v];
          if (R==M) { /* bd complete, go to start of fd */ next=fd; R=R0; C=M-R; v=0;
          } else { C=++R; v=0; } // go forward on bd
        }
      }
    }
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // SODLSodd

int SODLSeven(int Q[maxN][maxN], const int v0, const int howMany, int wfd) { // nfr
//  ---------
  time_t startTime=time(NULL); enum { row, col, col0, bd, fdt, fdb } next=bd;
  const int R0=1; int count=0, R=R0, C=R, v=v0, vq=0; initSODLS(T); bool breakDo=F;
  do {
    int r=R, c=C, ov=Q[r][c]; Q[r][c]=-1;
    switch (next) {
    case row:
      if (ov>=0) { rU[r]^=B[ov]; cU[c]^=B[ov]; } // clear old
      if (v>M) { // value too big
        if (C==(N-R)) --C;
        if (C==(R+1)) { // start of row, all tried for this row
          if (R==1) { next=col0; C=0; R=L; } else { next=col; C=R-1; R=M; }
        } else { /* back up in col */ next=col; int t=R; R=C-1; C=t; }
        v=Q[R][C]+1;
      } else { /* check value used */ while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if (v<N) { // good, use, go to col
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; next=col; int t=R; R=C; C=t; v=0;
        }
      }
      break;
    case col:
      vq=Q[c][r];
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; qrU[ov]^=B[vq]; qrU[vq]^=B[ov]; }
      if (v>M) { /* value too big, back to row with incr value */ next=row; int t=R; R=C; C=t; v=Q[R][C]+1; }
      else { // check value used
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(qrU[v]&B[vq]))) break; ++v; }
        if (v<N) { // good, use, go to row
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; qrU[v]|=B[vq]; qrU[vq]|=B[v]; next=row; int t=R; R=C; C=t;
          if (C==M) { // col limit
            if (R==L) { // row limit
              ++count; printLS(Q, wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
              if (count==howMany) {
                if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
                if (!outputLast(wfd)) return 0; return count;
              } else if ((N>8)|((count&0xf)==0)) {
                printf("%d%s", count, N>9?"":"\n"); if (N>9) printElapsedTime(startTime, ' ');
              } 
              // clear and go back to row with incr value
              rU[r]^=B[v]; cU[c]^=B[v]; qrU[v]^=B[vq]; qrU[vq]^=B[v];
              Q[C][R]=-1; v=Q[R][C]+1;
            } else { /* to start of next row */ ++R; C=R+1; if (C==(M-R)) ++C; v=0; }
          } else { /* go to row, next col */ ++C; if (C==(M-R)) ++C; v=0; }
        }
      }
      break;
    case col0:
      vq=Q[c][r];
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; qrU[ov]^=B[vq]; qrU[vq]^=B[ov]; }
      if (v>M) { // value too big, back to row with incr value
        if (R==R0) { R=Nd2; C=M-R; next=fdb; } else --R; /* back up in col */ v=Q[R][C]+1;
      } else { // check value used
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(qrU[v]&B[vq]))) break; ++v; }
        if (v<N) { // good, use, advance on col
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; qrU[v]|=B[vq]; qrU[vq]|=B[v];
          // col limit, to start of row 1, else advance in col
          if (R==L) { R=1; C=(N==4)?3:2; next=row; } else ++R; v=0;
        }
      }
      break;
    case fdt:
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; fU^=B[ov]; }
      if (v>M) { // all possible tried
        int t=R; R=C; C=t; ++R; --C; v=Q[R][C]+1; next=fdb; // back up with incr value
      } else { // used ?
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(fU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fU|=B[v]; int t=R; R=C; C=t; v=0; next=fdb;
        }
      }
      break;
   case fdb:
      if (ov>=0) { // clear old
        rU[r]^=B[ov]; cU[c]^=B[ov]; fU^=B[ov]; int ovr=Q[c][r]; qrU[ov]^=B[ovr]; qrU[ovr]^=B[ov];
      }
      if (v>M) { // all possible tried
        if (C==0) { C=M; next=bd; }
        else { int t=R; R=C; C=t; next=fdt; } /* back up with incr value */ v=Q[R][C]+1;
      } else { // used ?
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(fU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fU|=B[v]; int vr=Q[c][r]; qrU[v]|=B[vr]; qrU[vr]|=B[v];
          if (R==Nd2) { next=col0; R=R0; C=0; } // fd complete, go col 0
          else { int t=R; R=C; C=t; ++R; --C; next=fdt; } /* advance on fd */ v=0;
        }
      }
      break;
    default: // bd
      if (R==R0) { if ((v>M)|((N>6)&(v>v0))) { breakDo=T; break; }} // make only for start value for N==8+
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; bU^=B[ov]; qrU[ov]^=B[ov]; }
      if (v>M) { /* all possible tried */  C=--R; v=Q[R][C]+1; } // go back on bd 
      else { // used ?
        while (v<N) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(bU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; bU|=B[v]; qrU[v]|=B[v];
          if (R==M) { /* bd complete, go to start of fd */ next=fdb; C=0; v=0;
          } else { C=++R; v=0; } // go forward on bd
        }
      }
      break;
    } 
    if (breakDo) break;
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // SODLSeven

int makeSODLS(int Q[maxN][maxN], const int v0, const int howMany, int wfd) {
// ----------
  return odd?SODLSodd(Q, v0, howMany, wfd):SODLSeven(Q, v0, howMany, wfd);           
} // makeSODLS

void initNFC() { // nfr
//   -------
 for (int i=0; i<N; i++) { Q[0][i]=i; Q[i][0]=i; rU[i]=B[i]; cU[i]=B[i]; } rU[0]=A; cU[0]=A;
} // initNFC

int makeNFC(int Q[maxN][maxN], const int v0, const int howMany, int wfd) { // nfr
//  -------
  bool next=T; int count=0, r=1, c=1; Uint v=v0; initNFC();
  do {
    if (next) {
      if ((r==1)&(c==1)&(N>6)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (c==1) { if (r==1) break; --r; c=M; } else --c; next=F;
      } else { // check value used
        while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        if ((r==1)&(c==1)&(N>6)&(v>v0)) break;
        if (v<=M) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v];
          if ((r==M)&(c==M)) { // end square
            ++count; printLS(Q,wfd);
            if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
            if (count==howMany) {
              if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
              if (!outputLast(wfd)) return 0; return count;
            } else { if ((count&0xffff)==0) printf("%d\n", count); next=F; }
          } else { ++c; if (c>M) { ++r; c=1; } v=0; }
        }
      }
    } else { v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; ++v; next=T; }
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeNFC

int makeSelfT(int Q[maxN][maxN], const int v0, const int howMany, int wfd) { // nfr
//  ---------
  bool next=T; int count=0, r=1, c=1; Uint v=v0; initNFC();
  do {
    if (next) {
      if ((r==1)&(c==1)&(N>6)&(v>v0)) break;
      if (v>M) { // value too big, back up
        if (c==r) { if (r==1) break; --r; c=M; } else --c; next=F;
      } else { // check value used
        if (r==c) while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v]))) break; ++v; }
        else while (v<=M) { if (!((rU[r]&B[v])|(cU[c]&B[v])|(rU[c]&B[v])|(cU[r]&B[v]))) break; ++v; }

        if ((r==1)&(c==1)&(N>6)&(v>v0)) break;
        if (v<=M) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; if (r!=c) { rU[c]|=B[v]; cU[r]|=B[v]; }

          if ((r==M)&(c==M)) { // end square
            for (int i=1; i<M; ++i) for (int j=i+1; j<N; ++j) Q[j][i]=Q[i][j];
            ++count; printLS(Q,wfd);
            if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
            if (count==howMany) {
              if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
              if (!outputLast(wfd)) return 0; return count;
            } else { if ((count&0xffff)==0) printf("%d\n", count); next=F; }
          } else { ++c; if (c>M) { ++r; c=r; } v=0; }
        }
      }
    } else { v=Q[r][c]; rU[r]^=B[v]; cU[c]^=B[v]; if (r!=c) { rU[c]^=B[v]; cU[r]^=B[v]; } ++v; next=T; }
  } while (T);
  if (!outputLast(wfd)) return 0; return count;
} // makeSelfT

int makePLS(int Q[maxN][maxN], const int howMany, int wfd) {
//  -------
  int count=0; for (int c=0; c<N; ++c) Q[0][c]=c;
  for (int i=2; i<M; ++i) {
    if ((N==25)&&((i%5)!=2)&&((i%5)!=3)) continue;
    for (int r=1; r<N; ++r) for (int c=0; c<N; ++c) Q[r][c]=Q[r-1][(c+i)%N];
    ++count; printLS(Q,wfd); if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
    if (count==howMany) {
      if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
      if (!outputLast(wfd)) return 0; return count;
    }
  }
  Q[0][0]=0; for (int c=1; c<N; ++c) Q[0][c]=N-c;
  for (int i=2; i<M; ++i) {
    if ((N==25)&&((i%5)!=2)&&((i%5)!=3)) continue;
    for (int r=1; r<N; ++r) for (int c=0; c<N; ++c) Q[r][c]=Q[r-1][(c+i)%N]; ++count; printLS(Q,wfd);
    if (count==howMany) {
      if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
      if (!outputLast(wfd)) return 0; return count;
    }
  }
  if (!outputLast(wfd)) return 0; return count;
} // makePLS

void getLdiags(int Q[maxN][maxN], int O[maxN][maxN]) {
//   ---------
  for (int i=0; i < N; ++i) {
    for (int r=0, c=i; r < N; ++r, ++c) { int cModn=c < N ? c : c - N; O[i][r]=Q[r][cModn]; }
  }
} // getLdiags

int makeWPLS9(int Q[maxN][maxN], const int howMany, int wfd) {
//  ---------
  int count=0, loop2=2; int t[9]; for (int c=0; c<N; ++c) t[c]=c;
  while (loop2--) {
    int loop=36, abc=1, x;
    while (loop--) {
      for (int c=0; c<N; ++c) Q[0][c]=t[c];
      for (int r=1; r<3; ++r) for (int c=0; c<9; ++c) Q[r][c]=Q[r-1][(c+6)%9];
      for (int c=0; c<9; ++c) Q[3][c]=Q[0][c%3==2?c-2:c+1];
      for (int r=4; r<6; ++r) for (int c=0; c<9; ++c) Q[r][c]=Q[r-1][(c+6)%9];
      for (int c=0; c<9; ++c) Q[6][c]=Q[3][c%3==2?c-2:c+1];
      for (int r=7; r<9; ++r) for (int c=0; c<9; ++c) Q[r][c]=Q[r-1][(c+6)%9];
      ++count; printLS(Q,wfd);
      if (count==1) { printf("first:\n"); printLSx(Q, stdout); }
      if (count==howMany) {
        if (count!=1) { printf("last:\n"); printLSx(Q, stdout); }
        if (!outputLast(wfd)) return 0; return count;
      }
      if ((loop==6)|(loop==18)|(loop==30)) {
        for (int c=3; c<6; ++c) { x=t[c]; t[c]=t[c+3]; t[c+3]=x; } abc=1;
      } else if ((loop==12)|(loop==24)) {
        for (int c=0; c<3; ++c) { x=t[c]; t[c]=t[c+6]; t[c+6]=x; } abc=1;
      } else {
        if (abc) {
          x=t[1]; t[1]=t[2]; t[2]=x; x=t[4]; t[4]=t[5]; t[5]=x; x=t[7]; t[7]=t[8]; t[8]=x; abc=0;
        } else {
          x=t[0]; t[0]=t[2]; t[2]=x; x=t[3]; t[3]=t[5]; t[5]=x; x=t[6]; t[6]=t[8]; t[8]=x; abc=1;
        }
      }
    }
    x=0; for (int c=0; c<N; ++c) t[c]=(c%3)==0?x++:t[c-1]+3;
  }
  if (!outputLast(wfd)) return 0; return count;
} // makeWPLS9

int makeWPLS15(int Q[maxN][maxN], const int howMany, int wfd) {
//  ----------
  int count=0, t[]={ 7,14,0,  9,1,11,  6,13,2,  8,3,10,  5,4,12 };
  bool u[15]; for (int i=0; i<15; ++i) u[i]=F;
  for (int a=0; a<15; a+=3) { u[a]=T; for (int b=0; b<15; b+=3) if (!u[b]) { u[b]=T;
  for (int c=0; c<15; c+=3) if (!u[c]) { u[c]=T; for (int d=0; d<15; d+=3) if (!u[d]) { u[d]=T;
  for (int e=0; e<15; e+=3) if (!u[e]) {
    for (int z=0; z<3; ++z)  {
      Q[0][z]=t[a+z]; Q[0][z+3]=t[b+z]; Q[0][z+6]=t[c+z]; Q[0][z+9]=t[d+z]; Q[0][z+12]=t[e+z];
    }
    for (int r=1; r<3; ++r) for (int c=0; c<15; ++c) Q[r][c]=Q[r-1][c%3==2?c-2:c+1];
    for (int r=3; r<15; ++r) for (int c=0; c<15; ++c) Q[r][c]=Q[r-3][c];
    ++count; getLdiags(Q,O); printLS(O,wfd); if (count==1) { printf("first:\n"); printLSx(O, stdout); }
    if (count==howMany) {
      if (count!=1) { printf("last:\n"); printLSx(O, stdout); }
      if (!outputLast(wfd)) return 0; return count;
    }
  } u[d]=F; } u[c]=F; } u[b]=F; } u[a]=F; }
  if (!outputLast(wfd)) return 0; return count;
} // makeWPLS15

int makeWPLS21(int Q[maxN][maxN], const int howMany, int wfd) {
//  ----------
  int t[]={ 14,5,11, 0,17,13, 18,4,8, 1,19,10, 20,3,7, 2,16,12, 15,6,9 }, count=0;
  bool u[21]; for (int i=0; i<21; ++i) u[i]=F;
  for (int a=0; a<21; a+=3) { u[a]=T; for (int b=0; b<21; b+=3) if (!u[b]) { u[b]=T;
  for (int c=0; c<21; c+=3) if (!u[c]) { u[c]=T; for (int d=0; d<21; d+=3) if (!u[d]) { u[d]=T;
  for (int e=0; e<21; e+=3) if (!u[e]) { u[e]=T; for (int f=0; f<21; f+=3) if (!u[f]) { u[f]=T;
  for (int g=0; g<21; g+=3) if (!u[g]) {
    for (int z=0; z<3; ++z)  {
      Q[0][z]=t[a+z]; Q[0][z+3]=t[b+z]; Q[0][z+6]=t[c+z]; Q[0][z+9]=t[d+z];
      Q[0][z+12]=t[e+z]; Q[0][z+15]=t[f+z]; Q[0][z+18]=t[g+z];
    }
    for (int r=1; r<3; ++r) for (int c=0; c<21; ++c) Q[r][c]=Q[r-1][c%3==2?c-2:c+1];
    for (int r=3; r<21; ++r) for (int c=0; c<21; ++c) Q[r][c]=Q[r-3][c];
    ++count; getLdiags(Q,O); printLS(O,wfd);
    if (count==1) { printf("first:\n"); printLSx(O, stdout); }
    if (count==howMany) {
      if (count!=1) { printf("last:\n"); printLSx(O, stdout); }
      if (!outputLast(wfd)) return 0; return count;
    }
  } u[f]=F; } u[e]=F; } u[d]=F; } u[c]=F; } u[b]=F; } u[a]=F; }
  if (!outputLast(wfd)) return 0; return count;
} // makeWPLS21

int makeWPLS27(int Q[maxN][maxN], const int howMany, int wfd) {
//  ----------
  int t[]={ 0,23,16, 14,24,1, 4,17,18, 15,19,5, 20,13,6, 21,7,11, 8,9,22, 25,2,12, 10,3,26 };
  int count=0; bool u[27]; for (int i=0; i<27; ++i) u[i]=F;
  for (int a=0; a<27; a+=3) { u[a]=T; for (int b=0; b<27; b+=3) if (!u[b]) { u[b]=T;
  for (int c=0; c<27; c+=3) if (!u[c]) { u[c]=T; for (int d=0; d<27; d+=3) if (!u[d]) { u[d]=T;
  for (int e=0; e<27; e+=3) if (!u[e]) { u[e]=T; for (int f=0; f<27; f+=3) if (!u[f]) { u[f]=T;
  for (int g=0; g<27; g+=3) if (!u[g]) { u[g]=T; for (int h=0; h<27; h+=3) if (!u[h]) { u[h]=T;
  for (int i=0; i<27; i+=3) if (!u[i]) {
    for (int z=0; z<3; ++z)  {
      Q[0][z]=t[a+z]; Q[0][z+3]=t[b+z]; Q[0][z+6]=t[c+z]; Q[0][z+9]=t[d+z]; Q[0][z+12]=t[e+z];
      Q[0][z+15]=t[f+z]; Q[0][z+18]=t[g+z]; Q[0][z+21]=t[h+z]; Q[0][z+24]=t[i+z];
    }
    for (int r=1; r<3; ++r) for (int c=0; c<27; ++c) Q[r][c]=Q[r-1][c%3==2?c-2:c+1];
    for (int r=3; r<27; ++r) for (int c=0; c<27; ++c) Q[r][c]=Q[r-3][c];
    ++count; getLdiags(Q,O); printLS(O,wfd); if (count==1) { printf("first:\n"); printLSx(O, stdout); }
    if (count==howMany) {
      if (count!=1) { printf("last:\n"); printLSx(O, stdout); }
      if (!outputLast(wfd)) return 0; return count;
    }
  } u[h]=F; } u[g]=F; } u[f]=F; } u[e]=F; } u[d]=F;
  } u[c]=F; } u[b]=F; } u[a]=F; }
  if (!outputLast(wfd)) return 0; return count;
} // makeWPLS27

int makeWPLS(int Q[maxN][maxN], const int v0, const int howMany, int wfd) {
//  --------
  if (N&1) {
    switch(N) {
      case 9: return makeWPLS9(Q, howMany, wfd);
      case 15: return makeWPLS15(Q, howMany, wfd);
      case 21: return makeWPLS21(Q, howMany, wfd);
      case 27: return makeWPLS27(Q, howMany, wfd);
      default: printf("\aProgram error: makeWPLS N=%d\n", N); return 0;
    }
  }
  return makeAssoc(Q, v0, F, T, T, howMany, wfd);
} // makeWPLS

int makeOrder1(int Q[maxN][maxN], const bool ort, const int wfd) {
//  ----------
  Q[0][0]=0; if (!printLS(Q,wfd)) return 0; if (ort&&!printLS(Q,wfd)) return 0;
  if (!outputLast(wfd)) return 0; return 1;
} // makeOrder1

enum { unknown, ls, sls, dsls, csls, ols, sols, nfrnfc, stran,
                dls, sdls, dsdls, csdls, odls, sodls, assoc, pls, wpls, ncsdls, nassoc } kind;
const char *kindName[]= { "unknown", "LS", "SymLS", "DSymLS", "CSymLS", "OLS", "SOLS",
                          "NFR_NFC", "SelfTrans",
                          "DLS", "SymDLS", "DSymDLS", "CSymDLS",
                          "ODLS", "SODLS", "Assoc", "PLS", "WPLS", "NearCsymDLS", "NearAssoc" };
const int numKinds=nassoc+1, sMin[]={1,1,1,1,1,1,2,0,0,2,1,1,2,2,2,2,0,2,2,2};
int sMax[numKinds];

bool checkKind(const int kind) {
//   ---------
  if (N==1) return T;
  if ((N==6)&(kind!=ls)&(kind!=csls)&(kind!=sls)&(kind!=nfrnfc)&(kind!=stran)&
    (kind!=dsls)&(kind!=dls)&(kind!=sdls)) {
    printf("There are no order %d %s.\n", N, kindName[kind]); return F;
  }
  if ((N==3)&(kind!=ls)&(kind!=csls)&(kind!=ols)&(kind!=nfrnfc)&(kind!=stran)) {
    printf("There are no order %d %s\n", N, kindName[kind]); return F;
  }
  if ((N==2)&(kind!=ls)&(kind!=dsls)&(kind!=csls)&(kind!=nfrnfc)&(kind!=stran)) {
    printf("There are no order %d %s.\n", N, kindName[kind]); return F;
  }
  if ((N&1)&((kind==sls)|(kind==dsls)|(kind==sdls)|(kind==dsdls))) {
    printf("There are no odd order %s.\n", kindName[kind]); return F;
  }
  if (((N&3)==2)&((kind==pls)|(kind==wpls))) {
    printf("There are no singly even order %s.\n", kindName[kind]); return F;
  }
  return T;
} // checkKind

bool getKind(int *kind) {
//   -------
  printf("\nType of Latin square,\n"
         "  1 LS, 2 axial symmetric LS, 3 double axial symmetric LS, 4 center symmetric LS,\n"
         "  5 orthogonal LS, 6 self-orthogonal LS, 7 nfr nfc, 8 self-transpose,\n"
         "  9 DLS, 10 axial symmetric DLS, 11 double axial symmetric DLS, 12 center symmetric DLS,\n"
         " 13 orthogonal DLS, 14 self-orthogonal DLS, 15 associative, or 16 pandiagonal? ");
  int k=getInt(); 
  if ((k<=unknown)|(k>pls)) { *kind=unknown; printf("\a\nUnknown type: %d.\n", k); return F; }
  if ((N&3)==2) { if (k==assoc) k=nassoc; else if (k==csdls) k=ncsdls; }
  if ((k==pls)&(!((N%6==1)|(N%6==5)))) k=wpls; return checkKind(*kind=k);
} // getKind

bool dirEmpty;
int makeSquares() {
// ------------
  int count=0, kind=ls; for (int i=0; i<numKinds; ++i) sMax[i]=M; sMax[dsdls]=L;
  if (getKind(&kind)) {
    int wfd=openOutput(kindName[kind]);
    if (wfd!=-1) {
      if (N==1) count=makeOrder1(Q, (kind==ols)|(kind==odls), wfd);
      else {
        int howMany=-1, Min=sMin[kind], Max=sMax[kind], start=Min;
        if (N>6) {
          printf("\nHow many? "); howMany=getInt();
          if ((kind==pls)|((kind==wpls)&(N&1))) start=Min;
          else {
            if ((kind==nfrnfc)|(kind==stran)) printf("\nstart, (0 or 2 .. %d)? ", Max);
            else printf("\nstart, (%d .. %d)? ", Min, Max); start=getInt();
          }
        }
        if ((start>=Min)&(start<=Max)&!((start==1)&((kind==nfrnfc)|(kind==stran)))) {
          time_t startTime=time(NULL);
          switch (kind) {
            case ls:     count=makeLS(Q, start, T, howMany, wfd); break;
            case sls:    count=makeSymLS(Q, start, howMany, wfd); break;
            case dsls:   count=makeDSymLS(Q, start, howMany, wfd); break;
            case csls:   count=makeCSym(Q, start, howMany, wfd); break;
            case ols:    count=makeOLS(Q, start, howMany, wfd); break;
            case sols:   count=makeSOLS(Q, start, howMany, wfd); break;
            case nfrnfc: count=makeNFC(Q, start, howMany, wfd); break;
            case stran:  count=makeSelfT(Q, start, howMany, wfd); break;
            case dls:    count=makeDLS(Q, start, T, howMany, wfd); break;     
            case sdls:   count=makeSymDLS(Q, start, T, howMany, wfd); break;
            case dsdls:  count=makeDSymDLS(Q, start, howMany, wfd); break;
            case csdls:  count=makeAssoc(Q, start, T, T, F, howMany, wfd); break;
            case ncsdls: count=makeNearAssoc(Q, start, T, howMany, wfd); break;
            case odls:   count=makeODLS(Q, start, howMany, wfd); break;
            case sodls:  count=makeSODLS(Q, start, howMany, wfd); break;
            case assoc:  count=makeAssoc(Q, start, F, T, F, howMany, wfd); break;
            case nassoc: count=makeNearAssoc(Q, start, F, howMany, wfd); break;
            case pls:    count=makePLS(Q, howMany, wfd); break;
            case wpls:   count=makeWPLS(Q, start, howMany, wfd); break;
            default: break;
          }
          printElapsedTime(startTime, '\n');
          if (writeError) printf("\aOutput error.\n\n");
          else printf("Number of %s %d\n\n", kindName[kind], count);
        } else printf("\aError: Bad start %d\n", start);
      }
      close(wfd); if (count==0) remove(outputFile); else dirEmpty=F;
    }
  }
  return count;
} // makeSquares
//============================================== main =============================================

void outputLocalTime() {
//   --------------
  time_t startTime=time(NULL); struct tm *local=localtime(&startTime);
  if (local!=NULL) {
    char dateTime[100];
    size_t slen=strftime(dateTime, 100, "%A %Y-%m-%d %X %Z\n\0", local); printf("\n%s", dateTime);
  }
} // outputLocalTime

int main() {
//  ----
  outputLocalTime(); seed_rand(); bool ok=F, inputSize=T; dirEmpty=T;
  if (openDir("./LS")) do {
    if (inputSize) { printf("order? "); N=getInt(); } initGlobals();
    if ((N>0)&(N<=maxN)) {
      int count=0; outPointer=outBuffer; outSquares=0; count=makeSquares(); if (!writeError) ok=T;
    } else printf("\aError: order limited to 1..%d\n\n", maxN);
    printf("Continue? input Y or the square order for yes, N for no: ");
    if (getYorOrder(&N)) inputSize=(N==0); else break;
  } while (T);
  if (chdir("..")==0) if (dirEmpty) rmdir(dirName);
  printf("\nHit return to close the console.");
  while (T) if (getchar()=='\n') break; return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} // main