MAG Disk (Apr 1990) : HANGMAN / hangman.c

/* hangman.c - a hangman game similar to one seen on some *nix machines.*
 *									*
 * hangman [wordlist]							*
 *	    if wordlist is not specified, reads words in current 	*
 *	    directory if it exists, else reads dict:words.		*
 *									*
 * hangman (C) 1989 by Gary L. Brant					*
 *									*
 * :ts=8								*/

#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <stat.h>

char word[30];
char dead_man[][4] = {
	" O ",
	"/|\\",
	" | ",
	"/ \\"
};

char guessed[28];	/* letters already guessed */
int count = 0;		/* count of letters in guessed */
char blimp[30];		/* string of -'s length of word */
char dictionary[30];	/* file name of dictionary */
float curavg = 0.0;
float overavg = 0.0;
int wordno = 0;
long totalwrong = 0L;
int done = 0;
int raw_mode = 0;	/* true if currently in raw mode */
FILE *dict, *fopen ();
struct stat statbuf;
long size;


main (argc, argv)
int argc;
char *argv[];
{
    int i;

    if (argc > 1) {
	if ((dict = fopen (argv[1], "r")) == NULL) {
	    printf ("can't open %s\n", argv[1]);
	    exit (20);
	} else
	    strcpy (dictionary, argv[1]);
    } else if ((dict = fopen ("words", "r")) == NULL) {
	if ((dict = fopen ("dict:words", "r")) == NULL) {
	    printf ("can't find dictionary\n");
	    exit (20);
	} else
	    strcpy (dictionary, "dict:words");
    } else
	strcpy (dictionary, "words");
    if ((stat (dictionary, &statbuf)) == -1) {
	printf ("can't get info for %s\n", dictionary);
	quit (10);
    }
    size = statbuf.st_size;
    srand ((int) time ((long *) 0));	/* use time as random seed */

    do {		/* loop until user says no more */
	getword ();	/* get word from dictionary */

	set_raw ();
	raw_mode = 1;
	hangman ();	/* play one word game */
	newgame ();
	set_con ();
	raw_mode = 0;
    } while (!done);

    quit (0);
}


/* get a random number. */

long getran () 
{
    long time ();
    unsigned long i, j;

    i = rand ();
    j = rand ();
    i += 65536 * j;	/* fabricate a random long int */
    return (i);
}


/* get a word from the dictionary for use in the game */

getword ()
{
    register int i, len;
    long num;
    long position;

    for (;;) {
	num = getran ();	/* get an random long integer */ 
	position = num % size;

	if ((fseek (dict, position, 0)) != 0) {
	    printf ("can't seek on %s\n", dictionary);
	    quit (10);
	}
	fgets (word, 29, dict);
	if (fgets (word, 29, dict) == NULL)
	    continue;

	if ((len = strlen (word) - 1) < 4)
	    continue;

	for (i = 0; i < len; i++)
	    if (word[i] < 'a' || word[i] > 'z')
		goto nogood;
	word[len] = '\0';
	return;			/* return word found */
nogood:
	continue;
    }
}


/* play one word game, return as soon as guesses used up or word guessed.
 * Display a congratulatory message before exiting if player guessed the
 * word, else display the word.
 */

hangman ()
{
    char guess;			/* the current guess */
    int i;
    int togo;			/* number of letters still to be guessed */
    int wrong = 0;		/* number of incorrect guesses */

    char getcharacter ();	/* get user's input */


    nextword ();
    redraw ();

    togo = strlen (word);
    while (togo > 0) {		/* haven't guessed all the characters */
	int dup = 0;		/* if letter was guessed before */
	for (;;) {		/* do until guess is a character */
	    scr_curs (12, 8);
	    scr_eol ();
	    fflush (stdout);

	    guess = getcharacter ();
	    putc (guess, stdout);
	    if (guess == '\f')	/* redraw screen if ^L */
		redraw	();
	    else if (!isalpha (guess)) { /* disallow non-alpha characters */
		scr_beep ();
		scr_curs (12, 8);
		scr_eol ();
		scr_curs (13, 0);
		fputs ("Not a valid guess, ", stdout);
		if (guess < ' ') {
		    char bad[4];

		    bad[0] = '^';
		    bad[1] = guess + 'A' - 1;
		    bad[2] = '\0';
		    fputs (bad, stdout);
		} else
		    putc (guess, stdout);
	    } else
		break;			/* drop out of loop if alpha */
	}

	for (i = 0; guessed[i]; i++)
	    if (guess == guessed[i]) {
		dup = 1;
		break;
	    }
	scr_curs (13, 0);
	scr_eol ();
	if (dup) {			/* if previously guessed */
	    printf ("Already guessed %c", guess);
	    dup = 0;
	} else {
	    int inword = 0;		/* if guess in word */
	    for (i = 0; word[i]; i++) {
		if (guess == word[i]) {
		    inword = 1;
		    togo--;
		    blimp[i] = guess;
		    scr_curs (11, i+8);
		    putc (guess, stdout);	/* place letter in word */
		    if (togo == 0) {		/* if word completed */
			insert (guess);
			scr_curs (13, 0);
			fputs ("You got it!", stdout);
			return;
		    }
		}
	    }
	    if (!inword) {
		wrong++;			/* scorekeeping */
		totalwrong++;
		curavg += 1.0 / ((float) wordno);
		scr_curs (6, 49);	/* update current average on screen */
		printf ("%8.4f", curavg);
		switch (wrong) {
		case 1: scr_curs (3, 10);
			putc ('O', stdout);
			dead_man[0][1] = 'O';
			break;
		case 2: scr_curs (4, 10);
			putc ('|', stdout);
			dead_man[1][1] = '|';
			break;
		case 3: scr_curs (5, 10);
			putc ('|', stdout);
			dead_man[2][1] = '|';
			break;
		case 4: scr_curs (6, 9);
			putc ('/', stdout);
			dead_man[3][0] = '/';
			break;
		case 5: scr_curs (4, 9);
			putc ('/', stdout);
			dead_man[1][0] = '/';
			break;
		case 6: scr_curs (4, 11);
			putc ('\\', stdout);
			dead_man[1][2] = '\\';
			break;
		case 7: scr_curs (6, 11);
			putc ('\\', stdout);
			dead_man[3][2] = '\\';
			scr_curs (13, 0);
			fputs ("The word was:  ", stdout);
			fputs (word, stdout);
			return;
		}
	    }
	    insert (guess);
	}
    }
    return;
}


