home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_100
/
136_01
/
cmaze.c
< prev
next >
Wrap
Text File
|
1979-12-31
|
17KB
|
973 lines
/* HEADER: CUG136.19;
TITLE: CMAZE;
VERSION: 1.00;
DATE: 5/29/1984;
DESCRIPTION: "3-D Maze Game";
KEYWORDS: game,maze;
SYSTEM: CP/M;
FILENAME: CMAZE.C;
AUTHORS: R. Rodman;
COMPILERS: C/80;
*/
/* >< CMAZE by R. Rodman ><
5/6/81 v0.8
9/14/81 v0.9 (Basic-E)
1/15/82 back to MBASIC
840512 convert to c
840513, 840514, 840515, 840516, 840518 rr continue conversion
840529 fix boxes 1.00
Robots move crudely.
Find objects in boxes: Compass - Radio - etc.
Shoot algorithm could show an alternating / \ or something.
Solving maze is difficult and gets boring. Tools would help. */
#define MX 15 /* define maximum X dimension of maze */
#define MY 10 /* define maximum Y dimension of maze */
#define MXMY 150 /* product of mx and my */
#define CLRSCN "\033+"
#define REVVID "\033G4"
#define NORVID "\033G0"
#define CURBEG "\033="
#define CLREOS "\033Y"
#define CUROFF "\033.0"
#define CURON "\033.2"
int maze[ MX ][ MY ];
int rx[ 4 ], ry[ 4 ];
char *robot[ 4 ][ 9 ] = {
" _______",
" / o' `o \\",
" \\ ----- /", /* close robot, height 9 */
" [TTTTT]",
" /[=====]\\",
"/ [MMMMM] \\",
") [=====] (",
" / \\ / \\",
"/ \\ / \\",
" _____",
"/ o o \\",
"\\ --- /",
"/[TTT]\\", /* height 7 */
")[===](",
" [===]",
"/ \\ / \\", "", "",
" ____",
"< o_o>",
"/[TT]\\",
" [==]", /* height 5 */
"/ \\/ \\", "", "", "", "",
"<oo>",
"/[]\\", /* dist 4, height 3 */
"/\\/\\", "", "", "", "", "", ""
};
int boxx[ 4 ], boxy[ 4 ];
char *boxes[ 3 ][ 3 ] = {
" ____",
"|\\ ___\\",
" \\|____|",
" __",
"<__>", "",
"<>", "", ""
};
int seed;
int plyr_x, plyr_y, plyr_face; /* player x, y, direction */
int alive; /* nonzero while alive */
int won; /* won game */
int comp, radi, shots;
int repaint; /* nonzero to cause repaint */
/* main program */
main()
{
instructions(); /* print instructions */
randomize(); /* randomize seed */
generate(); /* generate maze */
init_robots();
init_boxes();
plyr_face = 2; /* face to "east" */
alive = 1;
repaint = 1;
won = 0;
while( alive && ! won ) {
if( repaint ) {
depict();
ck_boxes();
repaint = 0;
}
ck_instruments();
if( ck_robots()) alive = 0;
else {
get_command();
update_robots();
}
}
sound( ",,,,,,,,,,,,,,,," ); /* shut up */
puts( CURON );
}
/* return random number between 0 and n-1 */
fnr( n )
int n;
{
return ( rnd() % n );
}
int rnd()
{
seed = seed * 3;
if( seed > 10000 ) seed = seed / 4;
return seed;
}
randomize()
{
int i;
seed = 1;
puts( "<Press a key>" );
while( bdos( 6, 0xFF ) == 0 ) i = rnd();
}
goxy( x, y )
int x, y;
{
puts( CURBEG );
putchar( y + 32 );
putchar( x + 32 );
}
/* print instructions */
instructions()
{
puts( CLRSCN );
puts( "\t\t\t> > > A M A Z E ! < < <\n\n" );
puts( "\nVersion 1.00\n\n" );
puts( "This program presents a Perspective Maze Display on your\n" );
puts( "terminal. Your object is to get through this maze.\n" );
puts( "four robots in the maze which will attempt to\n" );
puts( "capture you. You have a laser pistol to protect yourself;\n" );
puts( "the pistol can fire only 5 shots.\n\n" );
puts( "On each turn, you will be asked for a command, which must\n" );
puts( "be made up of any combination of:\n\n" );
puts( "S to step forward one square\n" );
puts( "L to turn to your left, R to turn to your right\n" );
puts( "F to fire the laser pistol\n" );
puts( "O to open a box\n\n" );
puts( "I am generating the maze now.\n" );
sound( ",,,,,,,,,,,,,,,," ); /* turn sound off */
}
/* >< Generate Maze ><
This program uses the algorithm described by R J Bishop
in his article in Byte Oct 78 P 136 */
generate()
{
int x, y;
int lc, oc, wf, bx, by;
int to_bit, from_bit, tp, path;
int qu[ MXMY ][ 2 ];
for( x = 0; x < MX; ++x )
for( y = 0; y < MY; ++y )
maze[ x ][ y ] = 0;
lc = 0; /* last cell in queue */
oc = 0; /* last cell taken out of queue */
wf = 0; /* found win path yet? */
plyr_x = 0;
plyr_y = fnr( MY ); /* player start position */
bx = plyr_x;
by = plyr_y; /* random walk start position */
x = 1; y = 1; /* junk values to cause loop to execute */
/* loop while any valid starting points for walks are in the queue */
while( oc <= lc ) {
/* random walk from bx, by until we come to a dead end or generate a goal. */
x = bx;
y = by;
while( x + y ) {
/* inner loop, try to move to another square from bx, by */
tp = 0; /* tried path */
while( tp < 15 ) {
x = bx;
y = by;
path = fnr( 4 ); /* get random path */
switch( path ) {
case 0 : to_bit = 1;
from_bit = 2;
--x;
break;
case 1 : to_bit = 2;
from_bit = 1;
++x;
break;
case 2 : to_bit = 4;
from_bit = 8;
--y;
break;
case 3 : to_bit = 8;
from_bit = 4;
++y;
break;
}
tp = tp | to_bit;
/* break out of loop if we hit an empty square */
if( x >= 0 && x <= ( MX - 2 )
&& y >= 0 && y < MY )
if( maze[ x ][ y ] == 0 ) break;
/* otherwise try again */
}
/* see if we got out, or just fell out */
if( tp >= 15 ) {
x = 0; /* no path left */
y = 0;
}
/* if not, we must have a good path here */
if( x + y ) {
/* flag where we opened path to */
maze[ bx ][ by ] = maze[ bx ][ by ] | to_bit;
bx = x; /* new origin */
by = y;
/* flag where we opened path from */
maze[ bx ][ by ] = maze[ bx ][ by ] | from_bit;
qu[ lc ][ 0 ] = bx;
qu[ lc ][ 1 ] = by; /* save in queue */
++lc;
/* have we no solution yet, and are we on next to last column of maze? */
if( wf == 0 && bx == ( MX - 2 )) {
/* if so, generate a goal */
++wf; /* mark goal found */
maze[ bx ][ by ] =
maze[ bx ][ by ] | 2;
maze[ MX - 1 ][ by ] = 1;
x = 0; /* cause no path */
y = 0;
}
}
}
/* no path. what do you do now? */
if( lc == MXMY ) break; /* give up if we've used all */
bx = qu[ oc ][ 0 ]; /* pull next starting point */
by = qu[ oc ][ 1 ]; /* from the queue */
++oc;
}
}
init_robots()
{
int i;
for( i = 0; i < 4; ++i ) {
rx[ i ] = fnr( MX - 3 ) + 1;
ry[ i ] = fnr( MY );
}
shots = 5;
}
init_boxes()
{
int i;
for( i = 0; i < 4; ++i ) {
boxx[ i ] = fnr( MX - 3 ) + 1;
boxy[ i ] = fnr( MY );
}
comp = 0; /* you have no compass */
radi = 0; /* you have no radio */
shots = 5;
}
/* depict view from current position and location */
depict()
{
int lsm, rsm; /* left side, right side masks */
int wx, wy; /* wall x, y */
int mw, wf, w;
int lw[ 6 ], rw[ 6 ];
char ldol, rdol, wdol[ 3 ];
int js, l1, l2, j1, j2, l, j, mi;
/* define side masks */
switch( plyr_face ) {
case 1 : lsm = 8;
rsm = 4;
break;
case 2 : lsm = 4;
rsm = 8;
break;
case 4 : lsm = 1;
rsm = 2;
break;
case 8 : lsm = 2;
rsm = 1;
break;
}
/* now we know which way to look */
wx = plyr_x;
wy = plyr_y;
mw = 4; /* max wall even if we don't run into one */
wf = 0;
w = 0;
while( w < mw ) {
lw[ w ] = maze[ wx ][ wy ] & lsm;
rw[ w ] = maze[ wx ][ wy ] & rsm;
/* mw is the wall beyond which we cannot see */
if( ! ( maze[ wx ][ wy ] & plyr_face )) {
mw = w;
lw[ w + 1 ] = 1;
rw[ w + 1 ] = 1;
}
if( wx == MX - 1 ) wf = 1;
switch( plyr_face ) {
case 1 : --wx; break;
case 2 : ++wx; break;
case 4 : --wy; break;
case 8 : ++wy; break;
}
++w;
}
/* got wall arrays, now draw them */
puts( CLRSCN ); /* clear the screen */
puts( CUROFF );
ldol = '\\';
rdol = '/';
/* js is 1 for top half of screen, -1 for bottom */
for( js = 1; js >= -1; js -= 2 ) {
if( js == 1 ) {
l1 = 0;
l2 = 4;
j1 = 0;
j2 = 1;
} else {
l1 = 4;
l2 = 0;
j1 = 1;
j2 = 0;
ldol = '/';
rdol = '\\';
}
/* l is line of screen, going 0 to 4 on top, then 4 to 0 on bottom. */
for( l = l1; l != l2 + js; l += js ) {
/* j is used to cause two screen lines to be used for each step of l. */
for( j = j1; j != j2 + js; j += js ) {
/* how many spaces go in the middle of line l? */
mi = 40 - 6 * l;
/* draw left side old walls, ie walls already passed by l. */
for( w = 0; w < l; ++w ) {
if( w > mw ) puts( " " );
else {
if(( w == l - 1 )
&& ( lw[ w ] != 0 )
&& ( j == 0 ))
wdol[ 0 ] = '-';
else wdol[ 0 ] = ' ';
wdol[ 1 ] = wdol[ 0 ];
wdol[ 2 ] = wdol[ 1 ];
if(( lw[ w ] > 0 )
&& ( w != mw ))
wdol[ 2 ] = '|';
if(( lw[ w ] == 0 )
&& ( lw[ w + 1 ] != 0
))
wdol[ 2 ] = '|';
putchar( wdol[ 0 ] );
putchar( wdol[ 1 ] );
putchar( wdol[ 2 ] );
}
}
/* left side new wall */
switch( j ) {
case 0 : if( l == ( mw + 1 )) {
puts( "--" );
break;
}
if( l > mw ) {
puts( " " );
break;
}
if( lw[ l ] == 0 ) {
putchar( ldol );
putchar( ' ' );
} else puts( " " );
break;
case 1 : if( l > mw ) {
puts( " " );
break;
}
if( lw[ l ] == 0 ) {
putchar( ' ' );
putchar( ldol );
} else puts( " " );
}
if(( l == ( mw + 1 )) && ( j == 0 ))
repchr( mi, '-' );
else repchr( mi, ' ' );
/* right side new walls */
switch( j ) {
case 0 : if( l == ( mw + 1 )) {
puts( "--" );
break;
}
if( l > mw ) {
puts( " " );
break;
}
if( rw[ l ] == 0 ) {
putchar( ' ' );
putchar( rdol );
} else puts( " " );
break;
case 1 : if( l > mw ) {
puts( " " );
break;
}
if( rw[ l ] == 0 ) {
putchar( rdol );
putchar( ' ' );
} else puts( " " );
}
/* right side old walls */
for( w = l - 1; w >= 0; --w ) {
if( w > mw ) puts( " " );
else {
if(( w == l - 1 )
&& ( rw[ w ] != 0 )
&& ( j == 0 ))
wdol[ 0 ] = '-';
else wdol[ 0 ] = ' ';
wdol[ 1 ] = wdol[ 0 ];
wdol[ 2 ] = wdol[ 1 ];
if(( rw[ w ] > 0 )
&& ( w != mw ))
wdol[ 0 ] = '|';
if(( rw[ w ] == 0 )
&& ( rw[ w + 1 ] != 0
))
wdol[ 0 ] = '|';
putchar( wdol[ 0 ] );
putchar( wdol[ 1 ] );
putchar( wdol[ 2 ] );
}
}
putchar( '\n' );
} /* loop on j */
} /* loop on l */
} /* loop on js (top or bottom) */
puts( CLREOS );
/* draw exit sign */
if( wf ) {
goxy( 18, 10 );
puts( "E X I T" );
}
}
/* check for robots */
int ck_robots()
{
int wx, wy, k, dr, r, d, h, w;
wx = plyr_x;
wy = plyr_y;
k = 0;
dr = 99;
w = 0;
/* step forward along player's view */
while( maze[ wx ][ wy ] & plyr_face ) {
switch( plyr_face ) {
case 1 : --wx; break;
case 2 : ++wx; break;
case 4 : --wy; break;
case 8 : ++wy; break;
}
for( r = 0; r < 4; ++r ) {
if( rx[ r ] == wx && ry[ r ] == wy ) {
for( h = 0; h < 9; ++h ) {
goxy( 15 + w, 13 + h );
puts( robot[ w ][ h ] );
}
}
if( rx[ r ] == plyr_x && ry[ r ] == plyr_y ) k = r;
d = abs( rx[ r ] - plyr_x ) + abs( ry[ r ] - plyr_y );
if( d < dr ) dr = d;
}
++w; /* increment distance */
}
if( dr < 5 ) {
sound( "255,9,0,0,1,0,1,234" );
cricket( 8, 9 - 2 * dr ); /* make a robot sound */
cricket( 9, 9 - 2 * dr );
cricket( 10, 9 - 2 * dr );
} else sound( ",,,,,,,,,,,,,,,," );
if( k ) {
goxy( 50, 22 );
puts( "Aighh! The robots got you!" );
}
return k; /* nonzero value means you got it */
}
/* check boxes */
ck_boxes()
{
int wx, wy, b, d, h, w;
wx = plyr_x;
wy = plyr_y;
w = 0;
/* look forward along player's view */
while( maze[ wx ][ wy ] & plyr_face ) {
switch( plyr_face ) {
case 1 : --wx; break;
case 2 : ++wx; break;
case 4 : --wy; break;
case 8 : ++wy; break;
}
if( w < 3 ) for( b = 0; b < 4; ++b ) {
if( boxx[ b ] == wx && boxy[ b ] == wy ) {
d = fnr( 10 ) + 12;
for( h = 0; h < 3; ++h ) {
goxy( d, 16 + w * 2 + h );
puts( boxes[ w ][ h ] );
}
}
}
++w; /* increment distance */
}
}
/* check the instruments */
ck_instruments()
{
if( comp ) {
goxy( 50, 10 );
puts( "Compass Reading: " );
switch( plyr_face ) {
case 1 : puts( "WEST " ); break;
case 2 : puts( "EAST " ); break;
case 4 : puts( "NORTH" ); break;
case 8 : puts( "SOUTH" ); break;
}
}
goxy( 50, 15 );
putchar( shots + '0' );
puts( " shots remaining" );
}
/* get and process user command */
get_command()
{
int b;
char command;
goxy( 0, 22 );
puts( "Command (L/R/S/F/O): " );
puts( CURON );
while( ! ( command = bdos( 6, 0xFF ))) ;
puts( CUROFF );
switch( command ) {
case '\003' : exit();
/* open box */
case 'O' : for( b = 0; b < 4; ++b ) {
if( boxx[ b ] == plyr_x
&& boxy[ b ] == plyr_y ) {
boxx[ b ] = 99;
goxy( 40, 22 );
puts( "Box contains a " );
switch( b ) {
case 0 : puts( "Compass!" );
comp = 1;
break;
case 1 : puts( "Radio!" );
radi = 1;
break;
case 2 : puts( "Rubik's Cube" );
break;
case 3 : puts(
"Laser Pistol recharge unit!" );
shots += 5;
}
}
}
break;
case 'F' : fire();
break;
/* turn left */
case 'L' : repaint = 1;
if( plyr_face == 1 ) {
plyr_face = 8;
break;
}
if( plyr_face == 8 ) {
plyr_face = 2;
break;
}
if( plyr_face == 2 ) {
plyr_face = 4;
break;
}
if( plyr_face == 4 ) {
plyr_face = 1;
break;
}
break;
/* turn right */
case 'R' : repaint = 1;
if( plyr_face == 1 ) {
plyr_face = 4;
break;
}
if( plyr_face == 4 ) {
plyr_face = 2;
break;
}
if( plyr_face == 2 ) {
plyr_face = 8;
break;
}
if( plyr_face == 8 ) {
plyr_face = 1;
break;
}
break;
/* step forward */
case 'S' : if( maze[ plyr_x ][ plyr_y ] & plyr_face ) {
switch( plyr_face ) {
case 1 : --plyr_x; break;
case 2 : ++plyr_x; break;
case 4 : --plyr_y; break;
case 8 : ++plyr_y; break;
}
if( plyr_x == MX - 1 ) {
puts( "You made it!! You''ve Won!!!" );
won = 1;
} else repaint = 1;
} else {
goxy( 40, 22 );
puts( "CAN'T!" );
}
break;
default: putchar( '\007' );
}
}
update_robots()
{
int r, x, y, rd, ok;
for( r = 0; r < 4; ++r ) {
if( rx[ r ] != 99 ) {
ok = 0;
while( ! ok ) {
x = rx[ r ];
y = ry[ r ];
switch( fnr( 3 )) {
case 0 : if( rx[ r ] < plyr_x ) {
rd = 2;
++x;
} else {
rd = 1;
--x;
}
break;
case 1 : if( ry[ r ] < plyr_y ) {
rd = 8;
++y;
} else {
rd = 4;
--y;
}
break;
case 2 : rd = 15; /* no move */
}
ok = maze[ rx[ r ]][ ry[ r ]] & rd;
}
}
}
}
/* fire laser */
fire()
{
int wx, wy, r, w, h;
if( ! shots ) return;
--shots;
sound( "1,0,,,,,1,238,7,7" );
r = 0;
for( wx = 2; wx < 56; ++wx ) cricket( r, wx );
sound( ",,,,,,,,," );
wx = plyr_x;
wy = plyr_y;
/* look forward along player's view */
w = 0;
while(( maze[ wx ][ wy ] & plyr_face ) && ( w < 4 )) {
switch( plyr_face ) {
case 1 : --wx; break;
case 2 : ++wx; break;
case 4 : --wy; break;
case 8 : ++wy; break;
}
goxy( 19, 18 - ( 2 * w ));
putchar( '*' );
for( r = 0; r < 4; ++r ) {
if( rx[ r ] == wx && ry[ r ] == wy ) {
goxy( 50, 22 );
puts( "\007>HIT!<" );
for( h = 3; h < 12; ++h ) {
goxy( 19 + ( h / 2 ) - fnr( h ),
12 + ( h / 2 ) - fnr( h ));
putchar( ' ' + fnr( 16 ));
}
rx[ r ] = 99;
break;
}
}
++w;
}
repaint = 1;
}
/* generate sound effects */
sound( p )
char *p;
{
int r, v;
char c;
r = 0;
v = 0;
while( c = *p++ ) {
if( c >= '0' && c <= '9' ) {
v = 10 * v + c - '0';
} else {
cricket( r, v ); /* send out value */
v = 0;
++r; /* increment register */
}
}
}
/* send value to cricket */
cricket( r, v )
int r, v;
{
portout( 177, r );
portout( 176, v );
}
repchr( n, c )
int n;
char c;
{
while( n-- ) putchar( c );
}
puts( p )
char *p;
{
while( *p ) putchar( *p++ );
}
int abs( i )
int i;
{
if( i < 0 ) return 0 - i;
else return i;
}
#include "portio.c"
#include "stdlib.c"