Created
October 28, 2022 15:19
-
-
Save wernsey/ca4ac0c73eaaf2f7ff8d9db884d3c40e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*************************************************************************** | |
* | |
* | |
* chase appeared in Creative Computing | |
* magazine way back in 1976. According | |
* to the book "More BASIC Computer Games" | |
* it was written by Mac Oglesby, with | |
* improvements by Bill Cotter and Arnold | |
* Loveridge. | |
* This version, in C, was written by | |
* Ken Brown. 7/25/84 | |
* Code specific to the Microsoft C compiler | |
* is noted. | |
* The cursor movement routines assume that | |
* the DOS 2.x ANSI.SYS driver has been | |
* loaded. | |
* | |
* It was further modified in 2022 by Werner Stoop (https://github.com/wernsey) | |
* to make the code C89 and get it working with Borland Turbo C (under DOSBox) | |
* It even compiles with GCC under Linux, though the characters are wrong | |
* I found it in \MSDOS\C\CHASE.ZIP in a Symtel CD on archive.org | |
* | |
* | |
***************************************************************************/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <ctype.h> | |
/* constant definitions */ | |
#define TRUE 1 | |
#define FALSE 0 | |
#define XDIM 60 | |
#define YDIM 20 | |
#define MAX_ROBOTS 120 | |
#define MAX_FENCES 120 | |
#define MIN_FENCES 5 | |
#define MIN_ROBOTS 5 | |
#define MY_CHAR '\002' | |
#define ROB_CHAR '\004' | |
#define JUNK_CHAR '@' | |
#define FENCE_CHAR 'X' | |
/* global variable definitions */ | |
char field[YDIM][XDIM], | |
field_save[YDIM][XDIM]; | |
int robot_y[MAX_ROBOTS], | |
robot_x[MAX_ROBOTS], | |
robot_y_save[MAX_ROBOTS], | |
robot_x_save[MAX_ROBOTS], | |
my_x, | |
my_y, | |
last_stand, | |
my_x_save, | |
my_y_save, | |
no_robots, | |
no_fences; | |
unsigned int seed; | |
/* Prototypes */ | |
void initial(void); | |
void instruct(void); | |
void new_board(void); | |
void old_board(void); | |
int move_me(void); | |
int move_robots(void); | |
int more_robots(void); | |
void draw_board(void); | |
void getnum(int *number); | |
void findspot(int *new_y, int *new_x); | |
int rnd(int range); | |
int sgn(int number); | |
void move(int y, int x); | |
void clrtoeol(int y, int x); | |
void clear(void); | |
void print_me(void); | |
void print_robot(void); | |
void flash(int y, int x); | |
int main() | |
{ | |
int i_won, | |
game_over, | |
set_up, | |
c; | |
initial(); | |
instruct(); | |
set_up=TRUE; | |
while(TRUE) { | |
if(set_up) | |
new_board(); | |
else | |
old_board(); | |
last_stand=FALSE; | |
game_over=FALSE; | |
i_won=FALSE; | |
while(!game_over) { | |
if(!last_stand) | |
game_over=move_me(); | |
if(!game_over) | |
game_over=move_robots(); | |
else | |
break; | |
if(!game_over) { | |
if(more_robots()==TRUE) | |
continue; | |
else { | |
i_won=TRUE; | |
break; | |
} | |
} | |
} | |
if (i_won) { | |
move(21,0); | |
printf("You have destroyed all your opponents -- the game is yours"); | |
} | |
move(22,0); | |
printf("another game? (y/n)"); | |
c=getchar(); | |
c=tolower(c); | |
if(c=='n') | |
break; | |
move(23,0); | |
printf("same set-up? (y/n)"); | |
c=getchar(); | |
c=tolower(c); | |
if(c=='y') | |
set_up=FALSE; | |
else | |
set_up=TRUE; | |
} | |
clear(); | |
move(22,0); | |
return EXIT_SUCCESS; | |
} | |
/* | |
* get a seed for the random number generator | |
*/ | |
void initial() | |
{ | |
clear(); | |
do { | |
clrtoeol(10,0); | |
printf("Enter a seed for the random number generator? "); | |
getnum((int *)&seed); | |
} while(seed<=0); | |
move(18,0); | |
printf("Be sure to lock the NUM LOCK KEY to use the numeric keypad"); | |
} | |
/* | |
* print instructions | |
*/ | |
void instruct() | |
{ | |
int c; | |
move(20,0); | |
printf("do you want instructions? (y/n)"); | |
c=getchar(); | |
c=tolower(c); | |
if (c=='y') { | |
clear(); | |
move(2,0); | |
printf("you are within the walls of a high voltage maze\r\n"); | |
printf("the areas marked '%c' are high voltage fences\r\n",FENCE_CHAR); | |
printf("being chased by robots\r\n"); | |
printf("your only chance for survival is to maneuver each\r\n"); | |
printf("robot into a fence\r\n"); | |
printf("you are the '%c' the robots are the '%c'\r\n",MY_CHAR,ROB_CHAR); | |
printf("moves are: 7.8.9\r\n"); | |
printf(" 4.*.6\r\n"); | |
printf(" 1.2.3\r\n"); | |
printf("\r\nj = a tremendous (but unfortunately random leap)\r\n"); | |
printf("s = no move for rest of the game\r\n"); | |
printf("q = gave up, situation hopeless.\r\n"); | |
printf("\r\n\r\ngood luck!!"); | |
move(22,0); | |
printf("press any key to begin"); | |
c=getchar(); | |
} | |
} | |
/* | |
* create and display a new playing board | |
*/ | |
void new_board() | |
{ | |
int y_coor, | |
x_coor, | |
fen_count, | |
rob_count; | |
clear(); | |
do { | |
clrtoeol(10,0); | |
printf("how many robots? (5 to 120) "); | |
getnum(&no_robots); | |
} while(no_robots<MIN_ROBOTS||no_robots>MAX_ROBOTS); | |
do { | |
clrtoeol(12,0); | |
printf("how many fences? (5 to 120) "); | |
getnum(&no_fences); | |
} while(no_fences<MIN_FENCES||no_fences>MAX_FENCES); | |
clear(); | |
move(10,34); | |
printf("working....."); | |
for(y_coor=0; y_coor<YDIM; y_coor++) { | |
for(x_coor=0; x_coor<XDIM; x_coor++) | |
field[y_coor][x_coor]=' '; | |
} | |
for (y_coor=0; y_coor<YDIM; y_coor++) { | |
field[y_coor][0]=FENCE_CHAR; | |
field[y_coor][XDIM-1]=FENCE_CHAR; | |
} | |
for(x_coor=0; x_coor<XDIM; x_coor++) { | |
field[0][x_coor]=FENCE_CHAR; | |
field[YDIM-1][x_coor]=FENCE_CHAR; | |
} | |
for(fen_count=0; fen_count<no_fences; fen_count++) { | |
findspot(&y_coor, &x_coor); | |
field[y_coor][x_coor]=FENCE_CHAR; | |
} | |
findspot(&my_y, &my_x); | |
field[my_y][my_x]=MY_CHAR; | |
for (rob_count=0; rob_count<no_robots; rob_count++) { | |
findspot(&robot_y[rob_count], &robot_x[rob_count]); | |
field[robot_y[rob_count]][robot_x[rob_count]]=ROB_CHAR; | |
} | |
for (y_coor=0; y_coor<YDIM; y_coor++) { | |
for (x_coor=0; x_coor<XDIM; x_coor++) { | |
field_save[y_coor][x_coor]=field[y_coor][x_coor]; | |
} | |
} | |
for (rob_count=0; rob_count<no_robots; rob_count++) { | |
robot_y_save[rob_count]=robot_y[rob_count]; | |
robot_x_save[rob_count]=robot_x[rob_count]; | |
} | |
my_y_save=my_y; | |
my_x_save=my_x; | |
draw_board(); | |
} | |
/* | |
* reload and display the previous board | |
*/ | |
void old_board() | |
{ | |
int y_coor, | |
x_coor, | |
rob_count; | |
for(y_coor=0; y_coor<YDIM; y_coor++) { | |
for(x_coor=0; x_coor<XDIM; x_coor++) { | |
field[y_coor][x_coor]=field_save[y_coor][x_coor]; | |
} | |
} | |
for(rob_count=0; rob_count<no_robots; rob_count++) { | |
robot_y[rob_count]=robot_y_save[rob_count]; | |
robot_x[rob_count]=robot_x_save[rob_count]; | |
} | |
my_y=my_y_save; | |
my_x=my_x_save; | |
draw_board(); | |
} | |
/* | |
* player's movement routine | |
*/ | |
int move_me() | |
{ | |
int c, | |
my_x_old, | |
my_y_old; | |
my_x_old=my_x; | |
my_y_old=my_y; | |
move(22,69); | |
putchar('*'); | |
putchar('\b'); | |
while(TRUE) { | |
c=getchar(); | |
c=tolower(c); | |
if(isdigit(c)||c=='j'||c=='s'||c=='q') | |
break; | |
if(c==0) /* trap for funtion keys */ | |
c=getchar(); | |
putchar('\007'); | |
} | |
putchar(c); | |
switch(c) { | |
case '1': | |
my_y++; | |
my_x--; | |
break; | |
case '2': | |
my_y++; | |
break; | |
case '3': | |
my_y++; | |
my_x++; | |
break; | |
case '4': | |
my_x--; | |
break; | |
case '6': | |
my_x++; | |
break; | |
case '7': | |
my_y--; | |
my_x--; | |
break; | |
case '8': | |
my_y--; | |
break; | |
case '9': | |
my_y--; | |
my_x++; | |
break; | |
case 'q': | |
clear(); | |
move(10,36); | |
printf("chicken\n\n\n"); | |
move(22,0); | |
exit(0); | |
case 'j': | |
my_y=1+rnd(YDIM-2); | |
my_x=1+rnd(XDIM-2); | |
break; | |
case 's': | |
last_stand=TRUE; | |
break; | |
default: | |
break; | |
} | |
field[my_y_old][my_x_old]=' '; | |
move(my_y_old,my_x_old); | |
putchar(' '); | |
c=field[my_y][my_x]; | |
switch(c) { | |
case ROB_CHAR: | |
flash(my_y,my_x); | |
flash(my_y,my_x); | |
move(my_y,my_x); | |
printf("**MUNCH**"); | |
move(21,0); | |
printf("You have been eaten by robots"); | |
return(TRUE); | |
case FENCE_CHAR: | |
case JUNK_CHAR: | |
flash(my_y,my_x); | |
flash(my_y,my_x); | |
move(my_y,my_x); | |
printf("**ZAP**"); | |
move(21,0); | |
printf("High Voltage!!! Zap, you're dead!"); | |
return(TRUE); | |
default: | |
field[my_y][my_x]=MY_CHAR; | |
move(my_y,my_x); | |
print_me(); | |
break; | |
} | |
return(FALSE); | |
} | |
/* | |
* movement routine for robots | |
*/ | |
int move_robots() | |
{ | |
int rob_count, | |
c; | |
for(rob_count=0; rob_count<no_robots; rob_count++) { | |
if((c=field[robot_y[rob_count]][robot_x[rob_count]])!=ROB_CHAR) | |
continue; | |
move(robot_y[rob_count], robot_x[rob_count]); | |
putchar(' '); | |
field[robot_y[rob_count]][robot_x[rob_count]]=' '; | |
robot_y[rob_count]=robot_y[rob_count]+sgn(my_y-robot_y[rob_count]); | |
robot_x[rob_count]=robot_x[rob_count]+sgn(my_x-robot_x[rob_count]); | |
c=field[robot_y[rob_count]][robot_x[rob_count]]; | |
switch(c) { | |
case MY_CHAR: | |
move(robot_y[rob_count],robot_x[rob_count]); | |
print_robot(); | |
field[robot_y[rob_count]][robot_x[rob_count]]=ROB_CHAR; | |
flash(robot_y[rob_count],robot_x[rob_count]); | |
flash(robot_y[rob_count],robot_x[rob_count]); | |
move(robot_y[rob_count],robot_x[rob_count]); | |
printf("**MUNCH**"); | |
move(21,0); | |
printf("you have been eaten by robots"); | |
return(TRUE); | |
case ROB_CHAR: | |
move(robot_y[rob_count],robot_x[rob_count]); | |
putchar(JUNK_CHAR); | |
field[robot_y[rob_count]][robot_x[rob_count]]=JUNK_CHAR; | |
flash(robot_y[rob_count],robot_x[rob_count]); | |
break; | |
case JUNK_CHAR: | |
flash(robot_y[rob_count],robot_x[rob_count]); | |
break; | |
case FENCE_CHAR: | |
flash(robot_y[rob_count],robot_x[rob_count]); | |
break; | |
default: | |
move(robot_y[rob_count],robot_x[rob_count]); | |
print_robot(); | |
field[robot_y[rob_count]][robot_x[rob_count]]=ROB_CHAR; | |
break; | |
} | |
} | |
return(FALSE); | |
} | |
/* | |
* check whether more robots are still alive | |
*/ | |
int more_robots() | |
{ | |
int rob_count; | |
for(rob_count=0; rob_count<no_robots; rob_count++) { | |
if(field[robot_y[rob_count]][robot_x[rob_count]]==ROB_CHAR) | |
return(TRUE); | |
} | |
return(FALSE); | |
} | |
/* | |
* draw the board from the array board[][] | |
*/ | |
void draw_board() | |
{ | |
int y_coor, | |
x_coor, | |
rob_count; | |
clear(); | |
move(0,0); | |
for(y_coor=0; y_coor<YDIM; y_coor++) { | |
for(x_coor=0; x_coor<XDIM; x_coor++) { | |
putchar(field[y_coor][x_coor]); | |
} | |
move(y_coor+1,0); | |
} | |
move(my_y,my_x); | |
print_me(); | |
for(rob_count=0; rob_count<no_robots; rob_count++) { | |
move(robot_y[rob_count],robot_x[rob_count]); | |
print_robot(); | |
} | |
move(1,63); | |
printf("Move Control:"); | |
move(2,67); | |
printf("7 8 9"); | |
move(3,68); | |
printf("\\|/"); | |
move(4,67); | |
printf("4-5-6"); | |
move(5,68); | |
printf("/|\\"); | |
move(6,67); | |
printf("1 2 3"); | |
move(9,66); | |
printf("Commands:"); | |
move(10,63); | |
printf("j - a giant jump"); | |
move(11,63); | |
printf("s - last stand"); | |
move(12,63); | |
printf("q - quit"); | |
move(15,66); | |
printf("Key:"); | |
move(16,63); | |
printf("* - you"); | |
move(17,63); | |
printf("+ - robot"); | |
move(18,63); | |
printf("@ - junked robot"); | |
move(19,63); | |
printf("X - electic fence"); | |
move(22,63); | |
printf("Move [*]"); | |
} | |
/* | |
* get a numeric input from the player | |
* non-numberic characters are locked out | |
* and the maximum length is arbitrarily set | |
* at 5 digits | |
*/ | |
void getnum(int *number) | |
{ | |
int c, | |
count; | |
char string[6]; | |
count=0; | |
while((c=getchar())!='\n'&&c!='\r') { | |
switch(c) { | |
case '1': | |
case '2': | |
case '3': | |
case '4': | |
case '5': | |
case '6': | |
case '7': | |
case '8': | |
case '9': | |
case '0': | |
if(count<5) { | |
string[count++]=c; | |
putchar(c); | |
} | |
break; | |
case '\b': | |
if(count>0) { | |
count--; | |
putchar('\b'); | |
putchar(' '); | |
putchar('\b'); | |
} else { | |
putchar('\007'); | |
} | |
break; | |
default: | |
putchar('\007'); | |
break; | |
} | |
} | |
string[count]='\0'; | |
*number = atoi(string); | |
} | |
/* | |
* locate a empty board position | |
*/ | |
void findspot(int *new_y, int *new_x) | |
{ | |
do { | |
*new_y=1+rnd(YDIM-2); | |
*new_x=1+rnd(XDIM-2); | |
} while(field[*new_y][*new_x] != ' '); | |
} | |
/* | |
* generate a random number in the | |
* range 0<= number < range | |
*/ | |
int rnd(int range) | |
{ | |
float x; | |
seed = (seed * 15625) & 0xFFFF; /* Multiplication mod 65536 */ | |
x=(seed/65536.0)*(float)range; | |
return((int)x); | |
} | |
/* | |
* return the sign of a number | |
*/ | |
int sgn(int number) | |
{ | |
if (number<0) | |
return(-1); | |
if(number>0) | |
return(1); | |
return(0); | |
} | |
/***************************************************************************** | |
* | |
* these routines assume that the ANSI.SYS driver | |
* has been loaded | |
* | |
*****************************************************************************/ | |
void move(int y, int x) | |
{ | |
printf("\033[%d;%dH",y+1,x+1); /* cursor postions are incremented | |
by one because playing board | |
starts at (0,0) and screen | |
starts at (1,1) */ | |
} | |
void clrtoeol(int y, int x) | |
{ | |
move(y,x); | |
printf("\033[K"); | |
} | |
void clear() | |
{ | |
printf("\033[2J"); | |
} | |
void print_me() | |
{ | |
printf("\033[1m"); | |
putchar(MY_CHAR); | |
printf("\033[0m"); | |
} | |
void print_robot() | |
{ | |
printf("\033[1m"); | |
putchar(ROB_CHAR); | |
printf("\033[0m"); | |
} | |
void flash(int y, int x) | |
{ | |
int count, | |
c; | |
c=field[y][x]; | |
move(y,x); | |
for(count=0; count<20; count++) { | |
printf("\033[1m"); | |
putchar(80); | |
putchar('\b'); | |
printf("\033[0m"); | |
putchar(c); | |
putchar('\b'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment