|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T q
Length: 12727 (0x31b7)
Types: TextFile
Names: »qix.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Qix/qix.c«
/* Qix -- a silly version based on a silly video game
* written by Dan Heller as an exapmle program to demonstrate select()
* August 8, 1984
* cc -O -s qix.c -lcurses -ltermlib -o qix
*/
#include <curses.h> /* no/te that most systems include <stdio.h> in here */
#include <sys/time.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#define SCOREFILE "/usr/games/lib/qix/qix.scores"
#define OWNER "play"
#define ever (;;)
#define when break;case
#define otherwise break;default
#define waitfor(c) while(getchar() != c)
#define is_a_line(c) c == '|' || c == '-' || c == '\\' || c == '/'
#define max(a,b) (a) > (b) ? (a) : (b)
#define min(a,b) (a) < (b) ? (a) : (b)
#define decr(var) var = max(1, var - 1)
#define incx(var) var = min(COLS - 2, var + 1)
#define incy(var) var = min(LINES - 2, var + 1)
#define THING '@'
#define OTHER '*'
#define STOP 00000000
#define DOWN 00000001
#define UP 00000002
#define LEFT 00000004
#define RIGHT 00000008
struct region {
int r_ycoord, r_xcoord;
struct region *r_next;
struct region *r_prev; /* double linked list of coords */
} *region, *rp;
struct timeval time_val;
int readFDs, writeFDs, exceptFDs, nfound; /* for select */
char msg_buf[80];
int msg_pos, die(), yposit, xposit, xcomp, ycomp, total, nitems, child;
FILE MSG; /* for _doprnt */
main(argc, argv)
char **argv;
{
char c, old_char = ' ';
int sv[2], baddir = 1, on_a_line = 0, dir = 0, draw = 0;
struct region *coord;
if(argc > 1 && (!strcmp(argv[1], "-x") || !strcmp(argv[1], "-s")))
high_score(1,!strcmp(argv[1],"-x") && !strcmp(getlogin(), OWNER)),
exit(0);
help();
init_board();
region = (struct region *) NULL;
rp = (struct region *) NULL;
if((child = socketpair_fork(AF_UNIX, SOCK_STREAM, 0, sv)) == -1)
oops("sockpair"); /* write to sd[1] */
if(!child) { /* machine follow the human */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
sleep(1);
while(1) {
dir = STOP;
if(read(sv[0], &yposit, sizeof (yposit)) <= 0)
exit(); /* current x and y coords */
if(read(sv[0], &xposit, sizeof (xposit)) <= 0)
exit();
dir = (yposit > ycomp) ? DOWN : UP;
dir |= (xposit > xcomp) ? RIGHT : LEFT;
if(dir & DOWN) incy(ycomp);
if(dir & UP) decr(ycomp);
if(dir & LEFT) decr(xcomp);
if(dir & RIGHT) incx(xcomp);
write(sv[1], &ycomp, sizeof (int));
write(sv[1], &xcomp, sizeof (int));
write(sv[1], &dir, sizeof (int));
}
}
if(child == -1) oops("fork");
for ever {
/* first do what the computer wants to do */
if(!on_a_line && !(rand() % 3)) {
int compdir;
write(sv[1], &yposit, sizeof (int));
write(sv[1], &xposit, sizeof (int));
read(sv[0], &ycomp, sizeof (int));
read(sv[0], &xcomp, sizeof (int));
read(sv[0], &compdir, sizeof (int));
draw_it(ycomp, xcomp, compdir);
}
if (dir) {
if(draw) {
draw_it(yposit, xposit, dir);
if(!(coord = (struct region *)malloc(sizeof(struct region))))
oops("%s, line %d: malloc failed\n", __FILE__, __LINE__);
coord->r_ycoord = yposit;
coord->r_xcoord = xposit;
coord->r_next = (struct region *) NULL;
coord->r_prev = rp; /* previous item in list */
if(nitems++)
rp->r_next = coord, rp = coord;
else region = coord, rp = region;
}
else mvaddch(yposit,xposit,old_char); /* draw old character */
if(dir & DOWN) incy(yposit);
if(dir & UP) decr(yposit);
if(dir & LEFT) decr(xposit);
if(dir & RIGHT) incx(xposit);
old_char = stdscr->_y[yposit][xposit];
mvaddch(yposit,xposit,THING); /* move pen to new position */
if((ycomp == yposit && xcomp == xposit) || is_a_line(old_char)) {
draw = 0, dir = 0;
if(!on_a_line)
on_a_line = 1, close_region(0);
nitems = 0;
}
else on_a_line = 0;
move(yposit,xposit);
refresh();
}
if(checkfd(0, -1, -1)) {
static char lc; /* last command */
read(0, &c, 1);
switch(c) {
when 'j' : case 'x' : case '2' :
if(draw && (lc == 'k' || lc == 'w' || lc == '8'))
close_region(1);
dir = DOWN; lc = c;
when 'k' : case 'w' : case '8' :
if(draw && (lc == 'j' || lc == 'x' || lc == '2'))
close_region(1);
dir = UP; lc = c;
when 'h' : case 'a' : case '4' :
if(draw && (lc == 'l' || lc == 'd' || lc == '6'))
close_region(1);
dir = LEFT; lc = c;
when 'l' : case 'd' : case '6' :
if(draw && (lc == 'h' || lc == 'a' || lc == '4'))
close_region(1);
dir = RIGHT; lc = c;
when 'y' : case 'q' : case '7' :
if(draw && (lc == 'c' || lc == 'n' || lc == '3'))
close_region(1);
dir = UP | LEFT; lc = c;
when 'c' : case 'n' : case '3' :
if(draw && (lc == 'y' || lc == 'q' || lc == '7'))
close_region(1);
dir = DOWN | RIGHT; lc = c;
when 'z' : case 'b' : case '1' :
if(draw && (lc == 'u' || lc == 'e' || lc == '9'))
close_region(1);
dir = DOWN | LEFT; lc = c;
when 'u' : case 'e' : case '9' :
if(draw && (lc == 'z' || lc == 'b' || lc == '1'))
close_region(1);
dir = UP | RIGHT; lc = c;
when ' ' : if(dir) draw = 1;
}
}
}
}
help()
{
char c;
printf("Do you want instructions? ");
if((c = getchar()) != '\n')
while(getchar() != '\n');
if (c != 'y') return;
puts("The best way to learn this game is by playing it, but I'll *try*");
puts("to give you some help here.");
puts("The object of this game is to enclose as many regions as you");
puts("can without touching the edge of the screen, any other region,");
puts("or hitting the 'thing' (or its tail) that's chasing you around");
puts("the screen. If you successfully close a region, you get points");
puts("the 'bricks' that created it. If the region has a tail -- a part ");
puts("of it that is not part of the circumference, the number of bricks ");
puts("in the tail is deducted from your score and those bricks erased ");
puts("from the screen. ");
puts("You may enclose regions inside one another. Once a region is closed");
puts("you may stay on the bricks that surround it, but leaving them ");
puts("means you can not touch them again. This would be a collission. ");
puts("\nYou move the pen (denoted by an 'x') with the vi/rogue keys, the ");
puts("keys surrounding the 's', or a numeric keypad. Figure it out if ");
puts("you're not already familiar with this sort of cursor addressing. ");
puts("You may move diagonally, too. Initially, you do not 'draw' ");
puts("anything until you hit the space-bar. This turns the pen on. You ");
puts("can not turn it off until you connect a region or die trying. ");
puts("Once you do connect a region, your pen is turned off until you ");
puts("hit the space-bar again.");
printf("\n Hit return when ready: ");
while(getchar() != '\n');
}
draw_it(y, x, dir)
{
switch (dir) {
when DOWN : case UP : mvaddch(y,x,'|');
when LEFT : case RIGHT : mvaddch(y,x,'-');
when (DOWN | LEFT) : case (UP | RIGHT) :
mvaddch(y,x,'/');
when (DOWN | RIGHT) : case (UP | LEFT) :
mvaddch(y,x,'\\');
}
}
static struct sgttyb tty;
socketpair_fork(d, type, protocol, sv)
int sv[2];
{
int pid, parent_to_child[2], child_to_parent[2];
if(socketpair(d, type, protocol, parent_to_child) == -1)
return -1;
if(socketpair(d, type, protocol, child_to_parent) == -1) {
close(parent_to_child[0]);
close(parent_to_child[1]);
return -1;
}
if ((pid = fork()) == -1) {
close(parent_to_child[1]);
close(parent_to_child[0]);
return -1;
}
if (pid) { /* this is the parent */
close(parent_to_child[0]);
close(child_to_parent[1]);
sv[0] = child_to_parent[0];
sv[1] = parent_to_child[1];
} else { /* this is the child */
close(child_to_parent[0]);
close(parent_to_child[1]);
sv[0] = parent_to_child[0];
sv[1] = child_to_parent[1];
}
return pid;
}
init_board()
{
char c;
int y, x;
srand(getpid());
gtty(0, &tty);
initscr();
crmode(); noecho();
signal(SIGINT, die);
signal(SIGQUIT, die);
clear();
for(y = 0, x = 0; y < LINES-1; y++) /* move y down left side */
mvaddch(y,x,'|'), refresh();
for(x = 1, y = LINES-2; x < COLS; x++) /* move x across bottom */
mvaddch(y,x,'-'), refresh();
for(x = COLS-1, y = LINES-2; y >= 0; y--) /* move y up right side */
mvaddch(y,x,'|'), refresh();
for(x = COLS-2, y = 0; x > 0; x--) /* move x across top */
mvaddch(y,x,'-'), refresh();
yposit = 2 + rand() % LINES - 4;
xposit = 2 + rand() % COLS - 4;
while((ycomp = 2 + rand() % LINES-4) == yposit);
while((xcomp = 2 + rand() % COLS-4) == xposit);
mvaddch(yposit, xposit, THING);
mvaddch(ycomp, xcomp, OTHER);
move(yposit,xposit); refresh();
}
checkfd(rfd, wfd, efd)
{
rfd = 1 << rfd;
wfd = 1 << wfd;
efd = 1 << efd;
time_val.tv_usec = tty.sg_ospeed <= B300 ? 30000 : 75000;
time_val.tv_sec = 0;
return select(32, &rfd, &wfd, &efd, &time_val);
}
die()
{
msg(" ");
nocrmode(); echo();
move(LINES - 1, 0); clrtoeol(); refresh();
endwin();
high_score(0,0);
high_score(1,0);
exit(0);
}
close_region(did_back_up)
{
bool success = FALSE;
int score = 0;
msg(""), msg("Clunk.");
for( ;!success && rp; rp = rp->r_prev) {
char oldchar;
free(rp);
if(rp->r_next)
mvaddch(rp->r_next->r_ycoord, rp->r_next->r_xcoord, oldchar);
oldchar = stdscr->_y[rp->r_ycoord][rp->r_xcoord];
mvaddch(rp->r_ycoord, rp->r_xcoord, '*'), refresh();
if(rp->r_ycoord == yposit && rp->r_xcoord == xposit)
success = TRUE;
else score++;
}
if(did_back_up) msg("You backed into yourself!");
else if(!success) {
msg("You collided with a different region!");
total -= score;
msg("You lost %d point%s for doing that.",score,score == 1 ? "" : "s");
crunch();
} else {
msg("You got %d point%s for this region.",score,score == 1 ? "" : "s");
total += score, score = 0;
}
for( ; rp; rp = rp->r_prev) {
mvaddch(rp->r_ycoord, rp->r_xcoord, ' ');
score++; refresh();
free(rp);
}
msg("You lost %d point%s for extra lines.", score,score == 1 ? "" : "s");
total -= score;
if(did_back_up) crunch();
msg("Score: %d", total);
region = rp = (struct region *) NULL;
}
crunch()
{
msg("You die with a score of %d.", total);
die();
}
oops(fmt, args)
char *fmt, *args;
{
msg(fmt, args);
die();
}
#define NAMELEN 40
struct Scores {
char sc_name[NAMELEN];
char sc_login[8];
int sc_score;
} top_ten[10];
high_score(Read, names)
int Read, names;
{
struct Scores *scp, *temp;
int fd;
for (scp = top_ten; scp < &top_ten[10]; scp++) {
scp->sc_name[0] = 0;
scp->sc_login[0] = 0;
scp->sc_score = 0;
}
/* read the top ten file into the array */
if ((fd = open(SCOREFILE, 2)) < 0)
{ puts("No score file."); exit(2); }
read(fd, top_ten, sizeof(top_ten));
if (Read) { /* Print the list */
int rank = 0;
puts("Qikest:");
printf("Rank\tScore\tName\n");
for (scp = top_ten; scp < &top_ten[10]; scp++)
if (scp->sc_name[0])
printf("%d\t%3d\t%s %s\n", ++rank,
scp->sc_score,scp->sc_name,(names) ? scp->sc_login : "\b.");
else break;
}
/* check to see if current score made it */
else if(total) {
for (scp = top_ten; scp < &top_ten[10]; scp++)
if(total > scp->sc_score) break;
if(scp < &top_ten[10]) {
for (temp = &top_ten[9]; temp > scp; temp--)
*temp = *(temp-1);
scp->sc_score = total;
strcpy(scp->sc_login, getlogin());
printf("You made the top ten! ");
do {
printf("Enter a name (%d chars): ", NAMELEN);
fgets(scp->sc_name, NAMELEN, stdin);
} while(strlen(scp->sc_name) < 2);
scp->sc_name[strlen(scp->sc_name) - 1] = 0;
lseek(fd, 0, 0); write(fd, top_ten, sizeof top_ten);
close(fd);
}
else puts("Sorry, you're not qik enough for the top ten.");
}
close(fd);
}
static char msgbuf[BUFSIZ];
static int newpos = 0;
msg(fmt, args)
char *fmt;
int *args;
{
if (!*fmt)
{ move(LINES-1, 0), clrtoeol(), newpos = 0; return; }
if(!strcmp(fmt, "repeat"))
{ addstr(msgbuf); return; }
if(newpos) {
move(LINES-1, newpos);
addstr("--more--"); refresh();
waitfor(' ');
newpos = 0;
}
move(LINES-1, 0), clrtoeol();
addmsg(fmt, args);
}
addmsg(fmt, args)
char *fmt;
int *args;
{
MSG._flag = _IOWRT + _IOSTRG;
MSG._ptr = &msgbuf[newpos];
MSG._cnt = 32767;
_doprnt(fmt, &args, &MSG);
fputc(0, &MSG);
newpos = strlen(msgbuf);
addstr(msgbuf);
refresh();
}