/*
 *  File:    SODLSs.cpp
 *  Author:  S Harry White
 *  Created: 2015-12-01
 *  Updated: 2021-07-15
 *    Re-named from SODLS.
 *  Updated 2022-01-27
 *    Remove tracing code from SSSODLSeven. Tidy code.
 *  Updated: 2023-01-27
 *    Change outputFile from bufSize to outSize.
*/

/*
 *  Uses backtracking to make SODLS, self-orthogonal diagonal Latin squares.
 *  Optionally makes SSSODLS, "strongly symmetric" SODLS for odd and doubly even orders.
 *
 *  Speed is improved for order 9 using techniques given in the 2017 paper:
 *
 *   ****************************************************************************
 *   *                                                                          *
 *   *   Fast Algorithm for Enumerating Diagonal Latin Squares of Small Order   *
 *   *                                 by                                       *
 *   *            Stepan Kochemazov, Eduard Vatutin, Oleg Zaikin                *
 *   *                                                                          *
 *   ****************************************************************************
 *
 */

#include "stdafx.h"
#include <conio.h>
#include <direct.h>
#include <errno.h>
#include <fcntl.h>
#include <io.h>
#include <share.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys\stat.h>
#include <time.h>
#include <Windows.h>

const bool F=false, T=true;
const int X=20,
          B[]={ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
                4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288 }, B10=1<<9, B10p1=B10+1;
int N,
    Nm1,   // N-1
    Nm2,   // N-2
    Nd2,   // N/2
    Nd2m1, // Nd2-1
    Nd2p1, // Nd2+1
    Q[X][X], rU[X], cU[X], qrU[B10p1], bdU, fdU, P[B10p1]; // Power of 2, the i of B[i]

void initGlobals() { Nm1=N-1; Nm2=N-2; Nd2=N/2; Nd2m1=Nd2-1; Nd2p1=Nd2+1; }
//=================================================== 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');
} // getY

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

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

bool getStart(const bool ssym, int *v) {
//   --------
  char buf[100];
  if (ssym) {
    char *s="First /diagonal value, (1";
    if (N==4) sprintf_s(buf, 100, "%s or 2)? ", s); else if (N==5) sprintf_s(buf, 100, "%s or 3)? ", s);
    else if (N&1) sprintf_s(buf, 100, "%s..%d or %d..%d)? ", s, Nd2m1, Nd2p1, Nm2);
    else sprintf_s(buf, 100, "%s..%d)? ", s, Nm2);
  } else {
    char *s="Second \\diagonal value, (2";
    if (N==4) sprintf_s(buf, 100, "%s or 3)? ", s); else sprintf_s(buf, 100, "%s..%d)? ", s, Nm1);
  }
  printf(buf); const int v0=getInt();
  const bool ok=ssym ? (v0>0)&&(v0<Nm1)&&!((N&1)&&(v0==Nd2)) : (v0>1)&&(v0<N);
  if (ok) *v=v0; else printf("\aError: Bad value %d.\n", v0); return ok;
} // getStart
//================================================== output =================================================

void printElapsedTime(time_t startTime, const char c) {
//   ---------------- 
  const 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

const int bufSize=1024, outSize=bufSize+50; char outputFile[outSize];
FILE *openOutputp(const bool ssym) {
//    -----------
  int sub=0; FILE *wfp=NULL; const int baseSize=bufSize+25; char baseName[baseSize], buf[outSize];
  sprintf_s(baseName, baseSize, "%sSODLS%d", ssym?"SS":"", N); sprintf_s(buf, outSize, "%s.txt", baseName);
  do {
    if (_access_s(buf, 00)==ENOENT) break; sprintf_s(buf, outSize, "%s_%d.txt", baseName, ++sub);
  } while (T);
  if (fopen_s(&wfp, buf, "w")==0) {
    printf(".. writing SODLS to file %s\n", buf); sprintf_s(outputFile, outSize, "%s", buf);
  } else {
    char msg[outSize+50]; sprintf_s(msg, outSize+50, "\a\nCan't open for write %s", buf); perror(msg);
  }
  return wfp;
} // openOutputp

int openOutputd() {
//  -----------
  int wfd=-1; int sub=0; const int baseSize=bufSize+25; char baseName[baseSize], buf[outSize];
  sprintf_s(baseName, baseSize, "SODLS%d", N); sprintf_s(buf, outSize, "%s.txt", baseName);
  do {
    if (_access_s(buf, 00)==ENOENT) break; sprintf_s(buf, outSize, "%s_%d.txt", baseName, ++sub);
  } while (T);

  if (_sopen_s(&wfd, buf, _O_CREAT|_O_WRONLY, _SH_DENYNO, _S_IWRITE)==0) {
    printf("\n... writing SODLS to file %s\n", buf); sprintf_s(outputFile, outSize, "%s", buf);
  } else {
    char msg[outSize+50]; sprintf_s(msg, outSize+50, "\a\nCan't open for write %s", buf); perror(msg);
  }
  return wfd;
} // openOutputd

bool printSODLSb(int s[X][X], const int n, FILE *wfp) {
//   -----------
  for (int i=0; i<n; i++) {
    if (!fprintf(wfp, "%2d", s[i][0])) return F;
    for (int j=1; j<n; j++) if (!fprintf(wfp, " %2d", s[i][j])) return F;
    if (fputc('\n', wfp)==EOF) return F;
  }
  const bool ok=fputc('\n', wfp)!=EOF; fflush(wfp); return ok;
} // printSODLSb

bool printSODLS(int s[X][X], const int n, FILE *wfp) {
//   ----------
  if (n>10) return printSODLSb(s, n, wfp);
  for (int i=0; i<n; i++) {
    if (!fprintf(wfp, "%d", s[i][0])) return F;
    for (int j=1; j<n; j++) if (!fprintf(wfp, " %d", s[i][j])) return F;
    if (fputc('\n', wfp)==EOF) return F;
  }
  const bool ok=fputc('\n', wfp)!=EOF; fflush(wfp); return ok;
} // printSODLS

const int squareBytes=163, numSquares=200000, outputSize=numSquares*squareBytes;
char outputBuffer[outputSize], *outPointer=NULL; int outSquares;
bool printSODLS9(int Q[X][X], const int 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; ++outSquares;
  if (outSquares>=numSquares) {
    if (_write(wfd, outputBuffer, outputSize)!=outputSize) return F; outPointer=outputBuffer; outSquares=0;
  }
  return T;
} // printSODLS9

bool outputLast(const int wfd) {
//   ----------
  if (outSquares>0) {
    const int outBytes=outSquares*squareBytes; if (_write(wfd, outputBuffer, outBytes)!=outBytes) return F;
  }
  return T;
} // outputLast
//======================================================= make =====================================================

void initSODLS(const 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; } bdU=0; fdU=0;
  if (nfr) {
    for (int c=0; c<N; ++c) { Q[0][c]=c; rU[0]|=B[c]; cU[c]|=B[c]; } bdU=1; fdU|=B[Nm1]; qrU[0]=1;
  } else {
    for (int r=0; r<N; ++r) { Q[r][r]=r; rU[r]|=B[r]; cU[r]|=B[r]; bdU|=B[r]; qrU[r]|=B[r]; }
    if (N&1) fdU|=B[Nd2];
  }
} // initSODLS

