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