home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <io.h>
- #include "cell.h"
-
- /*
- ** visit neighboring cells like this (where [9] is on the other side):
- **
- ** +---+---+---+
- ** | 1 | 2 | 3 |
- ** +---+---+---+
- ** | 4 |[9]| 5 |
- ** +---+---+---+
- ** | 6 | 7 | 8 |
- ** +---+---+---+
- */
-
- static int delta[8][2] = { /* for visiting neighbors on the same side */
- { 1, -1 }, /* northwest */
- { 1, 0 }, /* north */
- { 1, 1 }, /* northeast */
- { 0, -1 }, /* west */
- { 0, 1 }, /* east */
- { -1, -1 }, /* southwest */
- { -1, 0 }, /* south */
- { -1, 1 } /* southeast */
- };
-
- static int ndir[8] = { /* for building paths back to source */
- FROM_SOUTHEAST, FROM_SOUTH, FROM_SOUTHWEST,
- FROM_EAST, FROM_WEST,
- FROM_NORTHEAST, FROM_NORTH, FROM_NORTHWEST
- };
-
- /* blocking masks for neighboring cells */
- #define BLOCK_NORTHEAST ( DIAG_NEtoSW | BENT_StoNE | BENT_WtoNE \
- | ANGLE_NEtoSE | ANGLE_NWtoNE \
- | SHARP_NtoNE | SHARP_EtoNE )
- #define BLOCK_SOUTHEAST ( DIAG_SEtoNW | BENT_NtoSE | BENT_WtoSE \
- | ANGLE_NEtoSE | ANGLE_SEtoSW \
- | SHARP_EtoSE | SHARP_StoSE )
- #define BLOCK_SOUTHWEST ( DIAG_NEtoSW | BENT_NtoSW | BENT_EtoSW \
- | ANGLE_SEtoSW | ANGLE_SWtoNW \
- | SHARP_StoSW | SHARP_WtoSW )
- #define BLOCK_NORTHWEST ( DIAG_SEtoNW | BENT_EtoNW | BENT_StoNW \
- | ANGLE_SWtoNW | ANGLE_NWtoNE \
- | SHARP_WtoNW | SHARP_NtoNW )
-
- struct block {
- int r1, c1;
- long b1, h1;
- int r2, c2;
- long b2, h2;
- };
-
- static struct block blocking[8] = { /* blocking masks */
- { 0, -1, BLOCK_NORTHEAST, HOLE_NORTHEAST,
- 1, 0, BLOCK_SOUTHWEST, HOLE_SOUTHWEST },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 1, 0, BLOCK_SOUTHEAST, HOLE_SOUTHEAST,
- 0, 1, BLOCK_NORTHWEST, HOLE_NORTHWEST },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, -1, BLOCK_SOUTHEAST, HOLE_SOUTHEAST,
- -1, 0, BLOCK_NORTHWEST, HOLE_NORTHWEST },
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { -1, 0, BLOCK_NORTHEAST, HOLE_NORTHEAST,
- 0, 1, BLOCK_SOUTHWEST, HOLE_SOUTHWEST }
- };
-
- static int selfok[5][8] = { /* mask for self-blocking corner effects */
- { 1, 1, 1, 1, 1, 1, 1, 1 },
- { 0, 0, 0, 0, 1, 0, 1, 0 },
- { 0, 0, 0, 1, 0, 0, 1, 0 },
- { 0, 1, 0, 0, 1, 0, 0, 0 },
- { 0, 1, 0, 1, 0, 0, 0, 0 }
- };
-
- static long newmask[5][8] = { /* patterns to mask out in neighbor cells */
- { 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, CORNER_NORTHEAST | CORNER_SOUTHEAST, 0,
- CORNER_SOUTHEAST | CORNER_SOUTHWEST, 0 },
- { 0, 0, 0, CORNER_SOUTHWEST | CORNER_NORTHWEST, 0, 0,
- CORNER_SOUTHEAST | CORNER_SOUTHWEST, 0 },
- { 0, CORNER_NORTHEAST | CORNER_NORTHWEST, 0, 0,
- CORNER_NORTHEAST | CORNER_SOUTHEAST, 0, 0, 0 },
- { 0, CORNER_NORTHEAST | CORNER_NORTHWEST, 0,
- CORNER_SOUTHWEST | CORNER_NORTHWEST, 0, 0, 0, 0 }
- };
-
- static char fmt[] =
- " open=%ld, closed=%ld, moved=%ld, max=%ld, %ld%% of board";
-
- /* board dimensions */
- extern int Nrows;
- extern int Ncols;
-
- /* measures of progress */
- int Ntotal = 0;
- int Ncurrent = 0;
-
- /* search statistics */
- extern long OpenNodes; /* total number of nodes opened */
- extern long ClosNodes; /* total number of nodes closed */
- extern long MoveNodes; /* total number of nodes moved */
- extern long MaxNodes; /* maximum number of nodes opened at one time */
-
- extern void GetWork( int *, int *, char far * far *, int *, int *,
- char far * far * );
- extern void InitQueue( void );
- extern void GetQueue( int *, int *, int *, int *, int * );
- extern void SetQueue( int, int, int, int, int, int, int );
- extern void ReSetQueue( int, int, int, int, int, int, int );
- extern long GetCell( int, int, int );
- extern void SetCell( int, int, int, long );
- extern void OrCell( int, int, int, long );
- extern int GetDir( int, int, int );
- extern void SetDir( int, int, int, int );
- extern int GetDist( int, int, int );
- extern void SetDist( int, int, int, int );
- extern int GetApxDist( int, int, int, int );
- extern int CalcDist( int, int, int );
-
- void Solve( void );
- void Retrace( int, int, int, int, int );
-
- void Solve () { /* route all traces */
- int r1, c1, r2, c2, r, c, s, d, a, nr, nc, skip;
- register int i;
- char far *n1;
- char far *n2;
- long curcell, newcell, buddy, lastopen, lastclos, lastmove;
- int newdist, olddir, success, self, echo;
-
- printf( "enter Solve()\n" );
- echo = isatty( fileno(stdout) ) ? 1 : 0;
- /* go until no more work to do */
- for (GetWork( &r1, &c1, &n1, &r2, &c2, &n2 ); r1 != ILLEGAL;
- GetWork( &r1, &c1, &n1, &r2, &c2, &n2 )) {
- Ncurrent++;
- printf( "routing %Fs=%Fs, %d of %d\n", n1, n2, Ncurrent,
- Ntotal );
- if (r1 == r2 && c1 == c2) /* trivial case; already routed */
- continue;
- success = 0;
- lastopen = lastclos = lastmove = 0;
- InitQueue(); /* initialize the search queue */
- a = GetApxDist( r1, c1, r2, c2 ); /* rough estimate */
- SetQueue( r1, c1, TOP, 0, a, r2, c2 );
- SetQueue( r1, c1, BOTTOM, 0, a, r2, c2 );
- /* search until success or we exhaust all possibilities */
- for (GetQueue( &r, &c, &s, &d, &a ); r != ILLEGAL;
- GetQueue( &r, &c, &s, &d, &a )) {
- if (r == r2 && c == c2) { /* success! */
- Retrace( r1, c1, r2, c2, s ); /* lay traces */
- success++;
- break;
- }
- /* report every 100 new nodes or so */
- if (echo && (OpenNodes - lastopen > 100
- || ClosNodes - lastclos > 100
- || MoveNodes - lastmove > 100)) {
- lastopen = (OpenNodes/100)*100;
- lastclos = (ClosNodes/100)*100;
- lastmove = (MoveNodes/100)*100;
- printf( fmt, OpenNodes, ClosNodes,
- MoveNodes, MaxNodes,
- (ClosNodes*50)/(Nrows*Ncols) );
- putchar( '\r' );
- }
- curcell = GetCell( r, c, s );
- if (curcell & CORNER_NORTHWEST)
- self = 1;
- else if (curcell & CORNER_NORTHEAST)
- self = 2;
- else if (curcell & CORNER_SOUTHWEST)
- self = 3;
- else if (curcell & CORNER_SOUTHEAST)
- self = 4;
- else
- self = 0;
- for (i = 0; i < 8; i++) { /* consider neighbors */
- if (!selfok[self][i]) /* check self-block */
- continue;
- if ((nr = r+delta[i][0]) < 0 || nr >= Nrows
- || (nc = c+delta[i][1]) < 0
- || nc >= Ncols) /* off the edge? */
- continue;
- newcell = GetCell( nr, nc, s );
- /* check for non-target hole */
- if (newcell & HOLE) {
- if (nr != r2 || nc != c2)
- continue;
- }
- else {
- newcell &= ~(newmask[self][i]);
- if (newcell) /* check for traces */
- continue;
- }
- /* check blocking on corner neighbors */
- if (delta[i][0] && delta[i][1]) {
- /* check first buddy */
- buddy = GetCell( r+blocking[i].r1,
- c+blocking[i].c1, s );
- if (buddy & HOLE) {
- if (buddy & (blocking[i].h1))
- continue;
- }
- else if (buddy & (blocking[i].b1))
- continue;
- /* check second buddy */
- buddy = GetCell( r+blocking[i].r2,
- c+blocking[i].c2, s );
- if (buddy & HOLE) {
- if (buddy & (blocking[i].h2))
- continue;
- }
- else if (buddy & (blocking[i].b2))
- continue;
- }
- olddir = GetDir( r, c, s );
- newdist = d+CalcDist( ndir[i], olddir,
- (olddir == FROM_OTHERSIDE)
- ? GetDir( r, c, 1-s ) : 0 );
- /* if not visited yet, add it to queue */
- if (!GetDir( nr, nc, s )) {
- SetDir( nr, nc, s, ndir[i] );
- SetDist( nr, nc, s, newdist );
- SetQueue( nr, nc, s, newdist,
- GetApxDist( nr, nc, r2, c2 ),
- r2, c2 );
- }
- /* we might have found a better path */
- else if (newdist < GetDist( nr, nc, s )) {
- SetDir( nr, nc, s, ndir[i] );
- SetDist( nr, nc, s, newdist );
- ReSetQueue( nr, nc, s, newdist,
- GetApxDist( nr, nc, r2, c2 ),
- r2, c2 );
- }
- }
- /* consider other side of board */
- /* check for holes or traces on other side */
- if (newcell = GetCell( r, c, 1-s ))
- continue;
- skip = 0;
- /* check for nearby holes */
- for (i = 0; i < 8; i++) {
- if ((nr = r+delta[i][0]) < 0 || nr >= Nrows
- || (nc = c+delta[i][1]) < 0
- || nc >= Ncols) /* off the edge? */
- continue;
- if (GetCell( nr, nc, s ) & HOLE) {
- skip = 1; /* neighboring hole */
- break;
- }
- }
- if (skip) /* neighboring hole? */
- continue; /* yes, can't drill one here */
- olddir = GetDir( r, c, s );
- newdist = d+CalcDist( FROM_OTHERSIDE, olddir,
- (olddir == FROM_OTHERSIDE)
- ? GetDir( r, c, 1-s ) : 0 );
- /* if not visited yet, add it to queue */
- if (!GetDir( r, c, 1-s )) {
- SetDir( r, c, 1-s, FROM_OTHERSIDE );
- SetDist( r, c, 1-s, newdist );
- SetQueue( r, c, 1-s, newdist, a, r2, c2 );
- }
- /* we might have found a better path */
- else if (newdist < GetDist( r, c, 1-s )) {
- SetDir( r, c, 1-s, FROM_OTHERSIDE );
- SetDist( r, c, 1-s, newdist );
- ReSetQueue( r, c, 1-s, newdist, a, r2, c2 );
- }
- }
- printf( fmt, OpenNodes, ClosNodes, MoveNodes, MaxNodes,
- (ClosNodes*50)/(Nrows*Ncols) );
- putchar( '\n' );
- if (!success)
- printf( "\t*!* UNSUCCESSFUL *!*\n" );
- /* clear direction flags */
- for (r = 0; r < Nrows; r++) {
- for (c = 0; c < Ncols; c++) {
- SetDir( r, c, TOP, EMPTY );
- SetDir( r, c, BOTTOM, EMPTY );
- }
- }
- }
- printf( "leave Solve()\n" );
- }
-
- static long bit[8][9] = { /* OT=Otherside */
- /* N, NE, E, SE, S, SW, W, NW, OT */
- /* N */ { LINE_VERTICAL, BENT_StoNE, CORNER_SOUTHEAST, SHARP_StoSE, 0,
- SHARP_StoSW, CORNER_SOUTHWEST, BENT_StoNW, (HOLE | HOLE_SOUTH) },
- /* NE */ { BENT_NtoSW, DIAG_NEtoSW, BENT_EtoSW, ANGLE_SEtoSW, SHARP_StoSW,
- 0, SHARP_WtoSW, ANGLE_SWtoNW, (HOLE | HOLE_SOUTHWEST) },
- /* E */ { CORNER_NORTHWEST, BENT_WtoNE, LINE_HORIZONTAL, BENT_WtoSE,
- CORNER_SOUTHWEST, SHARP_WtoSW, 0, SHARP_WtoNW, (HOLE | HOLE_WEST) },
- /* SE */ { SHARP_NtoNW, ANGLE_NWtoNE, BENT_EtoNW, DIAG_SEtoNW, BENT_StoNW,
- ANGLE_SWtoNW, SHARP_WtoNW, 0, (HOLE | HOLE_NORTHWEST) },
- /* S */ { 0, SHARP_NtoNE, CORNER_NORTHEAST, BENT_NtoSE, LINE_VERTICAL,
- BENT_NtoSW, CORNER_NORTHWEST, SHARP_NtoNW, (HOLE | HOLE_NORTH) },
- /* SW */ { SHARP_NtoNE, 0, SHARP_EtoNE, ANGLE_NEtoSE, BENT_StoNE, DIAG_NEtoSW,
- BENT_WtoNE, ANGLE_NWtoNE, (HOLE | HOLE_NORTHEAST) },
- /* W */ { CORNER_NORTHEAST, SHARP_EtoNE, 0, SHARP_EtoSE, CORNER_SOUTHEAST,
- BENT_EtoSW, LINE_HORIZONTAL, BENT_EtoNW, (HOLE | HOLE_EAST) },
- /* NW */ { BENT_NtoSE, ANGLE_NEtoSE, SHARP_EtoSE, 0, SHARP_StoSE,
- ANGLE_SEtoSW, BENT_WtoSE, DIAG_SEtoNW, (HOLE | HOLE_SOUTHEAST) }
- };
-
- void Retrace ( rr1, cc1, rr2, cc2, s )
- /* work from target back to source, actually laying the traces */
- int rr1, cc1, rr2, cc2, s; /* start on side s */
- {
- int r0, c0, s0, r1, c1, s1, r2, c2, s2;
- register int x, y;
- long b;
-
- r1 = rr2;
- c1 = cc2;
- s1 = s;
- r0 = c0 = s0 = ILLEGAL;
- do {
- /* find where we came from to get here */
- switch (x = GetDir( r2 = r1, c2 = c1, s2 = s1 )) {
- case FROM_NORTH: r2++; break;
- case FROM_EAST: c2++; break;
- case FROM_SOUTH: r2--; break;
- case FROM_WEST: c2--; break;
- case FROM_NORTHEAST: r2++; c2++; break;
- case FROM_SOUTHEAST: r2--; c2++; break;
- case FROM_SOUTHWEST: r2--; c2--; break;
- case FROM_NORTHWEST: r2++; c2--; break;
- case FROM_OTHERSIDE: s2 = 1-s2; break;
- default:
- printf( "internal error: no way back\n" );
- exit( -1 );
- break;
- }
- if (r0 != ILLEGAL)
- y = GetDir( r0, c0, s0 );
- /* see if target or hole */
- if ((r1 == rr2 && c1 == cc2) || (s1 != s0)) {
- switch (x) {
- case FROM_NORTH:
- OrCell( r1, c1, s1, HOLE_NORTH ); break;
- case FROM_EAST:
- OrCell( r1, c1, s1, HOLE_EAST ); break;
- case FROM_SOUTH:
- OrCell( r1, c1, s1, HOLE_SOUTH ); break;
- case FROM_WEST:
- OrCell( r1, c1, s1, HOLE_WEST ); break;
- case FROM_NORTHEAST:
- OrCell( r1, c1, s1, HOLE_NORTHEAST ); break;
- case FROM_SOUTHEAST:
- OrCell( r1, c1, s1, HOLE_SOUTHEAST ); break;
- case FROM_SOUTHWEST:
- OrCell( r1, c1, s1, HOLE_SOUTHWEST ); break;
- case FROM_NORTHWEST:
- OrCell( r1, c1, s1, HOLE_NORTHWEST ); break;
- case FROM_OTHERSIDE:
- default:
- printf( "internal error\n" );
- exit( -1 );
- break;
- }
- }
- else {
- if ((y == FROM_NORTH || y == FROM_NORTHEAST
- || y == FROM_EAST || y == FROM_SOUTHEAST
- || y == FROM_SOUTH || y == FROM_SOUTHWEST
- || y == FROM_WEST || y == FROM_NORTHWEST)
- && (x == FROM_NORTH || x == FROM_NORTHEAST
- || x == FROM_EAST || x == FROM_SOUTHEAST
- || x == FROM_SOUTH || x == FROM_SOUTHWEST
- || x == FROM_WEST || x == FROM_NORTHWEST
- || x == FROM_OTHERSIDE)
- && (b = bit[y-1][x-1])) {
- OrCell( r1, c1, s1, b );
- if (b & HOLE)
- OrCell( r2, c2, s2, HOLE );
- }
- else {
- printf( "internal error\n" );
- exit( -1 );
- }
- }
- if (r2 == rr1 && c2 == cc1) { /* see if source */
- switch (x) {
- case FROM_NORTH:
- OrCell( r2, c2, s2, HOLE_SOUTH ); break;
- case FROM_EAST:
- OrCell( r2, c2, s2, HOLE_WEST ); break;
- case FROM_SOUTH:
- OrCell( r2, c2, s2, HOLE_NORTH ); break;
- case FROM_WEST:
- OrCell( r2, c2, s2, HOLE_EAST ); break;
- case FROM_NORTHEAST:
- OrCell( r2, c2, s2, HOLE_SOUTHWEST ); break;
- case FROM_SOUTHEAST:
- OrCell( r2, c2, s2, HOLE_NORTHWEST ); break;
- case FROM_SOUTHWEST:
- OrCell( r2, c2, s2, HOLE_NORTHEAST ); break;
- case FROM_NORTHWEST:
- OrCell( r2, c2, s2, HOLE_SOUTHEAST ); break;
- case FROM_OTHERSIDE:
- default:
- printf( "internal error\n" );
- exit( -1 );
- break;
- }
- }
- /* move to next cell */
- r0 = r1; c0 = c1; s0 = s1;
- r1 = r2; c1 = c2; s1 = s2;
- } while (!(r2 == rr1 && c2 == cc1));
- }
-