int SODLSodd(const int v0, FILE *wfp) { // nfr
//  --------
  time_t startTime=time(NULL); enum { row, col, bd, fd } next=bd;
  const int M=Nm1, L=M-1, U=Nd2, R0=1; int count=0, R=R0, C=R, v=v0; initSODLS(T);
  do {
    const 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==N) { // value too big
        if (C==(M-R)+1) if (R!=U) --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; const 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; const int t=R; R=C; C=t; v=0;
        }
      }
    } else if (next==col) {
      const 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==N) { // 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; const 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; const int t=R; R=C; C=t;
          if ((C==M)|((R==0)&(C==L))) { // col limit
            if (R==L) { // row limit
              if(!printSODLS(Q, N, wfp)) break; ++count;
              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]; fdU^=B[ov]; if (R>U) { const int ovr=Q[c][r]; qrU[ov]^=B[ovr]; qrU[ovr]^=B[ov]; }
      }
      if (v==N) { // all possible tried
        if (r==R0) { next=bd; R=M; C=R; } // start of fd, back to bd
        else { --R; ++C; if (R==U) { --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])|(fdU&B[v]))) break; ++v; }
        if (v<N) { /* good, use, go */ Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fdU|=B[v];
          if (R>U) { const 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==U) { ++R, --C; }} /* advance on fd */ v=0;
        }
      }
    } else { /* next==bd */ if ((R==R0)&(v>v0)) break;
      if (ov>=0) { // clear old
        rU[r]^=B[ov]; cU[c]^=B[ov]; bdU^=B[ov]; qrU[ov]^=B[ov]; if ((N&1)&(r==U)) fdU^=B[ov];
      }
      if (v==N) { /* 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])|(bdU&B[v])|((r==U)&(v==M)))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; bdU|=B[v]; qrU[v]|=B[v]; if (r==U) fdU|=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);
  return count;
} // SODLSodd

int SSSODLSodd(const int v0, FILE *wfp) { // nbd
//  ----------
  time_t startTime=time(NULL); enum { row, col, fd } next=fd;
  const int M=Nm1, L=M-1, U=Nd2m1, Ud=Nd2, Ur=U; int count=0, vq=v0, R=0, C=M; initSODLS(F);
  do {
    const int rq=R, cq=C, ovq=Q[rq][cq], ovr=M-ovq; Q[rq][cq]=-1;
    if (next==row) {
      const int rr=M-rq, cr=M-cq;
      if (ovq>=0) { /* not advanced, clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; rU[rr]^=B[ovr]; cU[cr]^=B[ovr]; }
      if (vq>M) { // value too big
        if (C==(R+1)) { // at start of row, all tried for this row
          if (R==0) { /* if top row, go back to fd middle */ R=U, C=M-U; next=fd; vq=Q[R][C]+1; }
          else { /* go back next outer col */ next=col; C=R-1; R=L-C; vq=Q[R][C]+1; }
        } else { /* backup in col */ next=col; const int t=R; R=C; C=t; vq=Q[--R][C]+1; }
      } else { /* check value used */ int vr=M-vq;
        while (vq<=M) { if (!((rU[rq]& B[vq])|(cU[cq]&B[vq])|(rU[rr]&B[vr])| (cU[cr]&B[vr]))) break; ++vq; --vr; }
        if (vq<=M) { /* good, use and advance to col */ Q[rq][cq]=vq; Q[rr][cr]=vr;
          rU[rq]|=B[vq]; cU[cq]|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr]; next=col; const int t=R; R=C; C=t; vq=0;
        }
      }
    } else if (next==col) {
      const int rr=M-rq, cr=M-cq; int vQ=Q[cq][rq], vR=Q[cr][rr];
      if (ovq>=0) { /* clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; rU[rr]^=B[ovr]; cU[cr]^=B[ovr];
        qrU[ovq]^=B[vQ]; qrU[vQ]^=B[ovq]; qrU[ovr]^=B[vR]; qrU[vR]^=B[ovr];
      }
      if (vq>M) { /* value too big, back to row with incr value */ next=row; const int t=R; R=C; C=t; vq=Q[R][C]+1;
      } else { /* check value used */ int vr=M-vq;
        while (vq<=M) {
          if (!((rU[rq]&B[vq])|(cU[cq]&B[vq])|(rU[rr]&B[vr])|(cU[cr]&B[vr])|(qrU[vq]&B[vQ]))) break; ++vq; --vr;
        }
        if (vq<=M) { /* good, use and go to row */ Q[rq][cq]=vq; Q[rr][cr]=vr; vQ=Q[cq][rq], vR=Q[cr][rr];
          rU[rq]|=B[vq]; cU[cq]|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr]; qrU[vq]|=B[vQ]; qrU[vQ]|=B[vq];
          qrU[vr]|=B[vR]; qrU[vR]|=B[vr]; next=row; const int t=R; R=C; C=t;
          if (C==(L-R)) { // col limit
            if (R==Ur) { // row limit
              if (!printSODLS(Q, N, wfp)) break; ++count;
              if ((N>11)|((count&0xf)==0)) {
                printf("%d%s", count, N>11 ? "" : "\n"); if (N>11) printElapsedTime(startTime, ' ');
              }
              // clear and go back to row with incr value
              rU[rq]^=B[vq]; cU[cq]^=B[vq]; rU[rr]^=B[vr]; cU[cr]^=B[vr]; qrU[vq]^=B[vQ]; qrU[vQ]^=B[vq];
              qrU[vr]^=B[vR]; qrU[vR]^=B[vr]; Q[C][R]=-1; vq=Q[R][C]+1;
            } else { ++R; C=R+1; vq=0; /* to start of next row */ }
          } else { ++C; vq=0; } // to row, next col
        }
      }
    } else { /* next==fd */ if ((R==0)&(vq>v0)) break; const int rr=cq, cr=rq;
      if (ovq>=0) { /* clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; fdU^=B[ovq];
        rU[rr]^=B[ovr]; cU[cr]^=B[ovr]; fdU^=B[ovr]; qrU[ovq]^=B[ovr]; qrU[ovr]^=B[ovq];
      }
      if (vq>M) { // all possible tried 
        if (rq==0) break; /* at start of fd, it's all over */ else { --R; ++C; vq=Q[R][C]+1; } // go back on fd
      } else { // used ?
        int vr=M-vq;
        while (vq<=M) {
          if (!((rU[rq]&B[vq])|(cU[cq]&B[vq])|(fdU&B[vq])|(rU[rr]&B[vr])|(cU[cr]&B[vr]))) break; ++vq; --vr;
        }
        //if ((R==0)&(vq>Ud)) break; // rest are rotations
        if ((vq<=M)) { /* good, use and go */ Q[rq][cq]=vq; Q[rr][cr]=vr; rU[rq]|=B[vq]; cU[cq]|=B[vq];
          fdU|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr]; fdU|=B[vr]; qrU[vq]|=B[vr]; qrU[vr]|=B[vq]; vq=0;
          if (R==U) { next=row; R=0; C=1; } /* fd complete, go to row */ else { ++R, --C; } // go forward on fd
        }
      }
    }
  } while (T);
  return count;
} // SSSODLSodd

