+ sprintf(str, "%x/%d", cbp->c_combo.s, cbp->c_nframes);
+ str += strlen(str);
+ for (; tcbp = cbp->c_link[1]; cbp = cbp->c_link[0]) {
+ sprintf(str, " %s%c%x", stoc(tcbp->c_vertex), pdir[tcbp->c_dir],
+ cbp->c_flg);
+ str += strlen(str);
+ }
+ sprintf(str, " %s%c", stoc(cbp->c_vertex), pdir[cbp->c_dir]);
+}
+
+#ifdef DEBUG
+markcombo(ocbp)
+ struct combostr *ocbp;
+{
+ struct combostr *cbp, *tcbp, **cbpp;
+ struct elist *ep, *nep, **epp;
+ struct spotstr *sp;
+ int s, d, m, i;
+ int nframes;
+ int r, n, flg, cmask, omask;
+
+ /* should never happen but check anyway */
+ if ((nframes = ocbp->c_nframes) >= MAXDEPTH)
+ return;
+
+ /*
+ * The lower level combo can be pointed to by more than one
+ * higher level 'struct combostr' so we can't modify the
+ * lower level. Therefore, higher level combos store the
+ * real mask of the lower level frame in c_emask[0] and the
+ * frame number in c_frameindex.
+ *
+ * First we traverse the tree from top to bottom and save the
+ * connection info. Then we traverse the tree from bottom to
+ * top overwriting lower levels with the newer emask information.
+ */
+ ep = &einfo[nframes];
+ cbpp = &ecombo[nframes];
+ for (cbp = ocbp; tcbp = cbp->c_link[1]; cbp = cbp->c_link[0]) {
+ ep--;
+ ep->e_combo = cbp;
+ *--cbpp = cbp->c_link[1];
+ ep->e_off = cbp->c_voff[1];
+ ep->e_frameindex = cbp->c_frameindex;
+ ep->e_fval.s = cbp->c_linkv[1].s;
+ ep->e_framecnt = cbp->c_framecnt[1];
+ ep->e_emask = cbp->c_emask[1];
+ }
+ cbp = ep->e_combo;
+ ep--;
+ ep->e_combo = cbp;
+ *--cbpp = cbp->c_link[0];
+ ep->e_off = cbp->c_voff[0];
+ ep->e_frameindex = 0;
+ ep->e_fval.s = cbp->c_linkv[0].s;
+ ep->e_framecnt = cbp->c_framecnt[0];
+ ep->e_emask = cbp->c_emask[0];
+
+ /* now update the emask info */
+ s = 0;
+ for (i = 2, ep += 2; i < nframes; i++, ep++) {
+ cbp = ep->e_combo;
+ nep = &einfo[ep->e_frameindex];
+ nep->e_framecnt = cbp->c_framecnt[0];
+ nep->e_emask = cbp->c_emask[0];
+
+ if (cbp->c_flg & C_LOOP) {
+ s++;
+ /*
+ * Account for the fact that this frame connects
+ * to a previous one (thus forming a loop).
+ */
+ nep = &einfo[cbp->c_dir];
+ if (--nep->e_framecnt)
+ nep->e_emask &= ~(1 << cbp->c_voff[0]);
+ else
+ nep->e_emask = 0;
+ }
+ }
+
+ /*
+ * We only need to update the emask values of "complete" loops
+ * to include the intersection spots.
+ */
+ if (s && ocbp->c_combo.c.a == 2) {
+ /* process loops from the top down */
+ ep = &einfo[nframes];
+ do {
+ ep--;
+ cbp = ep->e_combo;
+ if (!(cbp->c_flg & C_LOOP))
+ continue;
+
+ /*
+ * Update the emask values to include the
+ * intersection spots.
+ */
+ nep = &einfo[cbp->c_dir];
+ nep->e_framecnt = 1;
+ nep->e_emask = 1 << cbp->c_voff[0];
+ ep->e_framecnt = 1;
+ ep->e_emask = 1 << ep->e_off;
+ ep = &einfo[ep->e_frameindex];
+ do {
+ ep->e_framecnt = 1;
+ ep->e_emask = 1 << ep->e_off;
+ ep = &einfo[ep->e_frameindex];
+ } while (ep > nep);
+ } while (ep != einfo);
+ }
+
+ /* mark all the frames with the completion spots */
+ for (i = 0, ep = einfo, cbpp = ecombo; i < nframes; i++, ep++, cbpp++) {
+ m = ep->e_emask;
+ cbp = *cbpp;
+ sp = &board[cbp->c_vertex];
+ d = dd[s = cbp->c_dir];
+ cmask = CFLAG << s;
+ omask = (IFLAG | CFLAG) << s;
+ s = ep->e_fval.c.b ? 6 : 5;
+ for (; --s >= 0; sp += d, m >>= 1)
+ sp->s_flg |= (m & 1) ? omask : cmask;