/* The game of hangman */ /* Will compile on Unix v5 */ /* select a random word initialise mask and no. of lives loop: display mask etc. and prompt user's guess read the user's input and check it if invalid prompt again if the guess is not in the word, decrement lives else update the mask and break loop if completed until no more lives if some lives left, user wins else sympathise */ /* available procedures: randline(filename) returns a pointer to a string containing a random line from the file char *filename; upmask( mask, word, try) insert try character in mask where it matches a letter in word char *mask, *word, try; getguess(good, bad) return a guess character, that it isnt in the good or bad guesses already made char *good, *bad; contains(string, ch) return 0 if ch isnt in string, else return ch char *string, ch; append(string, ch) add the ch to the string char *string, ch; */ #define LEXICON "/usr/lib/w2006" #define GALLOWS 9 #define MAXWORD 64 #define FORMFEED 014 main() { int lives; char tbuf[16]; lives = GALLOWS; printf("Hangman\n-------\n"); for(;;) { lives =- game(lives); if(lives <= 1) { printf("You are the champ!\n"); lives = 2; }; printf("Another game? :"); read(0, tbuf, 16); if(tbuf[0] != 'y') exit(); } } game(lives) { char *word, try; char goodtries[MAXWORD]; char badtries[GALLOWS]; char mask[MAXWORD]; int slives; slives = lives; word = randline(LEXICON); goodtries[0] = badtries[0] = '\0'; upmask(mask, word, '-'); /* initialise mask */ do { printf("\n%d li%s: %s\n", lives, lives == 1?"fe":"ves", mask); try = getguess(goodtries, badtries); /* prompts the user and returns his first valid guess */ if(contains(word, try) == 0) { lives--; append(badtries, try); } else { putchar(FORMFEED); append(goodtries, try); if( upmask(mask, word, try) == 0) break; } } while(lives); if(lives) { printf("\n%s\nYou win!\n", word); return lives/2; } else { printf("\nBefore you die,\nI will tell you the word:\t%s\n", word); return -1; } } upmask( mask, word, try) /* insert try character in mask where it matches a letter in word */ char *mask, *word, try; { register char *sp, *rp; int m; /* to count unknowns */ m = 0; sp = mask; rp = word; if(try<'A') { /* initialising mask only */ while(*rp++) *sp++ = try; *sp = '\0'; return sp-mask; } do { if(try == *rp) *sp++ = try; else if(*sp++ == '-') m++; }while(*++rp); return m; } getguess(good, bad) /* return a guess character, that it isnt in the good or bad guesses already made */ char *good, *bad; { char tbuf[4]; do { if(*bad) printf("[%s]", bad); printf("\tyour guess: "); if(read(0, tbuf, 4) != 2) continue; if(tbuf[0] < 'a' || tbuf[0] > 'z') continue; if(contains(good, tbuf[0]) || contains(bad, tbuf[0])) { printf("already used,\n"); continue; } return tbuf[0]; }while(1); } contains(string, ch) /* return 0 if ch isnt in string, else return ch */ char *string, ch; { register char *sp; sp = string; while(*sp) if(*sp++ == ch) return ch; return 0; } append(string, ch) /* add the ch to the string */ char *string, ch; { register char *sp; sp = string; while(*sp++); *sp = 0; *--sp = ch; } randline(filename) /* returns a pointer to a random line from the file */ char *filename; { int dict, tim[2]; static char buf[128]; register char *sp, *rp; time(tim); srand(tim[1] & 077777); /*arbitrary random starter*/ if((dict = open(filename,0)) == -1) { printf("sorry, can't think of any words today"); exit();}; do { seek(dict, rand()%nblocks(dict), 3); /* % is remainder */ /*seek to some random block*/ seek(dict, rand()%512, 1); /* random byte*/ } while(read( dict, buf, 128) < 128); /* try again if not enough */ close(dict); sp = buf; buf[127] = '\n'; /* in case the word is very long */ while(*sp++ != '\n'); /* first full line starts here */ rp = sp; while(*++sp != '\n'); /* end of first full line */ *sp = '\0'; /* terminate the word with eos instead of eol */ return rp; } nblocks(fildes) /* return number of blocks in open file fildes */ { struct status { int ident[2]; int flags; char nlinks; char uid; char gid; char size0; int size; int addr[8]; int acdate[2]; int date[2]; }; struct status stat; fstat(fildes, &stat); /* to get the length of dict */ return (stat.size0<<7) + ((stat.size>>9)&0177); }