int SODLSeven(const int v0, FILE *wfp) { // nfr
//  ---------
  time_t startTime=time(NULL); enum { row, col, col0, bd, fdt, fdb } next=bd;
  const int M=Nm1, L=M-1, U=Nd2m1, R0=1; int count=0, R=R0, C=R, v=v0, vq=0; initSODLS(T); bool breakDo=F;
  do {
    const int r=R, c=C, ov=Q[r][c]; Q[r][c]=-1;
    switch (next) {
    case row:
      //fprintf(wfp, "row R %d C %d v %d\n", R, C, v);
      if (ov>=0) { rU[r]^=B[ov]; cU[c]^=B[ov]; } // clear old
      if (v==N) { /* 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; const 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; const int t=R; R=C; C=t; v=0; }
      }
      break;
    case col:
      //fprintf(wfp, "col R %d C %d v %d\n", R, C, v); //break;//if (!printSODLS(Q, N, wfp)) break;
      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==N) { /* value too big, back to row with incr value */ next=row; const 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; const int t=R; R=C; C=t;
          if (C==M) { // col limit
            if (R==L) { /* row limit */ if (!printSODLS(Q, N, wfp)) { breakDo=T; break; } ++count;
              if ((N>8)|((count&0xf)==0)) {
                printf("%d%s", count, N>8 ? "" : "\n"); if (N>8) 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:
      // fprintf(wfp, "col0 R %d C %d v %d\n", R, C, v); if (!printSODLS(Q, N, wfp)) break;
      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==N) { // 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:
      //fprintf(wfp, "fdt R %d C %d v %d\n", R, C, v);
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; fdU^=B[ov]; }
      if (v==N) { // all possible tried
        const 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])|(fdU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fdU|=B[v]; const int t=R; R=C; C=t; v=0; next=fdb;
        }
      }
      break;
   case fdb:
      //fprintf(wfp, "fdb R %d C %d v %d\n", R, C, v);
      if (ov>=0) { // clear old
        rU[r]^=B[ov]; cU[c]^=B[ov]; fdU^=B[ov]; const int ovr=Q[c][r]; qrU[ov]^=B[ovr]; qrU[ovr]^=B[ov];
      }
      if (v==N) { // all possible tried
        if (C==0) { C=M; next=bd; } else { const 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])|(fdU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; fdU|=B[v]; const 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 { const int t=R; R=C; C=t; ++R; --C; next=fdt; } /* advance on fd */ v=0;
        }
      }
      break;
    default: // bd
      //fprintf(wfp, "bd R %d C %d v %d\n", R, C, v);
      if ((R==R0)&(v>v0)) { breakDo=T; break; } // make only for start value
      if (ov>=0) { /* clear old */ rU[r]^=B[ov]; cU[c]^=B[ov]; bdU^=B[ov]; qrU[ov]^=B[ov]; }
      if (v==N) { /* 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])|(bdU&B[v]))) break; ++v; }
        if (v<N) { // good, use, go
          Q[r][c]=v; rU[r]|=B[v]; cU[c]|=B[v]; bdU|=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);
  return count;
} // SODLSeven

int SSSODLSeven(const int v0, FILE *wfp) { // nbd
//  -----------
  time_t startTime=time(NULL); enum { row, col, fd } next=fd; char *nname[]={"row", "col", "fd"};
  const int M=Nm1, L=M-1, U=Nd2m1, Ud=U, Ur=U-1; int count=0, vq=v0, R=0, C=M; initSODLS(F);
  do {
    const int rq=R, cq=C, ovq=Q[rq][cq], ovr=M-ovq; Q[rq][cq]=-1;
    if (next==row) {
      const int rr=M-rq, cr=M-cq;
      if (ovq>=0) { /* not advanced, clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; rU[rr]^=B[ovr]; cU[cr]^=B[ovr]; }
      if (vq>M) { // value too big
        if (C==(R+1)) { // at start of row, all tried for this row
          if (R==0) { /* if top row, go back to fd middle */ R=U, C=M-U; next=fd; vq=Q[R][C]+1; }
          else { /* go back next outer col */ next=col; C=R-1; R=L- C; vq=Q[R][C]+1; }
        } else { /* backup in col */ next=col; const int t=R; R=C; C=t; vq=Q[--R][C]+1; }
      } else { /* check value used */ int vr=M-vq;
        while (vq<=M) { if (!((rU[rq]&B[vq])|(cU[cq]&B[vq])|(rU[rr]&B[vr])|(cU[cr]&B[vr]))) break; ++vq; --vr; }
        if (vq<=M) { /* good, use and advance to col */ Q[rq][cq]=vq; Q[rr][cr]=vr;
          rU[rq]|=B[vq]; cU[cq]|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr]; next=col; const int t=R; R=C; C=t; vq=0;
        }
      }
    } else if (next==col) { const int rr=M-rq, cr=M-cq; int vQ=Q[cq][rq], vR=Q[cr][rr];
      if (ovq>=0) { /* clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; rU[rr]^=B[ovr]; cU[cr]^=B[ovr];
        qrU[ovq]^=B[vQ]; qrU[vQ]^=B[ovq]; qrU[ovr]^=B[vR]; qrU[vR]^=B[ovr];
      }
      if (vq>M) { /* value too big, back to row with incr value */ next=row; const int t=R; R=C; C=t; vq=Q[R][C]+1; }
      else { /* check value used */ int vr=M-vq;
        while (vq<=M) {
          if (!((rU[rq]&B[vq])|(cU[cq]&B[vq])|(rU[rr]&B[vr])|(cU[cr]&B[vr])|(qrU[vq]&B[vQ]))) break; ++vq; --vr;
        }
        if (vq<=M) { /* good, use and go to row */ Q[rq][cq]=vq; Q[rr][cr]=vr; vQ=Q[cq][rq], vR=Q[cr][rr];
          rU[rq]|=B[vq]; cU[cq]|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr];
          qrU[vq]|=B[vQ]; qrU[vQ]|=B[vq]; qrU[vr]|=B[vR]; qrU[vR]|=B[vr]; next=row; const int t=R; R=C; C=t;
          if (C==(L-R)) { // col limit
            if (R==Ur) { /* row limit */ if (!printSODLS(Q, N, wfp)) break; ++count;
              if ((N>8)|((count&0xf)==0)) {
                printf("%d%s", count, N>12 ? "" : "\n"); if (N>12) printElapsedTime(startTime, ' ');
              }
              // clear and go back to row with incr value
              rU[rq]^=B[vq]; cU[cq]^=B[vq]; rU[rr]^=B[vr]; cU[cr]^=B[vr]; qrU[vq]^=B[vQ]; qrU[vQ]^=B[vq];
              qrU[vr]^=B[vR]; qrU[vR]^=B[vr]; Q[C][R]=-1; vq=Q[R][C]+1;
            } else { ++R; C=R+1; vq=0; } // to start of next row
          } else { ++C; vq=0; } // to row, next col
        }
      }
    } else { /* next==fd */ if ((R==0)&(vq>v0)) break; const int rr=cq, cr=rq;
      if (ovq>=0) { /* clear old */ rU[rq]^=B[ovq]; cU[cq]^=B[ovq]; fdU^=B[ovq]; rU[rr]^=B[ovr];
        cU[cr]^=B[ovr]; fdU^=B[ovr]; qrU[ovq]^=B[ovr]; qrU[ovr]^=B[ovq];
      }
      if (vq>M) { // all possible tried
        if (rq==0) break; /* at start of fd, it's all over */ else {--R; ++C; vq=Q[R][C]+1; } // back up on fd
      } else { /* used ? */ int vr=M-vq;
        while (vq<=M) {
          if (!((rU[rq]&B[vq])|(cU[cq]&B[vq])|(fdU&B[vq])|(rU[rr]&B[vr])|(cU[cr]&B[vr]))) break; ++vq; --vr;
        }
        //if ((R==0)&(vq>Ud)) break; // rest are rotations
        if ((vq<=M)) { /* good, use and go */ Q[rq][cq]=vq; Q[rr][cr]=vr; rU[rq]|=B[vq]; cU[cq]|=B[vq];
          fdU|=B[vq]; rU[rr]|=B[vr]; cU[cr]|=B[vr]; fdU|=B[vr]; qrU[vq]|=B[vr]; qrU[vr]|=B[vq]; vq=0;
          if (R==U) { next=row; R=0; C=1; } /* fd complete, go to row */ else { ++R, --C; } // go forward on fd
        }
      }
    }
  } while (T);
  return count;
} // SSSODLSeven

