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 | HOLE )
- #define BLOCK_SOUTHEAST ( DIAG_SEtoNW | BENT_NtoSE | BENT_WtoSE \
- | ANGLE_NEtoSE | ANGLE_SEtoSW \
- | SHARP_EtoSE | SHARP_StoSE | HOLE )
- #define BLOCK_SOUTHWEST ( DIAG_NEtoSW | BENT_NtoSW | BENT_EtoSW \
- | ANGLE_SEtoSW | ANGLE_SWtoNW \
- | SHARP_StoSW | SHARP_WtoSW | HOLE )
- #define BLOCK_NORTHWEST ( DIAG_SEtoNW | BENT_EtoNW | BENT_StoNW \
- | ANGLE_SWtoNW | ANGLE_NWtoNE \
- | SHARP_WtoNW | SHARP_NtoNW | HOLE )
- #define BLOCK_NORTH ( LINE_VERTICAL | BENT_NtoSE | BENT_NtoSW \
- | BENT_EtoNW | BENT_WtoNE \
- | BENT_StoNE | BENT_StoNW \
- | CORNER_NORTHEAST | CORNER_NORTHWEST \
- | ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_NWtoNE \
- | DIAG_NEtoSW | DIAG_SEtoNW \
- | SHARP_NtoNE | SHARP_NtoNW \
- | SHARP_EtoNE | SHARP_WtoNW | HOLE )
- #define BLOCK_EAST ( LINE_HORIZONTAL | BENT_EtoSW | BENT_EtoNW \
- | BENT_NtoSE | BENT_StoNE \
- | BENT_WtoNE | BENT_WtoSE \
- | CORNER_NORTHEAST | CORNER_SOUTHEAST \
- | ANGLE_NEtoSE | ANGLE_SEtoSW | ANGLE_NWtoNE \
- | DIAG_NEtoSW | DIAG_SEtoNW \
- | SHARP_EtoNE | SHARP_EtoSE \
- | SHARP_NtoNE | SHARP_StoSE | HOLE )
- #define BLOCK_SOUTH ( LINE_VERTICAL | BENT_StoNE | BENT_StoNW \
- | BENT_EtoSW | BENT_WtoSE \
- | BENT_NtoSE | BENT_NtoSW \
- | CORNER_SOUTHEAST | CORNER_SOUTHWEST \
- | ANGLE_NEtoSE | ANGLE_SWtoNW | ANGLE_SEtoSW \
- | DIAG_NEtoSW | DIAG_SEtoNW \
- | SHARP_StoSE | SHARP_StoSW \
- | SHARP_EtoSE | SHARP_WtoSW | HOLE )
- #define BLOCK_WEST ( LINE_HORIZONTAL | BENT_WtoNE | BENT_WtoSE \
- | BENT_NtoSW | BENT_StoNW \
- | BENT_EtoSW | BENT_EtoNW \
- | CORNER_SOUTHWEST | CORNER_NORTHWEST \
- | ANGLE_SWtoNW | ANGLE_SEtoSW | ANGLE_NWtoNE \
- | DIAG_NEtoSW | DIAG_SEtoNW \
- | SHARP_WtoSW | SHARP_WtoNW \
- | SHARP_NtoNW | SHARP_StoSW | HOLE )
-
- struct block {
- int r1, c1;
- long b1;
- int r2, c2;
- long b2;
- };
-
- static struct block blocking[8] = { /* blocking masks for diagonal traces */
- { 0, -1, BLOCK_NORTHEAST, 1, 0, BLOCK_SOUTHWEST },
- { 0, 0, 0, 0, 0, 0 },
- { 1, 0, BLOCK_SOUTHEAST, 0, 1, BLOCK_NORTHWEST },
- { 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0 },
- { 0, -1, BLOCK_SOUTHEAST, -1, 0, BLOCK_NORTHWEST },
- { 0, 0, 0, 0, 0, 0 },
- { -1, 0, BLOCK_NORTHEAST, 0, 1, BLOCK_SOUTHWEST }
- };
-
- static long blocking2[8] = { /* blocking masks for drilling vias */
- BLOCK_SOUTHEAST, BLOCK_SOUTH, BLOCK_SOUTHWEST,
- BLOCK_EAST, BLOCK_WEST,
- BLOCK_NORTHEAST, BLOCK_NORTH, BLOCK_NORTHWEST
- };
-
- 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 }
- };
-
- /* mask for hole-related blocking effects */
- static struct {
- long trace;
- int present;
- } selfok2[8] = {
- { HOLE_NORTHWEST, 0 },
- { HOLE_NORTH, 0 },
- { HOLE_NORTHEAST, 0 },
- { HOLE_WEST, 0 },
- { HOLE_EAST, 0 },
- { HOLE_SOUTHWEST, 0 },
- { HOLE_SOUTH, 0 },
- { HOLE_SOUTHEAST, 0 }
- };
-
- static long newmask[8] = { /* patterns to mask out in neighbor cells */
- 0, CORNER_NORTHWEST|CORNER_NORTHEAST, 0,
- CORNER_NORTHWEST|CORNER_SOUTHWEST, CORNER_NORTHEAST|CORNER_SOUTHEAST,
- 0, CORNER_SOUTHWEST|CORNER_SOUTHEAST, 0
- };
-
- static char fmt[] =
- " open=%ld, closed=%ld, moved=%ld, max=%ld, %ld%% of board";
-
- extern int Nrows, Ncols; /* board dimensions */
-
- /* measures of progress */
- extern int Ntotal;
- int Ncurrent = 0;
- int CompleteTrace = 0;
-
- /* Do we want a double sided board? Added by Stephen P. Smith */
- extern int DoubleSided;
- extern int NoDiag;
- extern int TopSide;
- extern long Percent;
- extern int RatsNest;
-
- /* 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, int );
-
- void Solve( FILE * );
- void Retrace( int, int, int, int, int );
-
- void Solve ( fp )
- FILE *fp;
- { /* 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 */
- if ( DoubleSided ) {
- SetQueue( r1, c1, TOP, 0, a, r2, c2 );
- SetQueue( r1, c1, BOTTOM, 0, a, r2, c2 );
- }
- else
- {
- if ( TopSide ) SetQueue( r1, c1, TOP, 0, a, r2, c2 );
- if ( !TopSide ) 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&HOLE) {
- self = 5;
- /* set 'present' bits */
- for (i = 0; i < 8; i++)
- selfok2[i].present =
- ((curcell&selfok2[i].trace)?1:0);
- }
- else 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 ( (delta[i][0] != 0) && (delta[i][1] != 0 ) )
- if ( NoDiag )
- continue;
- /* Cause routing failure if a rats nest is desired */
- if ( RatsNest ) continue;
- /* check self-block */
- if (self < 5 && !selfok[self][i])
- continue; if ((nr = r+delta[i][0]) < 0 || nr >= Nrows
- || (nc = c+delta[i][1]) < 0
- || nc >= Ncols) /* off the edge? */
- continue;
- if (self == 5 && selfok2[i].present)
- continue;
- newcell = GetCell( nr, nc, s );
- /* check for non-target hole */
- if (newcell & HOLE) {
- if (nr != r2 || nc != c2)
- continue;
- }
- /* check for traces */
- else if (newcell & ~(newmask[i]))
- 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 & (blocking[i].b1))
- continue;
- /* check second buddy */
- buddy = GetCell( r+blocking[i].r2,
- c+blocking[i].c2, s );
- if (buddy & (blocking[i].b2))
- continue;
- }
- olddir = GetDir( r, c, s );
- newdist = d+CalcDist( ndir[i], olddir,
- (olddir == FROM_OTHERSIDE, s)
- ? GetDir( r, c, 1-s ) : 0, s );
- /* if (a) not visited yet, or (b) we have */
- /* found a better path, add it to queue */
- if (!GetDir( nr, nc, s )
- || (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 );
- }
- }
- if ( DoubleSided ) {
- /* consider other side of board */
- olddir = GetDir( r, c, s );
- if (olddir == FROM_OTHERSIDE)
- continue; /* useless move, so don't bother */
- if (curcell) /* can't drill via if anything here */
- continue;
- /* check for holes or traces on other side */
- if (newcell = GetCell( r, c, 1-s ))
- continue;
- /* check for nearby holes or traces on both sides */
- for (skip = i = 0; i < 8; i++) {
- if ( (delta[i][0] != 0) && (delta[i][1] != 0 ) )
- if ( NoDiag )
- continue;
- 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 ) & blocking2[i]) {
- skip = 1; /* can't drill via here */
- break;
- }
- if (GetCell( nr, nc, 1-s ) & blocking2[i]) {
- skip = 1; /* can't drill via here */
- break;
- }
- }
- if (skip) /* neighboring hole or trace? */
- continue; /* yes, can't drill via here */
- newdist = d+CalcDist( FROM_OTHERSIDE, olddir, 0, s );
- /* if (a) not visited yet, or (b) we have found a
- /* better path, add it to queue */
- if (!GetDir( r, c, 1-s )
- || (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 );
- }
- }
- if( Percent <= ((ClosNodes*50)/(Nrows*Ncols)) ) break;
- }
- printf( fmt, OpenNodes, ClosNodes, MoveNodes, MaxNodes,
- (ClosNodes*50)/(Nrows*Ncols) );
- putchar( '\n' );
- if (!success){
- printf( "\t*!* UNSUCCESSFUL *!*\n" );
- if( fp != NULL )
- fprintf( fp, "LINE2( %d, %d, %d, %d)\n",
- r1*50+25, c1*50+25, r2*50+25, c2*50+25 );
- }
- else
- CompleteTrace++;
- /* clear direction flags */
- for (r = 0; r < Nrows; r++) {
- for (c = 0; c < Ncols; c++) {
- SetDir( r, c, TOP, FROM_NOWHERE );
- SetDir( r, c, BOTTOM, FROM_NOWHERE );
- }
- }
- }
- printf( "\nCompleted Traces: %d of %d\n\n", CompleteTrace, Ntotal );
- 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:
- fprintf( stderr, "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:
- fprintf( stderr, "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 {
- fprintf( stderr, "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:
- fprintf( stderr, "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));
- }
-