Modified "chase" game
chris at eneevax.UUCP
chris at eneevax.UUCP
Tue Jan 24 01:25:57 AEST 1984
Here is source code for a modified version of the game ``chase''. While
bored one afternoon I tried it and got annoyed at the various bugs, so I
rewrote it. I've incorporated a suggestion from Linton Floyd that makes
the game considerably more challenging.
This program requires the Maryland Window Library, and includes a random
number generator written in Vax assembly code (no, I didn't write it; I
got it from someone who got it from someone else). However, if you have
the C library rand() routine you can write a randint() function easily
enough -- see the comments in the Makefile.
Oh yes, the best part: the "-r" option lets you use the Rogue motion
keys.
Chris
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting Makefile'
sed 's/^X//' <<'//go.sysin dd *' >Makefile
# Makefile for chase
#
# rand.s is for Vaxen. The only routines I use from it are srand and randint.
# randint(n) returns an integer in the range [0..n-1], and can be done on a
# 32 bit machine with
# (int) ((double) n * ((double) rand () / 2147483648.))
# or for 16 bit machines
# (int) ((double) n * ((double) rand () / 32768.))
# assuming that rand() returns a positive integer.
#
# -- 23 Jan 1983 Chris Torek
OBJS= chase.o dochase.o gen.o initwin.o key.o move.o rand.o
CFLAGS= -O
chase: $(OBJS)
cc -o chase $(OBJS) -lwinlib -ljobs -ltermlib
chase.o: chase.c chase.h
dochase.o: dochase.c chase.h
gen.o: gen.c chase.h
initwin.o: initwin.c chase.h
key.o: key.c chase.h
move.o: move.c chase.h
rand.o: rand.s
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 Makefile
/bin/echo -n ' '; /bin/ls -ld Makefile
fi
/bin/echo 'Extracting chase.c'
sed 's/^X//' <<'//go.sysin dd *' >chase.c
#ifndef lint
static char rcsid[] = "$Header: /usr/enee/chris/bin/src/chase/RCS/chase.c,v 1.2 84/01/23 04:05:55 chris Rel $";
#endif
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/chase.c,v 1.2 84/01/23 04:05:55 chris Rel $
*
* $Log: chase.c,v $
* Revision 1.2 84/01/23 04:05:55 chris
* "fields"->"fences"
*
* Revision 1.1 84/01/23 03:58:01 chris
* Initial revision
*
*/
#include "chase.h"
#include <ctype.h>
main (argc, argv)
register int argc;
register char **argv;
{
static char askr[] = "How many robots? ";
static char askef[] = "How many electric fences? ";
int i;
printf (" Welcome to Chase\n");
while (argc > 1 && argv[1][0] == '-') {
register char *s;
argc--;
argv++;
s = &argv[0][1];
while (*s) switch (*s++) {
case 'r':
WantRogueStyle++;
break;
default:
fprintf (stderr, "Usage: chase [ -r ] [ robots [ fences ]]\n");
exit (1);
}
}
if (argc > 1)
GetNum (argv[1], &Robots, 1, MaxRobots, askr);
else
GetNum ((char *) 0, &Robots, 1, MaxRobots, askr);
if (argc > 2)
GetNum (argv[2], &EFences, 0, MaxEFences, askef);
else
GetNum ((char *) 0, &EFences, 0, MaxEFences, askef);
GetKey = WantRogueStyle ? RogueGetKey : OldGetKey;
InitWin ();
srand (time ((long *) 0) + getpid ());
i = randint ((Robots + 1) >> 1) + (Robots >> 2);
Gen (i, HRobotChar);
Gen (Robots - i, RobotChar);
Gen (EFences, EFenceChar);
PlaceSelf ();
DoChase ();
}
X/* Get a number between min and max, from optional string str or keyboard */
GetNum (str, num, min, max, prompt)
char *str;
register int *num;
int min, max;
char *prompt;
{
static char *remember;
static char buf[100];
for (;;) {
if (str) {
*num = atoi (str);
str = 0;
remember = 0;
}
else {
register char *s;
if (remember)
s = remember;
else {
printf (prompt);
fgets (buf, sizeof buf, stdin);
s = buf;
}
while (isspace (*s))
s++;
*num = 0;
while (isdigit (*s))
*num = *num * 10 + *s++ - '0';
while (isspace (*s))
s++;
remember = *s ? s : 0;
}
if (*num >= min && *num <= max)
return;
printf ("Must be at least %d and at most %d\n", min, max);
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 chase.c
/bin/echo -n ' '; /bin/ls -ld chase.c
fi
/bin/echo 'Extracting chase.h'
sed 's/^X//' <<'//go.sysin dd *' >chase.h
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/chase.h,v 1.1 84/01/23 03:58:11 chris Rel $
* chase -- robot hunt game
*
* $Log: chase.h,v $
* Revision 1.1 84/01/23 03:58:11 chris
* Initial revision
*
*/
#include <stdio.h>
#include <local/window.h>
#define FieldRows 24
#define FieldCols 60
#define UsageRows 22
#define UsageCols 18
#define MinRows (FieldRows > UsageRows ? FieldRows : UsageRows)
#define MinCols (FieldCols + UsageCols + 1)
#define FieldX (FieldCols-2)
#define FieldY (FieldRows-2)
#define MaxRobots 500
#define MaxEFences 300
#define MaxTries 4000 /* for placement; see Gen, PlaceSelf */
#define SelfChar 'I' /* You */
#define RobotChar '=' /* A robot */
#define HRobotChar '#' /* Another type of robot */
#define EFenceChar 'X' /* An electric fence */
#define JunkChar '@' /* A junk heap */
Win *Field; /* The playing field */
Win *Usage; /* Description of keys */
int Rows; /* Real screen rows */
int Cols; /* Real screen cols */
int Robots; /* Number of robots on screen */
int EFences; /* Number of E-Fences */
Pos SelfAt; /* Self's position in field */
int (*GetKey) (); /* Keyboard reader */
int OldGetKey (); /* Old-chase-style */
int RogueGetKey (); /* Rogue style */
int WantRogueStyle; /* True => want rogue-style keys */
#define KUL 0 /* Key: Up & Left */
#define KU 1 /* Key: Up */
#define KUR 2 /* Key: Up & Right */
#define KL 3 /* Key: Left */
#define KDOT 4 /* Key: stay */
#define KR 5 /* Key: Right */
#define KDL 6 /* Key: Down & Left */
#define KD 7 /* Key: Down */
#define KDR 8 /* Key: Down & Right */
#define KTele 9 /* Key: Teleport */
#define KStand 10 /* Key: Stand */
#define KQuit 11 /* Key: Quit */
#define KRedraw 12 /* Key: Redraw */
#define KBad 13 /* Key: Bad (others) */
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 chase.h
/bin/echo -n ' '; /bin/ls -ld chase.h
fi
/bin/echo 'Extracting dochase.c'
sed 's/^X//' <<'//go.sysin dd *' >dochase.c
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/dochase.c,v 1.1 84/01/23 03:58:18 chris Rel $
*
* $Log: dochase.c,v $
* Revision 1.1 84/01/23 03:58:18 chris
* Initial revision
*
*/
#include "chase.h"
DoChase () {
register int c;
WSetRealCursor++;
for (;;) {
WRCurRow = SelfAt.row + 1;
WRCurCol = SelfAt.col + 1;
Wrefresh (0);
if (Robots == 0)
End ("You have defeated all the robots!");
switch ((*GetKey) ()) {
case EOF:
case KQuit:
Wexit (0);
case KUL:
Move (-1, -1);
break;
case KU:
Move (-1, 0);
break;
case KUR:
Move (-1, 1);
break;
case KL:
Move (0, -1);
break;
case KDOT:
Move (0, 0);
break;
case KR:
Move (0, 1);
break;
case KDL:
Move (1, -1);
break;
case KD:
Move (1, 0);
break;
case KDR:
Move (1, 1);
break;
case KTele:
Teleport ();
break;
case KStand:
for (;;) {
Move (0, 0);
Wrefresh (0);
if (Robots == 0)
break;
}
break;
case KRedraw:
ScreenGarbaged++;
break;
default:
Ding ();
break;
}
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 dochase.c
/bin/echo -n ' '; /bin/ls -ld dochase.c
fi
/bin/echo 'Extracting gen.c'
sed 's/^X//' <<'//go.sysin dd *' >gen.c
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/gen.c,v 1.1 84/01/23 03:58:32 chris Rel $
*
* $Log: gen.c,v $
* Revision 1.1 84/01/23 03:58:32 chris
* Initial revision
*
*/
#include "chase.h"
X/* Generate positions for n things displayed with c */
Gen (n, c)
register int n;
int c;
{
register int row,
col,
tries;
while (--n >= 0) {
for (tries = MaxTries; --tries >= 0;) {
row = randint (FieldY);
col = randint (FieldX);
WAcursor (Field, row, col);
if (Wread (Field, 1, 0) != ' ')
continue;
WAcursor (Field, row, col);
Wputc (c, Field);
goto ok;
}
Wcleanup ();
printf ("Unable to place %c after %d tries!\n", c, MaxTries);
exit (1);
ok:;
}
}
PlaceSelf () {
register int tries;
for (tries = MaxTries; --tries >= 0;) {
SelfAt.row = randint (FieldY - 2) + 1;
SelfAt.col = randint (FieldX - 2) + 1;
WAcursor (Field, SelfAt.row - 1, SelfAt.col - 1);
if (Wread (Field, 1, 0) != ' ' || Wread (Field, 1, 0) != ' '
|| Wread (Field, 1, 0) != ' ')
continue;
WAcursor (Field, SelfAt.row, SelfAt.col - 1);
if (Wread (Field, 1, 0) != ' ' || Wread (Field, 1, 0) != ' '
|| Wread (Field, 1, 0) != ' ')
continue;
WAcursor (Field, SelfAt.row + 1, SelfAt.col - 1);
if (Wread (Field, 1, 0) != ' ' || Wread (Field, 1, 0) != ' '
|| Wread (Field, 1, 0) != ' ')
continue;
WAcursor (Field, SelfAt.row, SelfAt.col);
Wputc (SelfChar, Field);
WAcursor (Field, SelfAt.row, SelfAt.col);
return;
}
Wcleanup ();
printf ("Unable to place self after %d tries!\n", MaxTries);
exit (1);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 gen.c
/bin/echo -n ' '; /bin/ls -ld gen.c
fi
/bin/echo 'Extracting initwin.c'
sed 's/^X//' <<'//go.sysin dd *' >initwin.c
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/initwin.c,v 1.1 84/01/23 03:58:54 chris Rel $
*
* $Log: initwin.c,v $
* Revision 1.1 84/01/23 03:58:54 chris
* Initial revision
*
*/
#include "chase.h"
X/* Initialize the window (display) system */
InitWin () {
if (Winit (0, 0)) {
printf ("Sorry, but this program won't run on your terminal.\n");
exit (1);
}
Wscreensize (&Rows, &Cols);
if (Rows < MinRows || Cols < MinCols) {
Wcleanup ();
printf ("Sorry, your screen is too small.\n");
exit (1);
}
Field = Wopen (0, 0, 0, FieldCols, FieldRows, 0, 0);
Usage = Wopen (1, FieldCols+1, 0, UsageCols, UsageRows, 0, 0);
if (Field == 0 || Usage == 0) {
Wcleanup ();
printf ("Something is wrong! I can't open the window.\n");
exit (1);
}
Woncursor (Field, 0);
Wframe (Field);
Wwrap (Field, 0);
Woncursor (Usage, 0);
Wnewline (Usage, 1);
Wwrap (Usage, 0);
Wputs (" Move Control:\n", Usage);
if (WantRogueStyle) {
Wputs (" y k u\n", Usage);
Wputs (" \\|/\n", Usage);
Wputs (" h-.-l\n", Usage);
Wputs (" /|\\\n", Usage);
Wputs (" b j n\n", Usage);
}
else {
Wputs (" y u i\n", Usage);
Wputs (" \\|/\n", Usage);
Wputs (" h-j-k\n", Usage);
Wputs (" /|\\\n", Usage);
Wputs (" n m ,\n", Usage);
}
Wputs ("\n\n\tCommands:\n", Usage);
Wputs (" t - Teleport\n", Usage);
Wputs (" s - Last stand\n", Usage);
Wputs (" q - Quit\n", Usage);
Wputs (" ^L - Redraw\n", Usage);
Wputs ("\n\n\tKey\n", Usage);
Wputs (" I - You\n = - Robot\n # - Robot\n X - Electric\n Fence\n @ - Junk heap", Usage);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 initwin.c
/bin/echo -n ' '; /bin/ls -ld initwin.c
fi
/bin/echo 'Extracting key.c'
sed 's/^X//' <<'//go.sysin dd *' >key.c
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/key.c,v 1.1 84/01/23 03:59:06 chris Rel $
*
* $Log: key.c,v $
* Revision 1.1 84/01/23 03:59:06 chris
* Initial revision
*
*/
#include "chase.h"
X/* Get a key type, old chase style keyboard */
OldGetKey () {
switch (getchar ()) {
case EOF:
return EOF;
case 'y': case 'Y':
return KUL;
case 'u': case 'U':
return KU;
case 'i': case 'I':
return KUR;
case 'h': case 'H':
return KL;
case 'j': case 'J':
return KDOT;
case 'k': case 'K':
return KR;
case 'n': case 'N':
return KDL;
case 'm': case 'M':
return KD;
case ',':
return KDR;
case 't': case 'T':
return KTele;
case 's': case 'S':
return KStand;
case 'q': case 'Q':
return KQuit;
case 014:
return KRedraw;
default:
return KBad;
}
}
X/* Get a key type, new Rogue style */
RogueGetKey () {
switch (getchar ()) {
case EOF:
return EOF;
case 'y': case 'Y':
return KUL;
case 'k': case 'K':
return KU;
case 'u': case 'U':
return KUR;
case 'h': case 'H':
return KL;
case '.':
return KDOT;
case 'l': case 'L':
return KR;
case 'b': case 'B':
return KDL;
case 'j': case 'J':
return KD;
case 'n': case 'N':
return KDR;
case 't': case 'T':
return KTele;
case 's': case 'S':
return KStand;
case 'q': case 'Q':
return KQuit;
case 014:
return KRedraw;
default:
return KBad;
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 key.c
/bin/echo -n ' '; /bin/ls -ld key.c
fi
/bin/echo 'Extracting move.c'
sed 's/^X//' <<'//go.sysin dd *' >move.c
X/*
* $Header: /usr/enee/chris/bin/src/chase/RCS/move.c,v 1.2 84/01/23 04:06:21 chris Rel $
*
* $Log: move.c,v $
* Revision 1.2 84/01/23 04:06:21 chris
* "field"->"fence"
*
* Revision 1.1 84/01/23 03:59:13 chris
* Initial revision
*
*/
#include "chase.h"
X/* Bad character found in field window */
BadChar (c, y, x)
int c, y, x;
{
Wcleanup ();
printf ("Odd character '%c' found at (%d, %d)\n", c, y, x);
exit (1);
}
X/* Sign function */
#define sgn(x) ((x) < 0 ? -1 : (x) ? 1 : 0)
X/* Absolute value */
#define abs(x) ((x) < 0 ? -(x) : (x))
X/* Move self, then robots */
Move (DelY, DelX)
int DelY, DelX;
{
register int c, y, x;
register char *np;
int DoMunch;
static char new[FieldY * FieldX];
static int beenhere;
static int minX, minY, maxX, maxY; /* Field-robot-scan optimization */
/* Move self */
if (DelY || DelX) {
if (SelfAt.row + DelY < 0 || SelfAt.row + DelY >= FieldY
|| SelfAt.col + DelX < 0 || SelfAt.col + DelX >= FieldX) {
Ding ();
return;
}
WAcursor (Field, SelfAt.row, SelfAt.col);
Wputc (' ', Field); /* Blank out self */
WAcursor (Field, SelfAt.row += DelY, SelfAt.col += DelX);
switch (c = Wread (Field, 1, 0)) {
case HRobotChar:
case RobotChar:
Munch ();
case EFenceChar:
End ("You ran into an electric fence and are now dead.");
case JunkChar:
ForcedStand ();
return;
case ' ':
break;
default:
BadChar (c, SelfAt.row, SelfAt.col);
}
WAcursor (Field, SelfAt.row, SelfAt.col);
Wputc (SelfChar, Field);
WAcursor (Field, SelfAt.row, SelfAt.col);
}
WRCurRow = SelfAt.row + 1;
WRCurCol = SelfAt.col + 1;
Wrefresh (0);
/* Move robots */
if (beenhere) {
for (np = new + sizeof new; np > new;)
*--np = 0;
}
else
maxX = FieldX - 1, maxY = FieldY - 1, beenhere++;
for (y = minY; y <= maxY; y++) {
WAcursor (Field, y, minX);
for (x = minX; x <= maxX; x++) {
register int ny, nx;
int nc;
c = Wread (Field, 1, 0);
if (c != RobotChar && c != HRobotChar)
continue;
WAcursor (Field, y, x);
Wputc (' ', Field);
if (c == RobotChar) {
ny = y + (y < SelfAt.row ? 1 : y == SelfAt.row ? 0 : -1);
nx = x + (x < SelfAt.col ? 1 : x == SelfAt.col ? 0 : -1);
}
else {
ny = SelfAt.row - y;
nx = SelfAt.col - x;
if (abs (ny) < abs (nx))
nx = x + sgn (nx), ny = y;
else if (abs (nx) < abs (ny))
nx = x, ny = y + sgn (ny);
else
nx = x + sgn (nx), ny = y + sgn (ny);
}
WAcursor (Field, ny, nx);
if ((nc = Wread (Field, 1, 0)) == EFenceChar || nc == JunkChar)
Robots--; /* Destroy one robot */
else {
np = &new[ny * FieldX + nx];
if (*np == 0)
*np = c;
else if (*np != JunkChar)
*np = JunkChar, Robots -= 2;
else
Robots--;
}
WAcursor (Field, y, x + 1);
}
}
np = new;
DoMunch = 0;
minX = FieldX;
minY = FieldY;
maxX = 0;
maxY = 0;
for (y = 0; y < FieldY; y++) {
for (x = 0; x < FieldX; x++) {
if ((c = *np++) == 0)
continue;
if (y < minY)
minY = y;
if (y > maxY)
maxY = y;
if (x < minX)
minX = x;
if (x > maxX)
maxX = x;
if (y == SelfAt.row && x == SelfAt.col)
DoMunch++;
WAcursor (Field, y, x);
Wputc (c, Field);
}
}
if (DoMunch)
Munch ();
}
X/* End of game routine */
End (message)
char *message;
{
Wrefresh (1);
Wcleanup ();
printf ("%s\n", message);
exit (0);
}
X/* Get munched by a robot */
Munch () {
Wauxcursor (Field, SelfAt.row + 1, SelfAt.col + 1);
Waputs ("*MUNCH*", WINVERSE, Field);
End ("You have been captured and eaten by robots.");
}
X/* Teleport */
Teleport () {
register int y, x, tries;
if (randint ((Robots / 10) + 10) == 0)
Munch ();
WAcursor (Field, SelfAt.row, SelfAt.col);
Wputc (' ', Field);
for (tries = MaxTries; --tries >= 0;) {
y = randint (FieldY);
x = randint (FieldX);
WAcursor (Field, y, x);
if (Wread (Field, 1, 0) != ' ')
continue;
WAcursor (Field, SelfAt.row = y, SelfAt.col = x);
Wputc (SelfChar, Field);
Move (0, 0);
return;
}
Wcleanup ();
printf ("Unable to place self after %d tries!\n", MaxTries);
exit (1);
}
ForcedStand () {
Win *msg;
WAcursor (Field, SelfAt.row, SelfAt.col);
Wputc (SelfChar, Field);
WAcursor (Field, SelfAt.row, SelfAt.col);
WRCurRow = SelfAt.row + 1;
WRCurCol = SelfAt.col + 1;
msg = Wopen (0, 1, FieldRows - 1, FieldCols - 2, 1, 0, 0);
if (msg) {
Woncursor (msg, 0);
Wsetmode (msg, WBLINK);
Wputs ("You are trapped in a junk pile!", msg);
}
Wrefresh (0);
for (;;) {
Move (0, 0);
Wrefresh (0);
if (Robots == 0)
return;
}
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 move.c
/bin/echo -n ' '; /bin/ls -ld move.c
fi
/bin/echo 'Extracting rand.s'
sed 's/^X//' <<'//go.sysin dd *' >rand.s
.data
.align 2
_randx:
.long 1
.text
.align 2
.globl _srand # set the random seed
_srand: # srand(seed) int seed;
.word 0
movl _randx,r0
movl 4(ap),_randx
ret
.align 2
.globl _rand # give a 31 bit random positive integer
_rand: # int rand()
.word 0
jsb rand
bicl2 $1,r0
rotl $-1,r0,r0
ret
.align 2
.globl _randint # return a number in [0..n-1]
_randint: # int randint(n) int n;
.word 0
jsb rand
emul 4(ap),r0,$0,r2
tstl r0
jgeq L1
addl3 4(ap),r3,r0
ret
L1: movl r3,r0
ret
.align 2
# compute the next 32 bit random number
rand: mull3 $505360173,_randx,r0
addl2 $907633385,r0
movl r0,_randx
rsb
.align 2
.globl _flat # give a random double in [0.,1.)
_flat: # double flat()
.word 0
jsb rand
movl r0,r2
movf $0f1.0,r0
extzv $25,$7,r2,r3
insv r3,$0,$7,r0
extzv $9,$16,r2,r3
insv r3,$16,$16,r0
extzv $0,$9,r2,r1
subd2 $0d1.0,r0
ret
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 644 rand.s
/bin/echo -n ' '; /bin/ls -ld rand.s
fi
--
Chris Torek, Dept of CS, Univeristy of Maryland, College Park, MD
...!umcp-cs!chris chris%umcp-cs at CSNet-Relay
More information about the Comp.sources.unix
mailing list