//--------- SODLS 9 fill order ----------
//
//0   0  1  2  3  4  5  6  7  8 
//1  24 10 31 33 35 37 39 18 40
//2  25 32 11 43 45 47 20 49 50
//3  26 34 44 12 53 22 55 57 58
//4  27 36 46 54  9 61 63 65 66
//5  28 38 48 23 62 13 69 71 72
//6  29 41 21 56 64 70 14 75 76
//7  30 19 51 59 67 73 80 15 77
//8  17 42 52 60 68 74 79 78 16

const int row9[81]={
  0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0..8
  4, 1, 2, 3, 5, 6, 7, 8, 8,  // 9..17
  1, 7, 2, 6, 3, 5, 1, 2, 3,  //18..26
  4, 5, 6, 7, 1, 2, 1, 3, 1,  //27..35
  4, 1, 5, 1, 1, 6, 8, 2, 3,  //36..44
  2, 4, 2, 5, 2, 2, 7, 8, 3,  //45..53
  4, 3, 6, 3, 3, 7, 8, 4, 5,  //54..62
  4, 6, 4, 4, 7, 8, 5, 6, 5,  //63..71
  5, 7, 8, 6, 6, 7, 8, 8, 7   //72..80
},

col9[81]={
  0, 1, 2, 3, 4, 5, 6, 7, 8,  // 0..8
  4, 1, 2, 3, 5, 6, 7, 8, 0,  // 9..17
  7, 1, 6, 2, 5, 3, 0, 0, 0,  //18..26
  0, 0, 0, 0, 2, 1, 3, 1, 4,  //27..35
  1, 5, 1, 6, 8, 1, 1, 3, 2,  //36..44
  4, 2, 5, 2, 7, 8, 2, 2, 4,  //45..53
  3, 6, 3, 7, 8, 3, 3, 5, 4,  //54..62
  6, 4, 7, 8, 4, 4, 6, 5, 7,  //63..71
  8, 5, 5, 7, 8, 8, 7, 6, 6   //72..80
};

void initSODLS9(int U[81]) { // natural first row
//   ---------
  for (int i=0; i<N; ++i) { rU[i]=0; qrU[B[i]]=B[i]; } // qrU of \diagonal
  for (int c=0; c<N; c++) { Q[0][c]=c; U[c]=B[c]; rU[0]|=B[c]; cU[c]=B[c]; }
  bdU=1; fdU=U[8]; for (int i=0; i<N; ++i) P[B[i]]=i;
} // initSODLS9

bool makeSODLS9a(int U[81], const int A, const int wfd) {
//   -----------
  bool ok=F; U[76]=rU[row9[76]]^A; // rl
  if (!(cU[col9[76]]&U[76])) {
    cU[col9[75]]|=U[75]; cU[col9[76]]|=U[76];

    U[77]=cU[col9[77]]^A; // cl
    if (!(rU[row9[77]]&U[77])) {
      rU[row9[77]]|=U[77];

      U[78]=cU[col9[78]]^A; // cl
      if (!((rU[row9[78]]&U[78])||(U[78]&qrU[U[77]]))) {
        rU[row9[78]]|=U[78]; qrU[U[78]]|=U[77]; qrU[U[77]]|=U[78];

        U[79]=rU[row9[79]]^A; // rl
        if (!((cU[col9[79]]&U[79])||(U[79]&qrU[U[76]]))) {
          cU[col9[79]]|=U[79]; qrU[U[79]]|=U[76]; qrU[U[76]]|=U[79];

          U[80]=rU[row9[80]]^A; // rl
          if (!((cU[col9[80]]&U[80])||(U[80]&qrU[U[75]]))) {
            for (int j=N; j<81; ++j) Q[row9[j]][col9[j]]=P[U[j]];
            ok=printSODLS9(Q, wfd);
          }
          cU[col9[79]]^=U[79]; qrU[U[79]]^=U[76]; qrU[U[76]]^=U[79];
        }
        rU[row9[78]]^=U[78]; qrU[U[78]]^=U[77]; qrU[U[77]]^=U[78];;
      }
      rU[row9[77]]^=U[77];
    }
    cU[col9[75]]^=U[75]; cU[col9[76]]^=U[76];
  } 
  return ok;
} // makeSODLS9a

