/* Do smoothness scaling check & return results */ static double do_stest( int verb, /* Verbosity */ int di, /* Dimensions */ int its, /* Number of function tests */ int res /* RSPL grid resolution */ ) { funcp fp; /* Function parameters */ DCOUNT(gc, MXDIDO, di, 1, 1, res-1); int it; double atse = 0.0; /* Make repeatable by setting random seed before a test set. */ rand32(0x12345678); for (it = 0; it < its; it++) { double tse; setup_func(&fp, di); /* New function */ DC_INIT(gc) tse = 0.0; for (; !DC_DONE(gc);) { double g[MXDI]; int e, k; double y1, y2, y3; double del; for (e = 0; e < di; e++) g[e] = gc[e]/(res-1.0); y2 = lookup_func(&fp, g); del = 1.0/(res-1.0); for (k = 0 ; k < di; k++) { double err; g[k] -= del; y1 = lookup_func(&fp, g); g[k] += 2.0 * del; y3 = lookup_func(&fp, g); g[k] -= del; err = 0.5 * (y3 + y1) - y2; tse += err * err; } DC_INC(gc); } /* Apply adjustments and corrections */ tse *= pow((res-1.0), 4.0); /* Aprox. geometric resolution factor */ tse /= pow((res-2.0),(double)di); /* Average squared non-smoothness */ if (verb) printf("smf for it %d = %f\n",it,tse); atse += tse; } return atse/(double)its; }
/* device space "fold-over" */ static void diag_gamut( icxLuBase *p, /* Lookup object */ double detail, /* Gamut resolution detail */ int doaxes, /* Do Lab axes */ double tlimit, /* Total ink limit */ double klimit, /* K ink limit */ char *outname /* Output VRML file */ ) { int i, j; FILE *wrl; struct { double x, y, z; double wx, wy, wz; double r, g, b; } axes[5] = { { 0, 0, 50-GAMUT_LCENT, 2, 2, 100, .7, .7, .7 }, /* L axis */ { 50, 0, 0-GAMUT_LCENT, 100, 2, 2, 1, 0, 0 }, /* +a (red) axis */ { 0, -50, 0-GAMUT_LCENT, 2, 100, 2, 0, 0, 1 }, /* -b (blue) axis */ { -50, 0, 0-GAMUT_LCENT, 100, 2, 2, 0, 1, 0 }, /* -a (green) axis */ { 0, 50, 0-GAMUT_LCENT, 2, 100, 2, 1, 1, 0 }, /* +b (yellow) axis */ }; int vix; /* Vertex index */ DCOUNT(coa, MXDI, p->inputChan, 0, 0, 2); double col[1 << MXDI][3]; /* Color asigned to each major vertex */ int res; if (tlimit < 0.0) tlimit = p->inputChan; if (klimit < 0.0) klimit = 1.0; /* Asign some colors to the combination nodes */ for (i = 0; i < (1 << p->inputChan); i++) { int a, b, c, j; double h; j = (i ^ 0x5a5a5a5a) % (1 << p->inputChan); h = (double)j/((1 << p->inputChan)-1); /* Make fully saturated with chosen hue */ if (h < 1.0/3.0) { a = 0; b = 1; c = 2; } else if (h < 2.0/3.0) { a = 1; b = 2; c = 0; h -= 1.0/3.0; } else { a = 2; b = 0; c = 1; h -= 2.0/3.0; } h *= 3.0; col[i][a] = (1.0 - h); col[i][b] = h; col[i][c] = d_rand(0.0, 1.0); } if (detail > 0.0) res = (int)(100.0/detail); /* Establish an appropriate sampling density */ else res = 4; if (res < 2) res = 2; if ((wrl = fopen(outname,"w")) == NULL) error("Error opening wrl output file '%s'",outname); /* Spit out a VRML 2 Object surface of gamut */ fprintf(wrl,"#VRML V2.0 utf8\n"); fprintf(wrl,"\n"); fprintf(wrl,"# Created by the Argyll CMS\n"); fprintf(wrl,"Transform {\n"); fprintf(wrl,"children [\n"); fprintf(wrl," NavigationInfo {\n"); fprintf(wrl," type \"EXAMINE\" # It's an object we examine\n"); fprintf(wrl," } # We'll add our own light\n"); fprintf(wrl,"\n"); fprintf(wrl," DirectionalLight {\n"); fprintf(wrl," direction 0 0 -1 # Light illuminating the scene\n"); fprintf(wrl," direction 0 -1 0 # Light illuminating the scene\n"); fprintf(wrl," }\n"); fprintf(wrl,"\n"); fprintf(wrl," Viewpoint {\n"); fprintf(wrl," position 0 0 340 # Position we view from\n"); fprintf(wrl," }\n"); fprintf(wrl,"\n"); if (doaxes != 0) { fprintf(wrl,"# Lab axes as boxes:\n"); for (i = 0; i < 5; i++) { fprintf(wrl,"Transform { translation %f %f %f\n", axes[i].x, axes[i].y, axes[i].z); fprintf(wrl,"\tchildren [\n"); fprintf(wrl,"\t\tShape{\n"); fprintf(wrl,"\t\t\tgeometry Box { size %f %f %f }\n", axes[i].wx, axes[i].wy, axes[i].wz); fprintf(wrl,"\t\t\tappearance Appearance { material Material "); fprintf(wrl,"{ diffuseColor %f %f %f} }\n", axes[i].r, axes[i].g, axes[i].b); fprintf(wrl,"\t\t}\n"); fprintf(wrl,"\t]\n"); fprintf(wrl,"}\n"); } fprintf(wrl,"\n"); } fprintf(wrl," Transform {\n"); fprintf(wrl," translation 0 0 0\n"); fprintf(wrl," children [\n"); fprintf(wrl," Shape { \n"); fprintf(wrl," geometry IndexedFaceSet {\n"); fprintf(wrl," solid FALSE\n"); /* Don't back face cull */ fprintf(wrl," convex TRUE\n"); fprintf(wrl,"\n"); fprintf(wrl," coord Coordinate { \n"); fprintf(wrl," point [ # Verticy coordinates\n"); /* Itterate over all the faces in the device space */ /* generating the vertx positions. */ DC_INIT(coa); vix = 0; while(!DC_DONE(coa)) { int e, m1, m2; double in[MXDI]; double inl[MXDI]; double out[3]; double sum; /* Scan only device surface */ for (m1 = 0; m1 < p->inputChan; m1++) { if (coa[m1] != 0) continue; for (m2 = m1 + 1; m2 < p->inputChan; m2++) { int x, y; if (coa[m2] != 0) continue; for (e = 0; e < p->inputChan; e++) in[e] = (double)coa[e]; /* Base value */ /* Scan over 2D device space face */ for (x = 0; x < res; x++) { /* step over surface */ in[m1] = x/(res - 1.0); for (y = 0; y < res; y++) { in[m2] = y/(res - 1.0); for (sum = 0.0, e = 0; e < p->inputChan; e++) { sum += inl[e] = in[e]; } if (sum >= tlimit) { for (e = 0; e < p->inputChan; e++) inl[e] *= tlimit/sum; } if (p->inputChan >= 3 && inl[3] >= klimit) inl[3] = klimit; p->lookup(p, out, inl); fprintf(wrl,"%f %f %f,\n",out[1], out[2], out[0]-50.0); vix++; } } } } /* Increment index within block */ DC_INC(coa); } fprintf(wrl," ]\n"); fprintf(wrl," }\n"); fprintf(wrl,"\n"); fprintf(wrl," coordIndex [ # Indexes of poligon Verticies \n"); /* Itterate over all the faces in the device space */ /* generating the quadrilateral indexes. */ DC_INIT(coa); vix = 0; while(!DC_DONE(coa)) { int e, m1, m2; double in[MXDI]; /* Scan only device surface */ for (m1 = 0; m1 < p->inputChan; m1++) { if (coa[m1] != 0) continue; for (m2 = m1 + 1; m2 < p->inputChan; m2++) { int x, y; if (coa[m2] != 0) continue; for (e = 0; e < p->inputChan; e++) in[e] = (double)coa[e]; /* Base value */ /* Scan over 2D device space face */ /* Only output quads under the total ink limit */ /* Scan over 2D device space face */ for (x = 0; x < res; x++) { /* step over surface */ for (y = 0; y < res; y++) { if (x < (res-1) && y < (res-1)) { fprintf(wrl,"%d, %d, %d, %d, -1\n", vix, vix + 1, vix + 1 + res, vix + res); } vix++; } } } } /* Increment index within block */ DC_INC(coa); } fprintf(wrl," ]\n"); fprintf(wrl,"\n"); fprintf(wrl," colorPerVertex TRUE\n"); fprintf(wrl," color Color {\n"); fprintf(wrl," color [ # RGB colors of each vertex\n"); /* Itterate over all the faces in the device space */ /* generating the vertx colors. */ DC_INIT(coa); vix = 0; while(!DC_DONE(coa)) { int e, m1, m2; double in[MXDI]; /* Scan only device surface */ for (m1 = 0; m1 < p->inputChan; m1++) { if (coa[m1] != 0) continue; for (m2 = m1 + 1; m2 < p->inputChan; m2++) { int x, y; if (coa[m2] != 0) continue; for (e = 0; e < p->inputChan; e++) in[e] = (double)coa[e]; /* Base value */ /* Scan over 2D device space face */ for (x = 0; x < res; x++) { /* step over surface */ double xb = x/(res - 1.0); for (y = 0; y < res; y++) { int v0, v1, v2, v3; double yb = y/(res - 1.0); double rgb[3]; for (v0 = 0, e = 0; e < p->inputChan; e++) v0 |= coa[e] ? (1 << e) : 0; /* Binary index */ v1 = v0 | (1 << m2); /* Y offset */ v2 = v0 | (1 << m2) | (1 << m1); /* X+Y offset */ v3 = v0 | (1 << m1); /* Y offset */ /* Linear interp between the main verticies */ for (j = 0; j < 3; j++) { rgb[j] = (1.0 - yb) * (1.0 - xb) * col[v0][j] + yb * (1.0 - xb) * col[v1][j] + (1.0 - yb) * xb * col[v3][j] + yb * xb * col[v2][j]; } fprintf(wrl,"%f %f %f,\n",rgb[1], rgb[2], rgb[0]); vix++; } } } } /* Increment index within block */ DC_INC(coa); } fprintf(wrl," ] \n"); fprintf(wrl," }\n"); fprintf(wrl," }\n"); fprintf(wrl," appearance Appearance { \n"); fprintf(wrl," material Material {\n"); fprintf(wrl," transparency 0.0\n"); fprintf(wrl," ambientIntensity 0.3\n"); fprintf(wrl," shininess 0.5\n"); fprintf(wrl," }\n"); fprintf(wrl," }\n"); fprintf(wrl," } # end Shape\n"); fprintf(wrl," ]\n"); fprintf(wrl," }\n"); fprintf(wrl,"\n"); fprintf(wrl," ] # end of children for world\n"); fprintf(wrl,"}\n"); if (fclose(wrl) != 0) error("Error closing output file '%s'",outname); }
/* Return NULL on error, check errc+err for reason */ static gamut *icxLuMatrixGamut( icxLuBase *plu, /* this */ double detail /* gamut detail level, 0.0 = def */ ) { xicc *p = plu->pp; /* parent xicc */ icxLuMatrix *lumat = (icxLuMatrix *)plu; /* Lookup xMatrix type object */ icColorSpaceSignature pcs; icmLookupFunc func; double white[3], black[3], kblack[3]; gamut *gam; int res; /* Sample point resolution */ int i, e; if (detail == 0.0) detail = 10.0; /* get some details */ plu->spaces(plu, NULL, NULL, NULL, NULL, NULL, NULL, &func, &pcs); if (func != icmFwd && func != icmBwd) { p->errc = 1; sprintf(p->err,"Creating Gamut surface for anything other than Device <-> PCS is not supported."); return NULL; } if (pcs != icSigLabData && pcs != icxSigJabData) { p->errc = 1; sprintf(p->err,"Creating Gamut surface PCS of other than Lab or Jab is not supported."); return NULL; } gam = new_gamut(detail, pcs == icxSigJabData, 0); /* Explore the gamut by itterating through */ /* it with sample points in device space. */ res = (int)(600.0/detail); /* Establish an appropriate sampling density */ if (res < 40) res = 40; /* Since matrix profiles can't be non-monotonic, */ /* just itterate through the surface colors. */ for (i = 0; i < 3; i++) { int co[3]; int ep[3]; int co_e = 0; for (e = 0; e < 3; e++) { co[e] = 0; ep[e] = res; } ep[i] = 2; while (co_e < 3) { double in[3]; double out[3]; for (e = 0; e < 3; e++) /* Convert count to input value */ in[e] = co[e]/(ep[e]-1.0); /* Always use the device->PCS conversion */ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1) error ("%d, %s",p->errc,p->err); gam->expand(gam, out); /* Increment the counter */ for (co_e = 0; co_e < 3; co_e++) { co[co_e]++; if (co[co_e] < ep[co_e]) break; /* No carry */ co[co_e] = 0; } } } #ifdef NEVER /* Try it twice */ for (i = 0; i < 3; i++) { int co[3]; int ep[3]; int co_e = 0; for (e = 0; e < 3; e++) { co[e] = 0; ep[e] = res; } ep[i] = 2; while (co_e < 3) { double in[3]; double out[3]; for (e = 0; e < 3; e++) /* Convert count to input value */ in[e] = co[e]/(ep[e]-1.0); /* Always use the device->PCS conversion */ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1) error ("%d, %s",p->errc,p->err); gam->expand(gam, out); /* Increment the counter */ for (co_e = 0; co_e < 3; co_e++) { co[co_e]++; if (co[co_e] < ep[co_e]) break; /* No carry */ co[co_e] = 0; } } } #endif #ifdef NEVER // (doesn't seem to make much difference) /* run along the primary ridges in more detail too */ /* just itterate through the surface colors. */ for (i = 0; i < 3; i++) { int j; double in[3]; double out[3]; res *= 4; for (j = 0; j < res; j++) { double vv = i/(res-1.0); in[0] = in[1] = in[2] = vv; in[i] = 0.0; if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1) error ("%d, %s",p->errc,p->err); gam->expand(gam, out); in[0] = in[1] = in[2] = 0.0; in[i] = vv; if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1) error ("%d, %s",p->errc,p->err); gam->expand(gam, out); } } #endif /* Put the white and black points in the gamut */ plu->efv_wh_bk_points(plu, white, black, kblack); gam->setwb(gam, white, black, kblack); /* set the cusp points by itterating through the 0 & 100% colorant combinations */ { DCOUNT(co, 3, 3, 0, 0, 2); gam->setcusps(gam, 0, NULL); DC_INIT(co); while(!DC_DONE(co)) { int e; double in[3]; double out[3]; if (!(co[0] == 0 && co[1] == 0 && co[2] == 0) && !(co[0] == 1 && co[1] == 1 && co[2] == 1)) { /* Skip white and black */ for (e = 0; e < 3; e++) in[e] = (double)co[e]; /* Always use the device->PCS conversion */ if (lumat->fwd_lookup((icxLuBase *)lumat, out, in) > 1) error ("%d, %s",p->errc,p->err); gam->setcusps(gam, 3, out); } DC_INC(co); } gam->setcusps(gam, 2, NULL); } #ifdef NEVER /* Not sure if this is a good idea ?? */ gam->getwb(gam, NULL, NULL, white, black); /* Get the actual gamut white and black points */ gam->setwb(gam, white, black); /* Put it back as colorspace one */ #endif return gam; }
/* Do a reverse lookup on the mpp */ static void mpp_rev( mpp *mppo, double limit, /* Ink limit */ double *out, /* Device value */ double *in /* Lab target */ ) { int i, j; inkmask imask; /* Device Ink mask */ int inn; revlus rs; /* Reverse lookup structure */ double sr[MAX_CHAN]; /* Search radius */ double tt; /* !!! This needs to be cached elsewhere !!!! */ static saent *start = NULL; /* Start array */ static int nisay = 0; /* Number in start array */ mppo->get_info(mppo, &imask, &inn, NULL, NULL, NULL, NULL, NULL); rs.di = inn; /* Number of device channels */ rs.Lab[0] = in[0]; /* Target PCS value */ rs.Lab[1] = in[1]; rs.Lab[2] = in[2]; rs.dev2lab = mppo->lookup; /* Dev->PCS Lookup function and context */ rs.d2lcntx = (void *)mppo; rs.ilimit = limit; /* Total ink limit */ { double Labw[3]; /* Lab value of white */ double Lab[MAX_CHAN][3]; /* Lab value of device primaries */ double min, max; /* Lookup the L value of all the device primaries */ for (j = 0; j < inn; j++) out[j] = 0.0; mppo->lookup(mppo, Labw, out); for (i = 0; i < inn; i++) { double tt; double de; out[i] = 1.0; mppo->lookup(mppo, Lab[i], out); /* Use DE measure heavily weighted towards L only */ tt = L_WEIGHT * (Labw[0] - Lab[i][0]); de = tt * tt; tt = 0.4 * (Labw[1] - Lab[i][1]); de += tt * tt; tt = 0.2 * (Labw[2] - Lab[i][2]); de += tt * tt; rs.oweight[i] = sqrt(de); out[i] = 0.0; } /* Normalise weights from 0 .. 1.0 */ min = 1e6, max = 0.0; for (j = 0; j < inn; j++) { if (rs.oweight[j] < min) min = rs.oweight[j]; if (rs.oweight[j] > max) max = rs.oweight[j]; } for (j = 0; j < inn; j++) rs.oweight[j] = (rs.oweight[j] - min)/(max - min); { for (j = 0; j < inn; j++) rs.sord[j] = j; for (i = 0; i < (inn-1); i++) { for (j = i+1; j < inn; j++) { if (rs.oweight[rs.sord[i]] > rs.oweight[rs.sord[j]]) { int xx; xx = rs.sord[i]; rs.sord[i] = rs.sord[j]; rs.sord[j] = xx; } } } } for (j = 0; j < inn; j++) printf("~1 oweight[%d] = %f\n",j,rs.oweight[j]); for (j = 0; j < inn; j++) printf("~1 sorted oweight[%d] = %f\n",j,rs.oweight[rs.sord[j]]); } /* Initialise the start point array */ if (start == NULL) { int mxstart; int steps = 4; DCOUNT(dix, MAX_CHAN, inn, 0, 0, steps); printf("~1 initing start point array\n"); for (mxstart = 1, j = 0; j < inn; j++) /* Compute maximum entries */ mxstart *= steps; printf("~1 mxstart = %d\n",mxstart); if ((start = malloc(sizeof(saent) * mxstart)) == NULL) error("mpp_rev malloc of start array failed\n"); nisay = 0; DC_INIT(dix); while(!DC_DONE(dix)) { double sum = 0.0; /* Figure device values */ for (j = 0; j < inn; j++) { sum += start[nisay].dev[j] = dix[j]/(steps-1.0); } if (sum <= limit) { /* Within ink limit */ double oerr; double tot; /* Compute Lab */ mppo->lookup(mppo, start[nisay].Lab, start[nisay].dev); /* Compute order error */ /* Skip first 3 colorants */ oerr = tot = 0.0; for (j = 3; j < inn; j++) { int ix = rs.sord[j]; /* Sorted order index */ double vv = start[nisay].dev[ix]; double we = (double)j - 2.0; /* Increasing weight */ if (vv > 0.0001) { oerr += tot + we * vv; } tot += we; } oerr /= tot; start[nisay].oerr = oerr; nisay++; } DC_INC(dix); } printf("~1 start point array done, %d out of %d valid\n",nisay,mxstart); } /* Search the start array for closest matching point */ { double bde = 1e38; int bix = 0; for (i = 0; i < nisay; i++) { double de; /* Compute delta E */ for (de = 0.0, j = 0; j < 3; j++) { double tt = rs.Lab[j] - start[i].Lab[j]; de += tt * tt; } de += 0.0 * start[i].oerr; if (de < bde) { bde = de; bix = i; } } printf("Start point at index %d, bde = %f, dev = ",bix,bde); for (j = 0; j < inn; j++) { printf("%f",start[bix].dev[j]); if (j < (inn-1)) printf(" "); } printf("\n"); for (j = 0; j < inn; j++) { out[j] = start[bix].dev[j]; sr[j] = 0.1; } } #ifdef NEVER out[0] = 0.0; out[1] = 0.0; out[2] = 0.45; out[3] = 0.0; out[4] = 0.0; out[5] = 0.0; out[6] = 0.6; out[7] = 1.0; #endif #ifdef NEVER out[0] = 1.0; out[1] = 0.0; out[2] = 0.0; out[3] = 0.0; out[4] = 0.0; out[5] = 0.0; out[6] = 0.0; out[7] = 0.0; #endif #ifdef NEVER rs.pass = 0; if (powell(&tt, inn, out, sr, 0.001, 5000, revoptfunc, (void *)&rs) != 0) { error("Powell failed inside mpp_rev()"); } printf("\n\n\n\n\n\n#############################################\n"); printf("~1 after first pass got "); for (j = 0; j < inn; j++) { printf("%f",out[j]); if (j < (inn-1)) printf(" "); } printf("\n"); printf("#############################################\n\n\n\n\n\n\n\n"); #endif #ifndef NEVER out[0] = 0.0; out[1] = 0.0; out[2] = 0.0; out[3] = 0.0; out[4] = 0.0; out[5] = 1.0; out[6] = 0.0; out[7] = 0.0; #endif #ifndef NEVER rs.pass = 1; if (powell(&tt, inn, out, sr, 0.00001, 5000, revoptfunc, (void *)&rs, NULL, NULL) != 0) { error("Powell failed inside mpp_rev()"); } #endif snap2gamut(&rs, out); }
/* * Returns 0, 1 or 2 for number of solutions. 2 means `any number * more than one', or more accurately `we were unable to prove * there was only one'. * * Outputs in a `placements' array, indexed the same way as the one * within this function (see below); entries in there are <0 for a * placement ruled out, 0 for an uncertain placement, and 1 for a * definite one. */ static int solver(int w, int h, int n, int *grid, int *output) { int wh = w*h, dc = DCOUNT(n); int *placements, *heads; int i, j, x, y, ret; /* * This array has one entry for every possible domino * placement. Vertical placements are indexed by their top * half, at (y*w+x)*2; horizontal placements are indexed by * their left half at (y*w+x)*2+1. * * This array is used to link domino placements together into * linked lists, so that we can track all the possible * placements of each different domino. It's also used as a * quick means of looking up an individual placement to see * whether we still think it's possible. Actual values stored * in this array are -2 (placement not possible at all), -1 * (end of list), or the array index of the next item. * * Oh, and -3 for `not even valid', used for array indices * which don't even represent a plausible placement. */ placements = snewn(2*wh, int); for (i = 0; i < 2*wh; i++) placements[i] = -3; /* not even valid */ /* * This array has one entry for every domino, and it is an * index into `placements' denoting the head of the placement * list for that domino. */ heads = snewn(dc, int); for (i = 0; i < dc; i++) heads[i] = -1; /* * Set up the initial possibility lists by scanning the grid. */ for (y = 0; y < h-1; y++) for (x = 0; x < w; x++) { int di = DINDEX(grid[y*w+x], grid[(y+1)*w+x]); placements[(y*w+x)*2] = heads[di]; heads[di] = (y*w+x)*2; } for (y = 0; y < h; y++) for (x = 0; x < w-1; x++) { int di = DINDEX(grid[y*w+x], grid[y*w+(x+1)]); placements[(y*w+x)*2+1] = heads[di]; heads[di] = (y*w+x)*2+1; } #ifdef SOLVER_DIAGNOSTICS printf("before solver:\n"); for (i = 0; i <= n; i++) for (j = 0; j <= i; j++) { int k, m; m = 0; printf("%2d [%d %d]:", DINDEX(i, j), i, j); for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k]) printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v'); printf("\n"); } #endif while (1) { int done_something = FALSE; /* * For each domino, look at its possible placements, and * for each placement consider the placements (of any * domino) it overlaps. Any placement overlapped by all * placements of this domino can be ruled out. * * Each domino placement overlaps only six others, so we * need not do serious set theory to work this out. */ for (i = 0; i < dc; i++) { int permset[6], permlen = 0, p; if (heads[i] == -1) { /* no placement for this domino */ ret = 0; /* therefore puzzle is impossible */ goto done; } for (j = heads[i]; j >= 0; j = placements[j]) { assert(placements[j] != -2); if (j == heads[i]) { permlen = find_overlaps(w, h, j, permset); } else { int tempset[6], templen, m, n, k; templen = find_overlaps(w, h, j, tempset); /* * Pathetically primitive set intersection * algorithm, which I'm only getting away with * because I know my sets are bounded by a very * small size. */ for (m = n = 0; m < permlen; m++) { for (k = 0; k < templen; k++) if (tempset[k] == permset[m]) break; if (k < templen) permset[n++] = permset[m]; } permlen = n; } } for (p = 0; p < permlen; p++) { j = permset[p]; if (placements[j] != -2) { int p1, p2, di; done_something = TRUE; /* * Rule out this placement. First find what * domino it is... */ p1 = j / 2; p2 = (j & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); #ifdef SOLVER_DIAGNOSTICS printf("considering domino %d: ruling out placement %d" " for %d\n", i, j, di); #endif /* * ... then walk that domino's placement list, * removing this placement when we find it. */ if (heads[di] == j) heads[di] = placements[j]; else { int k = heads[di]; while (placements[k] != -1 && placements[k] != j) k = placements[k]; assert(placements[k] == j); placements[k] = placements[j]; } placements[j] = -2; } } } /* * For each square, look at the available placements * involving that square. If all of them are for the same * domino, then rule out any placements for that domino * _not_ involving this square. */ for (i = 0; i < wh; i++) { int list[4], k, n, adi; x = i % w; y = i / w; j = 0; if (x > 0) list[j++] = 2*(i-1)+1; if (x+1 < w) list[j++] = 2*i+1; if (y > 0) list[j++] = 2*(i-w); if (y+1 < h) list[j++] = 2*i; for (n = k = 0; k < j; k++) if (placements[list[k]] >= -1) list[n++] = list[k]; adi = -1; for (j = 0; j < n; j++) { int p1, p2, di; k = list[j]; p1 = k / 2; p2 = (k & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); if (adi == -1) adi = di; if (adi != di) break; } if (j == n) { int nn; assert(adi >= 0); /* * We've found something. All viable placements * involving this square are for domino `adi'. If * the current placement list for that domino is * longer than n, reduce it to precisely this * placement list and we've done something. */ nn = 0; for (k = heads[adi]; k >= 0; k = placements[k]) nn++; if (nn > n) { done_something = TRUE; #ifdef SOLVER_DIAGNOSTICS printf("considering square %d,%d: reducing placements " "of domino %d\n", x, y, adi); #endif /* * Set all other placements on the list to * impossible. */ k = heads[adi]; while (k >= 0) { int tmp = placements[k]; placements[k] = -2; k = tmp; } /* * Set up the new list. */ heads[adi] = list[0]; for (k = 0; k < n; k++) placements[list[k]] = (k+1 == n ? -1 : list[k+1]); } } } if (!done_something) break; } #ifdef SOLVER_DIAGNOSTICS printf("after solver:\n"); for (i = 0; i <= n; i++) for (j = 0; j <= i; j++) { int k, m; m = 0; printf("%2d [%d %d]:", DINDEX(i, j), i, j); for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k]) printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v'); printf("\n"); } #endif ret = 1; for (i = 0; i < wh*2; i++) { if (placements[i] == -2) { if (output) output[i] = -1; /* ruled out */ } else if (placements[i] != -3) { int p1, p2, di; p1 = i / 2; p2 = (i & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); if (i == heads[di] && placements[i] == -1) { if (output) output[i] = 1; /* certain */ } else { if (output) output[i] = 0; /* uncertain */ ret = 2; } } } done: /* * Free working data. */ sfree(placements); sfree(heads); return ret; }
int main() { listPtr List, Queue, Stack, Splay; char *String1, *String2, *String3, *String4, *Get; int Result; printf("Testing LINKLIST Library for ANSI C.\n\n"); String1 = malloc(20); String2 = malloc(20); String3 = malloc(20); String4 = malloc(20); strcpy(String1, "Hi"); strcpy(String2, "Low"); strcpy(String3, "Up"); strcpy(String4, "Down"); printf("Creating List.\n"); List = NewListAlloc(LIST, DMALLOC, DFREE, (NodeCompareFunc)strcmp); printf("Creating Queue.\n"); Queue = NewListAlloc(QUEUE, DMALLOC, DFREE, NULL); printf("Creating Stack.\n"); Stack = NewListAlloc(STACK, DMALLOC, DFREE, NULL); printf("Creating Splay Tree\n"); Splay = NewListAlloc(STREE, DMALLOC, DFREE, (NodeCompareFunc)StringCompare); printf("Adding Elements to List...\n"); AddNode(List, NewNode("Hi")); AddNode(List, NewNode("Low")); AddNode(List, NewNode("Up")); AddNode(List, NewNode("Down")); printf("Adding Elements to Queue...\n"); AddNode(Queue, NewNode("Hi")); AddNode(Queue, NewNode("Low")); AddNode(Queue, NewNode("Up")); AddNode(Queue, NewNode("Down")); printf("Adding Elements to Stack...\n"); AddNode(Stack, NewNode(String1)); AddNode(Stack, NewNode(String2)); AddNode(Stack, NewNode(String3)); AddNode(Stack, NewNode(String4)); printf("Adding Elements to Splay Tree...\n"); AddNode(Splay, NewNode("High")); AddNode(Splay, NewNode("Low")); AddNode(Splay, NewNode("Up")); AddNode(Splay, NewNode("Down")); printf("Attempting to add duplicate nodes to Splay Tree...\n"); Result = AddNode(Splay, NewNode("Down")); printf("Result: "); if (Result == LLIST_OK) printf("OK\n"); else if (Result == LLIST_BADVALUE) printf("Node Already Exists; not added\n"); else printf("Error\n"); printf("Calimed Memory: %d bytes\n", DCOUNT(NULL)); printf("LIST:\n"); PrintList(List, "%s"); printf("QUEUE:\n"); PrintList(Queue, "%s"); printf("STACK:\n"); PrintList(Stack, "%s"); printf("SPLAY:\n"); PrintList(Splay, "%s"); printf("\n-----------------------\n"); printf("Reading Element from LIST\n"); printf("Read Element: %s\n", GetNode(List)); PrintList(List, "%s"); printf("\n\nReading Element from QUEUE\n"); printf("Read Element: %s\n", GetNode(Queue)); PrintList(Queue, "%s"); printf("\n\nReading Element from STACK\n"); printf("Read Element: %s\n", (Get = GetNode(Stack))); DFREE(Get); PrintList(Stack, "%s"); printf("\n-----------------------\n"); printf("Reading Element #2 from LIST\n"); printf("Read Element: %s\n", IndexNode(List, 2)); PrintList(List, "%s"); printf("\nAdding One More Element to LIST\n"); AddNode(List, NewNode("And")); PrintList(List, "%s"); printf("\n-----------------------\n"); printf("\nSorting LIST\n"); SortList(List); PrintList(List, "%s"); printf("\n-----------------------\n"); printf("\nDeleting Element 2 From LIST\n"); IndexNode(List, 2); RemoveList(List); PrintList(List, "%s"); printf("\nDeleting Head From LIST\n"); DelHeadList(List); PrintList(List, "%s"); printf("\nDeleting Tail From LIST\n"); DelTailList(List); PrintList(List, "%s"); printf("\n------------------------\n"); printf("Reading Element from Splay Tree\n"); printf("Read Element: %s\n", GetNode(Splay)); printf("\nDeleting Element From Splay Tree\n"); DelNode(Splay); PrintList(Splay, "%s"); printf("\nDeleting Element \"Low\" In Splay Tree\n"); FindNode(Splay, "Low"); DelNode(Splay); PrintList(Splay, "%s"); printf("Reading Element from Splay Tree\n"); printf("Read Element: %s\n", GetNode(Splay)); printf("\n-----------------------\n"); printf("Removing List.\n"); FreeList(List, NULL); printf("Removing Queue.\n"); FreeList(Queue, NULL); printf("Removing Stack.\n"); FreeList(Stack, NULL); printf("Removing Splay Tree.\n"); FreeList(Splay, NULL); printf("\n-----------------------\n"); printf("\nUnclaimed Memory: %d bytes\n", DCOUNT(NULL)); printf("\nLinkList Test/Demo Done.\n"); return 0; } /* main */