@*Intro. Given the specification of a SuperSlitherlink puzzle in |stdin|, this program outputs {\mc MCC} data for the problem of finding all solutions. (It's based on {\mc SLITHERLINK-DLX}, which handles ordinary Slitherlink.) SuperSlitherlink extends the former rules by allowing several cells to participate in the same clue. Each superclue is identified by a letter, and the relevant cells are marked with that letter. An edge that lies between two cells with the same letter is called ``internal'' and it cannot participate in the solution. An edge that lies between a cell with a letter and a cell that either has a numeric clue or a blank clue or lies off the board is a ``boundary edge'' for that letter. An edge that lies between cells with different letters is a boundary edge for both of those letters. The clue for a letter is the number of boundary edges that should appear in the solution. No attempt is made to enforce the ``single loop'' condition. Solutions found by {\mc DLX3} will consist of disjoint loops. But {\mc DLX3-LOOP} will weed out any disconnected solutions; in fact it will nip most of them in the bud. The specification begins with $m$ lines of $n$ characters each; those characters should be either `\.0' or `\.1' or `\.2' or `\.3' or `\.4' or `\..' or a letter. Those opening lines should be followed by lines of the form \.!$\langle\,\hbox{letter}\,\rangle\.=\langle\,\hbox{clue}\,\rangle$, one for each letter in the opening lines. For example, here's the specification for a simple SuperSlitherlink puzzle designed by Johan de Ruiter for Pi Day 2025: $$\vbox{\halign{\tt#\hfil\cr aaa....\cr aaabb..\cr aaabb..\cr .......\cr ..ccddd\cr ..ccddd\cr ....ddd\cr !a=3\cr !b=1\cr !c=4\cr !d=1\cr }}$$ (See {\tt https://cs.stanford.edu/\char`\~knuth/news25.html}.) @ Here now is the general outline. @d maxn 30 /* |m| and |n| must be at most this */ @d bufsize 80 @d panic(message) {@+fprintf(stderr,"%s: %s",message,buf);@+exit(-1);@+} @c #include #include char buf[bufsize]; int board[maxn][maxn]; /* the given clues */ char super[128]; /* did this letter appear? */ int clue[128]; /* numeric clues for letters that have appeared */ char code[]={0xc,0xa,0x5,0x3,0x9,0x6,0x0}; char edge[2*maxn+1][2*maxn+1]; /* is this a legal edge? */ void main() { register int d,i,j,k,m,n; @; @; @; for (i=0;i<=m;i++) for (j=0;j<=n;j++) { @; @; @; @; @; @; @; } } @ @= printf("| slitherlink-dlx:\n"); for (i=0;i; for (j=0;j'4')) super[k]=1,clue[k]=-1; /* we treat |k| as a letter */ board[i][j]=k; } if (i++==0) n=j; else if (n!=j) panic("row has wrong number of clues"); } m=i; if (m<2 || n<2) panic("the board dimensions must be 2 or more"); for (k=0;k<128;k++) if (super[k] && clue[k]<0) fprintf(stderr,"No `!%c=...'!\n", k); fprintf(stderr,"OK, I've read a %dx%d array of clues.\n", m,n); @ @= { if (buf[2]!='=') panic("no = sign"); k=buf[1]; if (!super[k]) fprintf(stderr,"letter `%c' never occurred!\n", k); else { for (d=0,j=3;buf[j]>='0' && buf[j]<='9';j++) d=10*d+buf[j]-'0'; clue[k]=d; } continue; } @ The primary items are ``tiles,'' ``cells,'' and ``clues.'' Tiles control the loop path; the name of tile $(i,j)$ is `$2i$\.,$2j$'. Cells represent numeric clues; the name of cell $(i,j)$ is `$2i{+}1$\.,$2j{+}1$'. A cell item is present only if a numeric clue has been given for that cell of the board. There also are primary items for ``subtiles,'' which are somewhat subtle (please forgive the pun) and explained later. A subtile represents the state of two adjacent edges. The secondary items are ``edges'' of the path. Their names are the midpoints of the tiles they connect. An edge is illegal if it is internal to the clue of some letter. A boundary edge for a zero clue is also illegal. @= for (i=0;i<=m+m;i++) for (j=0;j<=n+n;j++) if ((i+j)&1) edge[i][j]=1; for (i=0;i0 && edge[i+i-1][j+j]) @d W(i,j) (j>0 && edge[i+i][j+j-1]) @d E(i,j) (j= for (i=0;i<=m;i++) for (j=0;j<=n;j++) { printf("%c%c ", encode(i+i),encode(j+j)); if (N(i,j) && W(i,j)) printf("%cNW%c ", encode(i+i),encode(j+j)); if (N(i,j) && E(i,j)) printf("%cNE%c ", encode(i+i),encode(j+j)); if (S(i,j) && E(i,j)) printf("%cSE%c ", encode(i+i),encode(j+j)); if (S(i,j) && W(i,j)) printf("%cSW%c ", encode(i+i),encode(j+j)); if (N(i,j) && S(i,j)) printf("%cNS%c ", encode(i+i),encode(j+j)); if (E(i,j) && W(i,j)) printf("%cEW%c ", encode(i+i),encode(j+j)); } for (i=0;i='1' && board[i][j]<='4') printf("%d|%c%c ", 2*(board[i][j]-'0'),encode(i+i+1),encode(j+j+1)); for (k=0;k<128;k++) if (super[k]) printf("%d|%c ", 2*clue[k],k); printf("|"); for (i=0;i<=m+m;i++) for (j=0;j<=n+n;j++) if (edge[i][j]) printf(" %c%c", encode(i),encode(j)); printf("\n"); @ A tile is filled with either zero or two edges, and each edge potentially contributes to one or two clue counts. If there are two edges, we must be sure that they don't contribute to the same count. Thus, with two edges, we might contribute to four counts. Two of them come from the tile; the other two from the corresponding subtile. @= { for (k=0;k<7;k++) { if ((code[k]&8)&&!N(i,j)) continue; /* can't go north */ if ((code[k]&4)&&!W(i,j)) continue; /* can't go west */ if ((code[k]&2)&&!E(i,j)) continue; /* can't go east */ if ((code[k]&1)&&!S(i,j)) continue; /* can't go south */ printf("%c%c", encode(i+i),encode(j+j)); if (N(i,j)) printf(" %c%c:%d", encode(i+i-1), encode(j+j), code[k]>>3); if (W(i,j)) printf(" %c%c:%d", encode(i+i), encode(j+j-1), (code[k]>>2)&1); if (E(i,j)) printf(" %c%c:%d", encode(i+i), encode(j+j+1), (code[k]>>1)&1); if (S(i,j)) printf(" %c%c:%d", encode(i+i+1), encode(j+j), code[k]&1); switch (k) { case 0: @;@+@;@+break; /* NW */ case 1: @;@+@;@+break; /* NE */ case 2: @;@+@;@+break; /* SW */ case 3: @;@+@;@+break; /* SE */ case 4: @;@+@;@+break; /* NS */ case 5: @;@+@;@+break; /* EW */ case 6: break; /* untouched */ } printf("\n"); } } @ The next six sections are almost the same, and rather boring. I hope I've got them right. @= if (N(i,j) && W(i,j)) { printf("%cNW%c", encode(i+i),encode(j+j)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); if (N(i,j)) { printf("%cNW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); } if (W(i,j)) { printf("%cNW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j-1)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); printf("\n"); } if (N(i,j) && W(i,j)) { printf("%cNW%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j),encode(i+i),encode(j+j-1)); @;@+@; printf("\n"); } } @ @= if (N(i,j) && E(i,j)) { printf("%cNE%c", encode(i+i),encode(j+j)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); printf("\n"); if (N(i,j)) { printf("%cNE%c %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); printf("\n"); } if (E(i,j)) { printf("%cNE%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j+1)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); printf("\n"); } if (N(i,j) && E(i,j)) { printf("%cNE%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j),encode(i+i),encode(j+j+1)); @;@+@; printf("\n"); } } @ @= if (S(i,j) && E(i,j)) { printf("%cSE%c", encode(i+i),encode(j+j)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); printf("\n"); if (S(i,j)) { printf("%cSE%c %c%c:1", encode(i+i),encode(j+j),encode(i+i+1),encode(j+j)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); printf("\n"); } if (E(i,j)) { printf("%cSE%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j+1)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); printf("\n"); } if (S(i,j) && E(i,j)) { printf("%cSE%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i+1),encode(j+j),encode(i+i),encode(j+j+1)); @;@+@; printf("\n"); } } @ @= if (S(i,j) && W(i,j)) { printf("%cSW%c", encode(i+i),encode(j+j)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); if (S(i,j)) { printf("%cSW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i+1),encode(j+j)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); } if (W(i,j)) { printf("%cSW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j-1)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); printf("\n"); } if (S(i,j) && W(i,j)) { printf("%cSW%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i+1),encode(j+j),encode(i+i),encode(j+j-1)); @;@+@; printf("\n"); } } @ @= if (N(i,j) && S(i,j)) { printf("%cNS%c", encode(i+i),encode(j+j)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); printf("\n"); if (N(i,j)) { printf("%cNS%c %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j)); if (S(i,j)) printf(" %c%c:0", encode(i+i+1),encode(j+j)); printf("\n"); } if (S(i,j)) { printf("%cNS%c %c%c:1", encode(i+i),encode(j+j),encode(i+i+1),encode(j+j)); if (N(i,j)) printf(" %c%c:0", encode(i+i-1),encode(j+j)); printf("\n"); } if (N(i,j) && S(i,j)) { printf("%cNS%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i-1),encode(j+j),encode(i+i+1),encode(j+j)); @;@+@; printf("\n"); } } @ @= if (E(i,j) && W(i,j)) { printf("%cEW%c", encode(i+i),encode(j+j)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); if (E(i,j)) { printf("%cEW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j+1)); if (W(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j-1)); printf("\n"); } if (W(i,j)) { printf("%cEW%c %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j-1)); if (E(i,j)) printf(" %c%c:0", encode(i+i),encode(j+j+1)); printf("\n"); } if (E(i,j) && W(i,j)) { printf("%cEW%c %c%c:1 %c%c:1", encode(i+i),encode(j+j),encode(i+i),encode(j+j+1),encode(i+i),encode(j+j-1)); @;@+@; printf("\n"); } } @ Finally we need to identify the clues, if any, that are relevant in each of the four quadrants of tile $(i,j)$. @= if (i>0 && j>0) { register int k=board[i-1][j-1]; if (k!='.') { if (k>='1' && k<='4') printf(" %c%c", encode(i+i-1),encode(j+j-1)); else printf(" %c", k); } } @ @= if (i>0 && j='1' && k<='4') printf(" %c%c", encode(i+i-1),encode(j+j+1)); else printf(" %c", k); } } @ @= if (i='1' && k<='4') printf(" %c%c", encode(i+i+1),encode(j+j+1)); else printf(" %c", k); } } @ @= if (i0) { register int k=board[i][j-1]; if (k!='.') { if (k>='1' && k<='4') printf(" %c%c", encode(i+i+1),encode(j+j-1)); else printf(" %c", k); } } @*Index.