home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
654.SOLVE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-16
|
14KB
|
421 lines
#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));
}