DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T q

⟦987685f8e⟧ TextFile

    Length: 12727 (0x31b7)
    Types: TextFile
    Names: »qix.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/General/Qix/qix.c« 

TextFile

/* 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();
}