int makeSODLS9(const int bv0, const int wfd) {
//  ----------
  const int n=9, A=(1<<n)-1; int G[81], U[81], count=0; initSODLS9(U);

  U[9]=bv0; rU[row9[9]]=bv0; cU[col9[9]]|=bv0; bdU|=bv0; fdU|=bv0; // bf

  for (G[10]=A^(cU[col9[10]]|bdU); G[10]!=0; G[10]&=(G[10]-1)) { // bc
  U[10]=(G[10]&-G[10]); rU[row9[10]]=U[10]; cU[col9[10]]|=U[10]; bdU|=U[10];

  for (G[11]=A^(cU[col9[11]]|bdU); G[11]!=0; G[11]&=(G[11]-1)) { // bc
  U[11]=(G[11]&-G[11]); rU[row9[11]]=U[11]; cU[col9[11]]|=U[11]; bdU|=U[11];

  for (G[12]=A^(cU[col9[12]]|bdU); G[12]!=0; G[12]&=(G[12]-1)) { // bc
  U[12]=(G[12]&-G[12]); rU[row9[12]]=U[12]; cU[col9[12]]|=U[12]; bdU|=U[12];

  for (G[13]=A^(cU[col9[13]]|bdU); G[13]!=0; G[13]&=(G[13]-1)) { // bc
  U[13]=(G[13]&-G[13]); rU[row9[13]]=U[13]; cU[col9[13]]|=U[13]; bdU|=U[13];

  for (G[14]=A^(cU[col9[14]]|bdU); G[14]!=0; G[14]&=(G[14]-1)) { // bc
  U[14]=(G[14]&-G[14]); rU[row9[14]]=U[14]; cU[col9[14]]|=U[14]; bdU|=U[14];

  for (G[15]=A^(cU[col9[15]]|bdU); G[15]!=0; G[15]&=(G[15]-1)) { // bc
  U[15]=(G[15]&-G[15]); bdU|=U[15];

      U[16]=bdU^A; if ((U[16]==U[8])) { bdU^=U[15]; continue; }
      rU[row9[15]]=U[15]; cU[col9[15]]|=U[15]; rU[row9[16]]=U[16]; cU[col9[16]]|=U[16];

  for (G[17]=A^(rU[row9[17]]|cU[col9[17]]|fdU); G[17]!=0; G[17]&=(G[17]-1)) { // fd
  U[17]=(G[17]&-G[17]); rU[row9[17]]|=U[17]; cU[col9[17]]|=U[17]; fdU|=U[17];
  qrU[U[17]]|=U[8]; qrU[U[8]]|=U[17];

  for (G[18]=A^(rU[row9[18]]|cU[col9[18]]|fdU); G[18]!=0; G[18]&=(G[18]-1)) { // fd
  U[18]=(G[18]&-G[18]); rU[row9[18]]|=U[18]; cU[col9[18]]|=U[18]; fdU|=U[18];

  for (G[19]=A^(rU[row9[19]]|cU[col9[19]]|fdU); G[19]!=0; G[19]&=(G[19]-1)) { // fd
  U[19]=(G[19]&-G[19]); rU[row9[19]]|=U[19]; cU[col9[19]]|=U[19]; fdU|=U[19];
  qrU[U[19]]|=U[18]; qrU[U[18]]|=U[19];

  for (G[20]=A^(rU[row9[20]]|cU[col9[20]]|fdU); G[20]!=0; G[20]&=(G[20]-1)) { // fd
  U[20]=(G[20]&-G[20]); rU[row9[20]]|=U[20]; cU[col9[20]]|=U[20]; fdU|=U[20];

  for (G[21]=A^(rU[row9[21]]|cU[col9[21]]|fdU); G[21]!=0; G[21]&=(G[21]-1)) { // fd
  U[21]=(G[21]&-G[21]); rU[row9[21]]|=U[21]; cU[col9[21]]|=U[21]; fdU|=U[21];
  qrU[U[21]]|=U[20]; qrU[U[20]]|=U[21];

  for (G[22]=A^(rU[row9[22]]|cU[col9[22]]|fdU); G[22]!=0; G[22]&=(G[22]-1)) { // fd
  U[22]=(G[22]&-G[22]); fdU|=U[22];

       U[23]=fdU^A; if ((U[23]==U[13])||cU[col9[23]]&U[23]) { fdU^=U[22]; continue; }
       rU[row9[22]]|=U[22]; cU[col9[22]]|=U[22]; qrU[U[22]]|=U[23];
       rU[row9[23]]|=U[23]; cU[col9[23]]|=U[23]; qrU[U[23]]|=U[22];

  for (G[24]=A^(rU[row9[24]]|cU[col9[24]]|qrU[U[1]]); G[24]!=0; G[24]&=(G[24]-1)) { // cd
  U[24]=(G[24]&-G[24]); rU[row9[24]]|=U[24]; cU[col9[24]]|=U[24];
  qrU[U[24]]|=U[1]; qrU[U[1]]|=U[24];

  for (G[25]=A^(rU[row9[25]]|cU[col9[25]]|qrU[U[2]]); G[25]!=0; G[25]&=(G[25]-1)) { // cd
  U[25]=(G[25]&-G[25]); rU[row9[25]]|=U[25]; cU[col9[25]]|=U[25];
  qrU[U[25]]|=U[2]; qrU[U[2]]|=U[25];

  for (G[26]=A^(rU[row9[26]]|cU[col9[26]]|qrU[U[3]]); G[26]!=0; G[26]&=(G[26]-1)) { // cd
  U[26]=(G[26]&-G[26]); rU[row9[26]]|=U[26]; cU[col9[26]]|=U[26];
  qrU[U[26]]|=U[3]; qrU[U[3]]|=U[26];

  for (G[27]=A^(rU[row9[27]]|cU[col9[27]]|qrU[U[4]]); G[27]!=0; G[27]&=(G[27]-1)) { // cd
  U[27]=(G[27]&-G[27]); rU[row9[27]]|=U[27]; cU[col9[27]]|=U[27];
  qrU[U[27]]|=U[4]; qrU[U[4]]|=U[27];

  for (G[28]=A^(rU[row9[28]]|cU[col9[28]]|qrU[U[5]]); G[28]!=0; G[28]&=(G[28]-1)) { // cd
  U[28]=(G[28]&-G[28]); rU[row9[28]]|=U[28]; cU[col9[28]]|=U[28];
  qrU[U[28]]|=U[5]; qrU[U[5]]|=U[28];

  for (G[29]=A^(rU[row9[29]]|cU[col9[29]]|qrU[U[6]]); G[29]!=0; G[29]&=(G[29]-1)) { // cd
  U[29]=(G[29]&-G[29]); cU[col9[29]]|=U[29];

      U[30]=cU[col9[30]]^A;
      if ((rU[row9[30]]&U[30])||(U[30]&qrU[U[7]])||((U[7]==U[29])&&(U[6]==U[30])))
        { cU[col9[29]]^=U[29]; continue; }
      rU[row9[29]]|=U[29]; qrU[U[29]]|=U[6]; qrU[U[6]]|=U[29];
      rU[row9[30]]|=U[30]; qrU[U[30]]|=U[7]; qrU[U[7]]|=U[30];

  for (G[31]=A^(rU[row9[31]]|cU[col9[31]]); G[31]!=0; G[31]&=(G[31]-1)) { // rd
  U[31]=(G[31]&-G[31]); rU[row9[31]]|=U[31]; cU[col9[31]]|=U[31];

  for (G[32]=A^(rU[row9[32]]|cU[col9[32]]|qrU[U[31]]); G[32]!=0; G[32]&=(G[32]-1)) { // cd
  U[32]=(G[32]&-G[32]); rU[row9[32]]|=U[32]; cU[col9[32]]|=U[32];
  qrU[U[32]]|=U[31]; qrU[U[31]]|=U[32];

  for (G[33]=A^(rU[row9[33]]|cU[col9[33]]); G[33]!=0; G[33]&=(G[33]-1)) { // rd
  U[33]=(G[33]&-G[33]); rU[row9[33]]|=U[33]; cU[col9[33]]|=U[33];

  for (G[34]=A^(rU[row9[34]]|cU[col9[34]]|qrU[U[33]]); G[34]!=0; G[34]&=(G[34]-1)) { // cd
  U[34]=(G[34]&-G[34]); rU[row9[34]]|=U[34]; cU[col9[34]]|=U[34];
  qrU[U[34]]|=U[33]; qrU[U[33]]|=U[34];

  for (G[35]=A^(rU[row9[35]]|cU[col9[35]]); G[35]!=0; G[35]&=(G[35]-1)) { // rd
  U[35]=(G[35]&-G[35]); rU[row9[35]]|=U[35]; cU[col9[35]]|=U[35];

  for (G[36]=A^(rU[row9[36]]|cU[col9[36]]|qrU[U[35]]); G[36]!=0; G[36]&=(G[36]-1)) { // cd
  U[36]=(G[36]&-G[36]); rU[row9[36]]|=U[36]; cU[col9[36]]|=U[36];
  qrU[U[36]]|=U[35]; qrU[U[35]]|=U[36];

  for (G[37]=A^(rU[row9[37]]|cU[col9[37]]); G[37]!=0; G[37]&=(G[37]-1)) { // rd
  U[37]=(G[37]&-G[37]); rU[row9[37]]|=U[37]; cU[col9[37]]|=U[37];

  for (G[38]=A^(rU[row9[38]]|cU[col9[38]]|qrU[U[37]]); G[38]!=0; G[38]&=(G[38]-1)) { // cd
  U[38]=(G[38]&-G[38]); rU[row9[38]]|=U[38]; cU[col9[38]]|=U[38];
  qrU[U[38]]|=U[37]; qrU[U[37]]|=U[38];

  for (G[39]=A^(rU[row9[39]]|cU[col9[39]]); G[39]!=0; G[39]&=(G[39]-1)) { // rd
  U[39]=(G[39]&-G[39]); rU[row9[39]]|=U[39];

      U[40]=rU[row9[40]]^A; if (cU[col9[40]]&U[40]) { rU[row9[39]]^=U[39]; continue; }
      cU[col9[39]]|=U[39]; cU[col9[40]]|=U[40];

  for (G[41]=A^(rU[row9[41]]|cU[col9[41]]|qrU[U[39]]); G[41]!=0; G[41]&=(G[41]-1)) { // cd
  U[41]=(G[41]&-G[41]); cU[col9[41]]|=U[41];

      U[42]=cU[col9[42]]^A;
      if ((rU[row9[42]]&U[42])||(U[42]&qrU[U[40]])||((U[40]==U[41])&&(U[39]==U[42])))
        { cU[col9[41]]^=U[41]; continue; }
      rU[row9[41]]|=U[41]; qrU[U[41]]|=U[39]; qrU[U[39]]|=U[41];
      rU[row9[42]]|=U[42]; qrU[U[42]]|=U[40]; qrU[U[40]]|=U[42];

  for (G[43]=A^(rU[row9[43]]|cU[col9[43]]); G[43]!=0; G[43]&=(G[43]-1)) { // rd
  U[43]=(G[43]&-G[43]); rU[row9[43]]|=U[43]; cU[col9[43]]|=U[43];

  for (G[44]=A^(rU[row9[44]]|cU[col9[44]]|qrU[U[43]]); G[44]!=0; G[44]&=(G[44]-1)) { // cd
  U[44]=(G[44]&-G[44]); rU[row9[44]]|=U[44]; cU[col9[44]]|=U[44];
  qrU[U[44]]|=U[43]; qrU[U[43]]|=U[44];

  for (G[45]=A^(rU[row9[45]]|cU[col9[45]]); G[45]!=0; G[45]&=(G[45]-1)) { // rd
  U[45]=(G[45]&-G[45]); rU[row9[45]]|=U[45]; cU[col9[45]]|=U[45];

  for (G[46]=A^(rU[row9[46]]|cU[col9[46]]|qrU[U[45]]); G[46]!=0; G[46]&=(G[46]-1)) { // cd
  U[46]=(G[46]&-G[46]); rU[row9[46]]|=U[46]; cU[col9[46]]|=U[46];
  qrU[U[46]]|=U[45]; qrU[U[45]]|=U[46];

  for (G[47]=A^(rU[row9[47]]|cU[col9[47]]); G[47]!=0; G[47]&=(G[47]-1)) { // rd
  U[47]=(G[47]&-G[47]); rU[row9[47]]|=U[47]; cU[col9[47]]|=U[47];

  for (G[48]=A^(rU[row9[48]]|cU[col9[48]]|qrU[U[47]]); G[48]!=0; G[48]&=(G[48]-1)) { // cd
  U[48]=(G[48]&-G[48]); rU[row9[48]]|=U[48]; cU[col9[48]]|=U[48];
  qrU[U[48]]|=U[47]; qrU[U[47]]|=U[48];

  for (G[49]=A^(rU[row9[49]]|cU[col9[49]]); G[49]!=0; G[49]&=(G[49]-1)) { // rd
  U[49]=(G[49]&-G[49]); rU[row9[49]]|=U[49];

        U[50]=rU[row9[50]]^A; if (cU[col9[50]]&U[50]) { rU[row9[49]]^=U[49]; continue; }
        cU[col9[49]]|=U[49]; cU[col9[50]]|=U[50];

  for (G[51]=A^(rU[row9[51]]|cU[col9[51]]|qrU[U[49]]); G[51]!=0; G[51]&=(G[51]-1)) { // cd
  U[51]=(G[51]&-G[51]); cU[col9[51]]|=U[51];

        U[52]=cU[col9[52]]^A;
        if ((rU[row9[52]]&U[52])||(U[52]&qrU[U[50]])||((U[50]==U[51])&&(U[49]==U[52])))
          { cU[col9[51]]^=U[51]; continue; }
        rU[row9[51]]|=U[51]; qrU[U[51]]|=U[49]; qrU[U[49]]|=U[51];
        rU[row9[52]]|=U[52]; qrU[U[52]]|=U[50]; qrU[U[50]]|=U[52];

  for (G[53]=A^(rU[row9[53]]|cU[col9[53]]); G[53]!=0; G[53]&=(G[53]-1)) { // rd
  U[53]=(G[53]&-G[53]); rU[row9[53]]|=U[53]; cU[col9[53]]|=U[53];

  for (G[54]=A^(rU[row9[54]]|cU[col9[54]]|qrU[U[53]]); G[54]!=0; G[54]&=(G[54]-1)) { // cd
  U[54]=(G[54]&-G[54]); rU[row9[54]]|=U[54]; cU[col9[54]]|=U[54]; qrU[U[54]]|=U[53]; qrU[U[53]]|=U[54];

  for (G[55]=A^(rU[row9[55]]|cU[col9[55]]); G[55]!=0; G[55]&=(G[55]-1)) { // rd
  U[55]=(G[55]&-G[55]); rU[row9[55]]|=U[55]; cU[col9[55]]|=U[55];

  for (G[56]=A^(rU[row9[56]]|cU[col9[56]]|qrU[U[55]]); G[56]!=0; G[56]&=(G[56]-1)) { // cd
  U[56]=(G[56]&-G[56]); rU[row9[56]]|=U[56]; cU[col9[56]]|=U[56]; qrU[U[56]]|=U[55]; qrU[U[55]]|=U[56];

  for (G[57]=A^(rU[row9[57]]|cU[col9[57]]); G[57]!=0; G[57]&=(G[57]-1)) { // rd
  U[57]=(G[57]&-G[57]); rU[row9[57]]|=U[57];

        U[58]=rU[row9[58]]^A; if (cU[col9[58]]&U[58]) { rU[row9[57]]^=U[57]; continue; }
        cU[col9[57]]|=U[57]; cU[col9[58]]|=U[58];

  for (G[59]=A^(rU[row9[59]]|cU[col9[59]]|qrU[U[57]]); G[59]!=0; G[59]&=(G[59]-1)) { // cd
  U[59]=(G[59]&-G[59]); cU[col9[59]]|=U[59];

        U[60]=cU[col9[60]]^A;
        if ((rU[row9[60]]&U[60])||(U[60]&qrU[U[58]])||((U[58]==U[59])&&(U[57]==U[60])))
          { cU[col9[59]]^=U[59]; continue; }
        rU[row9[59]]|=U[59]; qrU[U[59]]|=U[57]; qrU[U[57]]|=U[59];
        rU[row9[60]]|=U[60]; qrU[U[60]]|=U[58]; qrU[U[58]]|=U[60]; 

  for (G[61]=A^(rU[row9[61]]|cU[col9[61]]); G[61]!=0; G[61]&=(G[61]-1)) { // rd
  U[61]=(G[61]&-G[61]); rU[row9[61]]|=U[61]; cU[col9[61]]|=U[61];

  for (G[62]=A^(rU[row9[62]]|cU[col9[62]]|qrU[U[61]]); G[62]!=0; G[62]&=(G[62]-1)) { // cd
  U[62]=(G[62]&-G[62]); rU[row9[62]]|=U[62]; cU[col9[62]]|=U[62]; qrU[U[62]]|=U[61]; qrU[U[61]]|=U[62];

  for (G[63]=A^(rU[row9[63]]|cU[col9[63]]); G[63]!=0; G[63]&=(G[63]-1)) { // rd
  U[63]=(G[63]&-G[63]); rU[row9[63]]|=U[63]; cU[col9[63]]|=U[63];

  for (G[64]=A^(rU[row9[64]]|cU[col9[64]]|qrU[U[63]]); G[64]!=0; G[64]&=(G[64]-1)) { // cd
  U[64]=(G[64]&-G[64]); rU[row9[64]]|=U[64]; cU[col9[64]]|=U[64]; qrU[U[64]]|=U[63]; qrU[U[63]]|=U[64];

  for (G[65]=A^(rU[row9[65]]|cU[col9[65]]); G[65]!=0; G[65]&=(G[65]-1)) { // rd
  U[65]=(G[65]&-G[65]); rU[row9[65]]|=U[65];

      U[66]=rU[row9[66]]^A; if (cU[col9[66]]&U[66]) { rU[row9[65]]^=U[65]; continue; }
      cU[col9[65]]|=U[65]; cU[col9[66]]|=U[66];

  for (G[67]=A^(rU[row9[67]]|cU[col9[67]]|qrU[U[65]]); G[67]!=0; G[67]&=(G[67]-1)) { // cd
  U[67]=(G[67]&-G[67]); cU[col9[67]]|=U[67];

      U[68]=cU[col9[68]]^A;
      if ((rU[row9[68]]&U[68])||(U[68]&qrU[U[66]])||((U[66]==U[67])&&(U[65]==U[68])))
        { cU[col9[67]]^=U[67]; continue; }
      rU[row9[67]]|=U[67]; qrU[U[67]]|=U[65]; qrU[U[65]]|=U[67];
      rU[row9[68]]|=U[68]; qrU[U[68]]|=U[66]; qrU[U[66]]|=U[68];

  for (G[69]=A^(rU[row9[69]]|cU[col9[69]]); G[69]!=0; G[69]&=(G[69]-1)) { // rd
  U[69]=(G[69]&-G[69]); rU[row9[69]]|=U[69]; cU[col9[69]]|=U[69];

  for (G[70]=A^(rU[row9[70]]|cU[col9[70]]|qrU[U[69]]); G[70]!=0; G[70]&=(G[70]-1)) { // cd
  U[70]=(G[70]&-G[70]); rU[row9[70]]|=U[70]; cU[col9[70]]|=U[70]; qrU[U[70]]|=U[69]; qrU[U[69]]|=U[70];

  for (G[71]=A^(rU[row9[71]]|cU[col9[71]]); G[71]!=0; G[71]&=(G[71]-1)) { // rd
  U[71]=(G[71]&-G[71]); rU[row9[71]]|=U[71];

      U[72]=rU[row9[72]]^A; if (cU[col9[72]]&U[72]) { rU[row9[71]]^=U[71]; continue; }
      cU[col9[71]]|=U[71]; cU[col9[72]]|=U[72];

  for (G[73]=A^(rU[row9[73]]|cU[col9[73]]|qrU[U[71]]); G[73]!=0; G[73]&=(G[73]-1)) { // cd
  U[73]=(G[73]&-G[73]); cU[col9[73]]|=U[73];

      U[74]=cU[col9[74]]^A;
      if ((rU[row9[74]]&U[74])||(U[74]&qrU[U[72]])||((U[72]==U[73])&&(U[71]==U[74])))
        { cU[col9[73]]^=U[73]; continue; } 
      rU[row9[73]]|=U[73]; qrU[U[73]]|=U[71]; qrU[U[71]]|=U[73];
      rU[row9[74]]|=U[74]; qrU[U[74]]|=U[72]; qrU[U[72]]|=U[74];

  for (G[75]=A^(rU[row9[75]]|cU[col9[75]]); G[75]!=0; G[75]&=(G[75]-1)) { // rd 
  U[75]=(G[75]&-G[75]); rU[row9[75]]|=U[75];

      if (makeSODLS9a(U, A, wfd)) { ++count; if ((count&0xff)==0) printf("%d\n", count); }

  rU[row9[75]]^=U[75];
  } // rd, rl
  rU[row9[74]]^=U[74];
  qrU[U[74]]^=U[72]; qrU[U[72]]^=U[74]; qrU[U[73]]^=U[71]; qrU[U[71]]^=U[73];
  rU[row9[73]]^=U[73]; cU[col9[73]]^=U[73];
  } // cd, cl
  cU[col9[72]]^=U[72]; rU[row9[71]]^=U[71]; cU[col9[71]]^=U[71]; 
  } // rd, rl
  rU[row9[70]]^=U[70]; cU[col9[70]]^=U[70]; qrU[U[70]]^=U[69]; qrU[U[69]]^=U[70];
  } // cd
  rU[row9[69]]^=U[69]; cU[col9[69]]^=U[69];
  } // rd
  rU[row9[68]]^=U[68];
  qrU[U[68]]^=U[66]; qrU[U[66]]^=U[68]; qrU[U[67]]^=U[65]; qrU[U[65]]^=U[67];
  rU[row9[67]]^=U[67]; cU[col9[67]]^=U[67];
  } // cd, cl
  cU[col9[66]]^=U[66]; rU[row9[65]]^=U[65]; cU[col9[65]]^=U[65];
  } // rd, rl
  rU[row9[64]]^=U[64]; cU[col9[64]]^=U[64]; qrU[U[64]]^=U[63]; qrU[U[63]]^=U[64];
  } // cd
  rU[row9[63]]^=U[63]; cU[col9[63]]^=U[63];
  } // rd
  rU[row9[62]]^=U[62]; cU[col9[62]]^=U[62]; qrU[U[62]]^=U[61]; qrU[U[61]]^=U[62];
  } // cd
  rU[row9[61]]^=U[61]; cU[col9[61]]^=U[61];
  } // rd
  rU[row9[60]]^=U[60];
  qrU[U[60]]^=U[58]; qrU[U[58]]^=U[60]; qrU[U[59]]^=U[57]; qrU[U[57]]^=U[59];
  rU[row9[59]]^=U[59]; cU[col9[59]]^=U[59];
  } // cd, cl
  cU[col9[58]]^=U[58]; rU[row9[57]]^=U[57]; cU[col9[57]]^=U[57];
  } // rd
  rU[row9[56]]^=U[56]; cU[col9[56]]^=U[56]; qrU[U[56]]^=U[55]; qrU[U[55]]^=U[56];
  } // cd
  rU[row9[55]]^=U[55]; cU[col9[55]]^=U[55];
  } // rd
  rU[row9[54]]^=U[54]; cU[col9[54]]^=U[54]; qrU[U[54]]^=U[53]; qrU[U[53]]^=U[54];
  } // cd
  rU[row9[53]]^=U[53]; cU[col9[53]]^=U[53];
  } // rd
  rU[row9[52]]^=U[52];
  qrU[U[52]]^=U[50]; qrU[U[50]]^=U[52]; qrU[U[49]]^=U[51]; qrU[U[51]]^=U[49];
  rU[row9[51]]^=U[51]; cU[col9[51]]^=U[51];
  } // cd, cl
  cU[col9[50]]^=U[50]; rU[row9[49]]^=U[49]; cU[col9[49]]^=U[49];
  } // rd, rl
  rU[row9[48]]^=U[48]; cU[col9[48]]^=U[48]; qrU[U[48]]^=U[47]; qrU[U[47]]^=U[48];
  } // cd
  rU[row9[47]]^=U[47]; cU[col9[47]]^=U[47];
  } // rd
  rU[row9[46]]^=U[46]; cU[col9[46]]^=U[46]; qrU[U[46]]^=U[45]; qrU[U[45]]^=U[46];
  } // cd
  rU[row9[45]]^=U[45]; cU[col9[45]]^=U[45];
  } // rd
  rU[row9[44]]^=U[44]; cU[col9[44]]^=U[44]; qrU[U[44]]^=U[43]; qrU[U[43]]^=U[44];
  } // cd
  rU[row9[43]]^=U[43]; cU[col9[43]]^=U[43];
  } // rd
  rU[row9[42]]^=U[42];
  qrU[U[42]]^=U[40]; qrU[U[40]]^=U[42]; qrU[U[41]]^=U[39]; qrU[U[39]]^=U[41];
  rU[row9[41]]^=U[41]; cU[col9[41]]^=U[41];
  } // cd, cl
  cU[col9[40]]^=U[40]; rU[row9[39]]^=U[39]; cU[col9[39]]^=U[39];
  } // rd, rl
  rU[row9[38]]^=U[38]; cU[col9[38]]^=U[38]; qrU[U[38]]^=U[37]; qrU[U[37]]^=U[38];
  } // cd
  rU[row9[37]]^=U[37]; cU[col9[37]]^=U[37];
  } // rd
  rU[row9[36]]^=U[36]; cU[col9[36]]^=U[36]; qrU[U[36]]^=U[35]; qrU[U[35]]^=U[36];
  } // cd
  rU[row9[35]]^=U[35]; cU[col9[35]]^=U[35];
  } // rd
  rU[row9[34]]^=U[34]; cU[col9[34]]^=U[34]; qrU[U[34]]^=U[33]; qrU[U[33]]^=U[34];
  } // cd
  rU[row9[33]]^=U[33]; cU[col9[33]]^=U[33];
  } // rd
  rU[row9[32]]^=U[32]; cU[col9[32]]^=U[32]; qrU[U[32]]^=U[31]; qrU[U[31]]^=U[32];
  } // cd
  rU[row9[31]]^=U[31]; cU[col9[31]]^=U[31];
  } // rd
  rU[row9[30]]^=U[30];
  qrU[U[30]]^=U[7]; qrU[U[7]]^=U[30]; qrU[U[29]]^=U[6]; qrU[U[6]]^=U[29];
  rU[row9[29]]^=U[29]; cU[col9[29]]^=U[29];
  } // cd, cl
  rU[row9[28]]^=U[28]; cU[col9[28]]^=U[28]; qrU[U[28]]^=U[5]; qrU[U[5]]^=U[28];
  } // cd
  rU[row9[27]]^=U[27]; cU[col9[27]]^=U[27]; qrU[U[27]]^=U[4]; qrU[U[4]]^=U[27];
  } // cd
  rU[row9[26]]^=U[26]; cU[col9[26]]^=U[26]; qrU[U[26]]^=U[3]; qrU[U[3]]^=U[26];
  } // cd
  rU[row9[25]]^=U[25]; cU[col9[25]]^=U[25]; qrU[U[25]]^=U[2]; qrU[U[2]]^=U[25];
  } // cd
  rU[row9[24]]^=U[24]; cU[col9[24]]^=U[24]; qrU[U[24]]^=U[1]; qrU[U[1]]^=U[24];
  } // cd
  rU[row9[23]]^=U[23]; cU[col9[23]]^=U[23]; qrU[U[23]]^=U[22];
  rU[row9[22]]^=U[22]; cU[col9[22]]^=U[22]; fdU^=U[22]; qrU[U[22]]^=U[23];
  } // fd, fE
  rU[row9[21]]^=U[21]; cU[col9[21]]^=U[21]; fdU^=U[21]; qrU[U[21]]^=U[20]; qrU[U[20]]^=U[21];
  } // fd
  rU[row9[20]]^=U[20]; cU[col9[20]]^=U[20]; fdU^=U[20];
  } // fd
  rU[row9[19]]^=U[19]; cU[col9[19]]^=U[19]; fdU^=U[19]; qrU[U[19]]^=U[18]; qrU[U[18]]^=U[19];
  } // fd
  rU[row9[18]]^=U[18]; cU[col9[18]]^=U[18]; fdU^=U[18];
  } // fd
  rU[row9[17]]^=U[17]; cU[col9[17]]^=U[17]; fdU^=U[17]; qrU[U[17]]^=U[8]; qrU[U[8]]^=U[17];
  } // fd
  cU[col9[16]]^=U[16]; cU[col9[15]]^=U[15]; bdU^=U[15];
  } // bc, bE
  cU[col9[14]]^=U[14]; bdU^=U[14];
  } // bc
  cU[col9[13]]^=U[13]; bdU^=U[13];
  } // bc
  cU[col9[12]]^=U[12]; bdU^=U[12];
  } // bc
  cU[col9[11]]^=U[11]; bdU^=U[11];
  } // bc
  cU[col9[10]]^=U[10]; bdU^=U[10];
  } // bc
  if (!outputLast(wfd)) count=0; return count;
} // makeSODLS9