/* game over; inquire from player whether to play another */

newgame ()
{
    char c;

    scr_curs (14, 0);
    fputs ("Another word? ", stdout);
    for (;;) {
	fflush (stdout);
	c = getcharacter ();
	if (c == 'n') {
	    done = 1;
	    return;
	} else if (c == 'y')
	    return;
	scr_curs (15, 0);
	fputs ("Please type 'y' or 'n'", stdout);
	scr_curs (14, 15);
    }
}


/* redraw display at beginning of new word or at user request (^L) */

redraw ()
{
    int i;

    scr_clear ();

    scr_curs (1, 5);
    fputs ("______", stdout);

    scr_curs (2, 5);
    fputs ("|    |", stdout);

    scr_curs (3, 5);
    putc ('|', stdout);
    scr_curs (3, 10);
    putc (dead_man[0][1], stdout);
    scr_curs (3, 32);
    fputs ("Guessed:  ", stdout);
    fputs (guessed, stdout);

    scr_curs (4, 5);
    putc ('|', stdout);
    scr_curs (4, 9);
    for (i = 0; i < 3; i++)
	putc (dead_man[1][i], stdout);

    scr_curs (5, 5);
    putc ('|', stdout);
    scr_curs (5, 9);
    for (i = 0; i < 3; i++)
	putc (dead_man[2][i], stdout);
    scr_curs (5, 32);
    printf ("Word #:  %d", wordno);

    scr_curs (6, 5);
    putc ('|', stdout);
    scr_curs (6, 9);
    for (i = 0; i < 3; i++)
	putc (dead_man[3][i], stdout);
    scr_curs (6, 32);
    printf ("Current Average: %8.4f", curavg);

    scr_curs (7, 3);
    fputs ("__|_____", stdout);
    scr_curs (7, 32);
    printf ("Overall Average: %8.4f", overavg);

    scr_curs (8, 3);
    putc ('|', stdout);
    scr_curs (8, 10);
    fputs ("|___", stdout);

    scr_curs (9, 3);
    fputs ("|_________|", stdout);

    scr_curs (11, 1);
    fputs ("Word:  ", stdout);
    fputs (blimp, stdout);

    scr_curs (12, 0);
    fputs ("Guess:", stdout);

    fflush (stdout);
}


/* reset stuff for next word */

nextword ()
{
    int i, j;

    for (i = 0; i < 4; i++)
	for (j = 0; j < 3; j++)
	    dead_man[i][j] = ' ';

    for (i = 0; i < strlen (word); i++)
	blimp[i] = '-';
    blimp[i] = '\0';

    for (i = 0; i < 28; i++)
	guessed[i] = '\0';

    count = 0;
    wordno++;
    overavg = curavg;
    curavg = ((float) totalwrong) / ((float) wordno);
}


/* get user's input */

char getcharacter ()
{

    while (!WaitForChar (Input (), 100L) &&
	   stdin->_bp >= stdin->_bend);
    return (tolower (getc (stdin)));
}


/* insert letter just guessed into list of guessed letters; also update list
 * on screen for player.
 */

insert (guess)
register char guess;
{
    if (count == 0) {			/* first guess ? */
	guessed[count++] = guess;
	scr_curs (3, 42);
	putc (guess, stdout);
    } else {
	register int i, j;

	for (i = 0; i < count; i++)
	    if (guessed[i] > guess)
		break;
	for (j = count; j > i; j--)
	    guessed[j] = guessed[j-1];
	guessed[i] = guess;		/* add the guess to list of */
					/* previously guessed letters*/
	scr_curs (3, i+42);
	fputs (&guessed[i], stdout);	/* update list on screen */
	count++;
    }
}


/* needed, since Manx version apparently doesn't work */

 scr_eol ()
{
    static char clr[] = {0x9b, 'K', '\0'};

    fputs (clr, stdout);
}


/* in order to have a chance at cleaning up & exiting gracefully */

_abort ()
{
    puts ("^C");
    quit (0);
}


quit (code)
int code;
{
    if (dict)
	fclose (dict);
    set_con ();
    exit (code);
}


_wb_parse ()
{
}