int makeEven(const bool ssym, const int v0, FILE *wfp) { return ssym ? SSSODLSeven(v0, wfp) : SODLSeven(v0, wfp); }
//  --------

int makeOdd(const bool ssym, const int v0, FILE *wfp) { return ssym ? SSSODLSodd(v0, wfp) : SODLSodd(v0, wfp); }
//  -------

int makeSODLS(const bool ssym, const int v0, FILE *wfp) { return (N&1) ? makeOdd(ssym, v0, wfp) : makeEven(ssym, v0, wfp); }
//  ---------
//========================================================= main =========================================================

bool validOrder(const int n) {
//   ----------
  if (n<=0) { printf("\aERROR: N must be a positive integer.\n"); return F; }
  else if ((n==2)|(N==3)|(N==6)) { printf("\aThere is no %dx%d SODLS.\n", N, N); return F; }
  return T;
}// validOrder

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

int main() {
//  ----
  bool another=T, inputSize=T, ok=F; outputLocalTime();
  do {
    int count=0; if (inputSize) { printf("\nSODLS order? "); N=getInt(); }
    if (N==1) printf("SOLDS is 0\n");
    else if (validOrder(N)) {
      initGlobals(); bool ssym=F;
      if ((N&3)!=2) { printf("\nMake SSSOLDS, y (yes) or n (no)? "); ssym=getY(); } int v0=0;
      if (getStart(ssym, &v0)) { time_t startTime=time(NULL);
        if (!ssym&(N==9)) {
          const int wfd=openOutputd();
          if (wfd!=-1) { outPointer=outputBuffer; outSquares=0; count=makeSODLS9(B[v0], wfd); _close(wfd); }
        } else {
          FILE *wfp=openOutputp(ssym); if (wfp!=NULL) { count=makeSODLS(ssym, v0, wfp); fclose(wfp); }
        }
        printElapsedTime(startTime, '\n');
        printf("Number of SODLS %d\n", count); if (count==0) remove(outputFile); else ok=T;
      }
    }
    printf("\nContinue? y (yes) or n (no) or the SODLS order: ");
    if (getYorOrder(&N)) inputSize=(N==0); else another=F;
  } while (another);
  printf("\nPress a key to close the console");
  while (!_kbhit()) Sleep(250); return ok ? EXIT_SUCCESS : EXIT_FAILURE;
} // main