games-request@tekred.TEK.COM (02/19/88)
Submitted by: Dan Heller (argv) <island!argv@sun.com> Comp.sources.games: Volume 3, Issue 84 Archive-name: jumble2 [A previously posted game "jumble" only unscrambled words that you fed it. This program plays the whole game, feeding you the jumbled words and letting you try and unscramble them. I compiled and ran this on a Sun 3/60. -br] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: README Makefile jumble.c # Wrapped by billr@saab on Thu Feb 18 16:45:48 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f README -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"README\" else echo shar: Extracting \"README\" \(287 characters\) sed "s/^X//" >README <<'END_OF_README' XJumble -- the game in which you unscramble words to compete for Xpoints on a high score list of 10 and 4 levels of Xdifficulty to choose from. Words are found in /usr/dict/words, Xthe basic dictionary found on all UNIX systems. X XThis program was written by Dan Heller. Xisland!argv@sun.com END_OF_README if test 287 -ne `wc -c <README`; then echo shar: \"README\" unpacked with wrong size! fi # end of overwriting check fi if test -f Makefile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"Makefile\" else echo shar: Extracting \"Makefile\" \(258 characters\) sed "s/^X//" >Makefile <<'END_OF_Makefile' X# simple makefile for jumble Xjumble: jumble.c X cc -o jumble jumble.c X Xinstall: jumble X cp jumble /usr/games X # note: this path is wired into the code X # edit it if you change the path X touch /usr/games/lib/jumble.score X chmod 666 /usr/games/lib/jumble.score END_OF_Makefile if test 258 -ne `wc -c <Makefile`; then echo shar: \"Makefile\" unpacked with wrong size! fi # end of overwriting check fi if test -f jumble.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"jumble.c\" else echo shar: Extracting \"jumble.c\" \(19914 characters\) sed "s/^X//" >jumble.c <<'END_OF_jumble.c' X/* X * Jumble -- the game in which you unscramble words to compete for X * points on a high score list of 10 and 4 levels of X * difficulty to choose from. Words are found in /usr/dict/words, X * the basic dictionary found on all UNIX systems. X * X * This program was written by Dan Heller. X * island!argv@sun.com X * X * compile normally, but if you're on a machine with 16 bit ints, use X * random() at the end of this file. X * X */ X X/* Include files */ X X#include <stdio.h> X#include <ctype.h> X#include <signal.h> X#include <sys/time.h> X#include <sys/types.h> X#include <sys/stat.h> X X/* convenience */ X#define upper(c) (isupper(c) ? c : toupper(c)) X#define lower(c) (islower(c) ? c : tolower(c)) X#define Upper(c) (c = upper(c)) X#define Lower(c) (c = lower(c)) X#define when break;case X#define otherwise break;default X X/* constants */ X#define time_left (int)(start_time + death_time - now) /* time left to guess */ X#define NAMELEN 30 /* length of name for scores */ X#define WORDS_NEEDED 4 /* words needed to get on score file */ X#define the_pope_is_catholic 1 /* while(1) is boring */ X X/* other files */ X#define WORDS "/usr/dict/words" /* where to get words */ X#define SCOREFILE "/usr/games/lib/jumble.scores" /* where scores live */ X Xchar *getlogin(); /* return the login name of user */ Xchar *ordinate(); /* returns "st", "nd", etc. for numbers */ Xchar jumble_word[40]; /* what the word we're jumbling is */ Xchar jumbled[40]; /* what the jumbled word is */ Xint debug; /* debug mode -- lets you cheat */ Xint num_of_words; /* how many words player chose to play */ Xint words_given; /* how many words we've given this round */ Xint passes; /* how many passes the player has used */ Xint total_passes; /* number of passes player has */ Xint gotit; /* did player guess the jumbled word? */ Xint level; /* the difficulty of play player chose */ Xint length; /* length of the current jumbled word */ Xunsigned death_time; /* time you have to unscramble words */ Xtime_t start_time; /* the time of the start of each round */ Xtime_t now; /* what time it is now */ Xlong random(); /* see the end of this file */ Xlong DICTSIZE; /* the size of the dictionary */ XFILE *dictionary; /* file pointer to the dictionary */ X Xunsigned alarm(), extra_credit(); X Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char c; X struct stat buf; X int owner, quit(), lose(); X srandom(getpid()); /* if you're on a 16 bit machine change to srand() */ X if (!(dictionary = fopen(WORDS, "r"))) /* open the dictionary */ X printf("Sorry, can't think of any words right now.\n"), quit(); X fstat(fileno(dictionary), &buf); /* get the file status of dictionary */ X DICTSIZE = buf.st_size; /* got the size of the dictionary */ X signal(SIGALRM, lose); /* tell the alarm what function to go */ X /* to if time runs out */ X signal(SIGINT, quit); /* if they ctrl-c let em quit */ X signal(SIGQUIT,quit); /* same as above */ X owner = (stat(argv[0], &buf) != -1 && buf.st_uid == getuid()); X /* is the player the owner of the program? */ X debug = (owner && argc > 1 && !strcmp(argv[1], "-x")); X /* if they used a -x flag and they're the owner, enter debug mode */ X if (argc > 1 && (!strcmp(argv[1], "-s") || !strcmp(argv[1], "-n"))) X high_score(1,argv[1][1] == 'n' && owner), exit(0); X /* if the player just wants to see the high scores or, if the owner */ X /* wants to see the account names of those on the high scores list */ X printf("Do you want directions? "); X while ((c = getchar()) == ' ' || c == '\t'); X if(c == 'y' || c == 'Y') X help(argv); /* give help if wanted */ X while(c != '\n') X c = getchar(); /* flush the input line */ X get_level(); /* find out how badly to kill */ X while(the_pope_is_catholic) { /* let's play */ X get_num_of_words(); /* how many words this round? */ X gotit = 1; /* so far they're doing fine */ X words_given = passes = 0; /* basic variables get values */ X if ((total_passes = (num_of_words - (-1*level + 5))) < 0) X total_passes = 0; X death_time = (long)55.0 * num_of_words * (1+level / 1.5); X (void) time(&start_time); /* game starts now */ X (void) alarm(death_time); /* alarm goes off in deathtime */ X printf("%d word%s coming.\n\n", X num_of_words, (num_of_words > 1) ? "s" : ""); X printf("You have %d pass%s.\n", X total_passes, (total_passes == 1) ? "" : "es"); X while (gotit > 0 && words_given < num_of_words) { X find_a_word(); X mixit(); X words_given++; /* we're giving another word... */ X printit(); X if(!letemguess()) words_given--; X /* letemguess returns 0 if they passed this word */ X else if(words_given - WORDS_NEEDED > 0) { X printf("\nExtra time for extra words: "); X /* reset alarm */ X (void) alarm(alarm((unsigned)0) + extra_credit()); X } X /* they got it so give them extra credit for words X gotten after words needed */ X } X if (gotit != -1) while(passes < total_passes) { X words_given++; /* for each pass, give away a free word */ X printf("Bonus for unused pass #%d: ",++passes); X start_time += extra_credit(); X } X time(&now); /* get current time and check to see if the current */ X /* score made it. This is based on time taken to */ X /* unscramble all the words */ X and_now(); /* we'll talk about it when we get there */ X } X} X X/* X * get the number of words they wish to unscramble. They have to X * choose at least WORDS_NEEDED to get on the high score file and X * have to choose at least 1 to play (or to exit procedure) X */ Xget_num_of_words() X{ X char buf[15]; X num_of_words = 0; X printf("You need at least %d words to get on the top ten.\n", WORDS_NEEDED); X printf("You get extra time for unscrambling each word over the %d%s word.\n" X ,WORDS_NEEDED, ordinate(WORDS_NEEDED)); X printf("How many words do you want? "); X while(num_of_words <= 0) X if(strlen(gets(buf)) < 1 || (num_of_words = atoi(buf)) <= 0) X printf("Use numbers (greater than 0), please: "); X putchar('\n'); X} X X/* X * just a bunch of print statments describing how to play X */ Xhelp(argv) Xchar **argv; X{ X /* get their login name and scramble it */ X (void) strcpy(jumble_word, getlogin()); X mixit(); /* scramble it */ X puts("\nJumble is a game in which you have to guess what the"); X puts("jumbled word is supposed to be. For example, you would"); X printf("have %d seconds to unscramble \"%s\" to \"%s\".\n", X strlen(jumbled) * 9, jumbled, jumble_word); X puts("\nTyping a '?' gives your time left and reprints the jumbled word."); X puts("Typing a 'q' forfeits that round and tell you the current word."); X puts("Entering 'p' (pass) reveals the current word and goes to the next."); X printf("You get one free pass for every %d%s word.\n", X WORDS_NEEDED, ordinate(WORDS_NEEDED)); X printf("For each word after the %d%s that you successfully unscramble,\n", X WORDS_NEEDED, ordinate(WORDS_NEEDED)); X puts("you get bonus time. That time increases more for each bonus word."); X puts("Some words can be constructed different ways. If your guess is a"); X puts("word that works with the given letters but isn't accepted,"); X puts("try a different word."); X puts("Since you are not penalized for wrong guesses, it is advisable"); X puts("to retype words to get the letters in a different order."); X puts("You can see the high scores without playing by typing:"); X printf("%% %s -s\n",argv[0]); X} X X/* X * get one of four differnt difficulty levels X * level expert finds words that are long and gives you little time X * to unscramble them and easy gives you little words with lots of X * time to unscramble them and the other levels are somewhere in between X * see find_a_word() for details X */ Xget_level() X{ X char c; X level = 0; X puts("\nDifficulty levels:"); X printf("(E)xpert, (H)ard, (M)oderate or (S)imple? "); X while(!level) X switch(c = getchar()) { X when ' ' : case '\t' : break; X when 'E' : case 'e' : /* Expert */ X level = 1; X when 'H' : case 'h' : /* Hard */ X level = 2; X when 'M' : case 'm' : /* Moderate */ X level = 3; X when 'S' : case 's' : /* Simple */ X level = 4; X otherwise : while(c != '\n') c = getchar(); X printf("E, H, M, or S: "); X } X while(getchar() != '\n'); /* flush input stream */ X putchar('\n'); X} X X/* X * finds a random word in the dictionary. X * first, go to random spot in the dictionary X * then, read till the next word -- we will probably have landed X * in the middle of a word so read till a carriage return. X * Now, we either got to a new word, or the end of the dictionary, X * in which case we'll try again. X * Else, we have our word in "jumble_word". X * Next, find out how long the word is and if it's appropriate for X * the level of play, set local variable "Ok" to true and exit. X * we don't want words with upper case letters or numbers. X */ Xfind_a_word() X{ X int c, ok; X printf("Jumbling a word..."); X do { X ok = 0; X (void) fseek(dictionary, (random() % DICTSIZE), 0); X while((c = getc(dictionary)) != EOF && c != '\n') ; X if(fscanf(dictionary, "%s", jumble_word) == EOF) X { clearerr(dictionary); continue; } X if((length = strlen(jumble_word)) >= 5) X switch(level) { X when 4 : if(length <= 6) ok = 1; X when 3 : if(length <= 7) ok = 1; X when 2 : if(length <= 8) ok = 1; X when 1 : ok = 1; /* anything goes */ X } X } while (isupper(jumble_word[0]) || isdigit(jumble_word[0]) || !ok); X putchar('\n'); X} X X/* X * mixit scrambles a word X * "tries" is static -- the function is recursive; if it can't scramble X * a word the first time, we call it again from within itself. X * First, convert the entire word to upper case letters, so that we know X * which letters have been used and which haven't been used. When X * searching for a letter to randomly pick, find one that is upper case X * put it in a random place in the jumbled word variable and change it X * to lower case. X * Sometimes, altho, not often, we randomly scramble a word 5 times and X * each time, it comes out the same as the regular word. X */ Xmixit() X{ X static int tries = 0; X int count = 0, rnd_num; X length = count = strlen(jumble_word); X while( count-- ) X Upper(jumble_word[count]); X count = 0; /* reset count; -1 after loop */ X while( count < length ) { X do rnd_num = random() % length; X while(islower(jumble_word[rnd_num])); X jumbled[count++] = Lower(jumble_word[rnd_num]); X } X jumbled[count] = 0; /* terminate string with a NULL character */ X if (!strcmp(jumble_word, jumbled)) tries++; /* is it different? */ X if (tries > 5) printf("I can't seem to jumble this word: %s\n",jumbled); X else if(tries) mixit(); X tries = 0; X} X X/* X * prints info -- the word you need to unscramble, how much time left X * before you lose, etc... X */ Xprintit() X{ X int count = num_of_words - words_given; X time(&now); X printf(" Time: %D min. %D sec.\n%d word%s left. ", X time_left / 60, time_left % 60, count, (count != 1) ? "s" : ""); X printf("'q' to quit"); X if(passes < total_passes) X printf(", 'p' to pass (%d)", total_passes - passes); X puts("."); X printf("\n Word #%d: \"%s\".\n", words_given, jumbled); X} X X/* X * letemguess -- if time runs out, they lose. if they type a '?' X * goto printit above. if 'q', terminate this round and tell them X * the word. if they guess it, great. if in debug mode, user types X * 'x' and the jumbled word will be printed in parens. X * if they type "pass", and they have passes, tell them word and X * continue with game. X */ Xletemguess() X{ X char guess[80]; X gotit = 0; X printf("---> Guess: "); X while(!gotit && gets(guess)) X if (time_left <= 0) return 1; X else if (!strlen(guess)) printf("Guess: "); X else if (!strcmp(guess, "?")) printit(), printf("Guess: "); X else if (!strcmp(guess, "q") || !strcmp(guess, "Q")) gotit = -1; X else if(!strcmp(guess, jumble_word)) gotit = 1; X else if(debug && !strcmp(guess,"x")) printf("(%s)\n",jumble_word); X else if(!strcmp(guess,"p")) X if (passes >= total_passes) X printf("You have no passes.\nGuess: "); X else { X passes++; X printf("Word was: \"%s\"\nYou have %d pass%s left.\n\n", X jumble_word, total_passes - passes, X (total_passes - passes == 1) ? "" : "es"); X gotit = 1; /* gotit = 1 so as not to exit main loop */ X return 0; /* return 0 if passed. */ X } X else printf("Nope. Guess: "); X if(strcmp(guess, jumble_word)) X clearerr(stdin), gotit = -1; /* in case some jerk ^D's */ X time(&now); /* get current time */ X if (gotit == -1) lose(); X else printf("You got it!\n"); X return 1; X} X X/* X * they lost either by no more time left, or they typed 'q' above. X * set alarm(0) to turn off alarm clock and get the current time. X * if the time_left is 0, time ran out... X * tell them word. X */ Xlose() X{ X (void) alarm(0); X (void) time(&now); X if (gotit == 1) return; /* we're in limbo, between words, whatever... */ X if (time_left < 1) X puts("Time ran out."); X printf("The word was \"%s\".\n", jumble_word); X if (time_left < 1) X fprintf(stderr, "--Hit RETURN--"), gotit = -1; X} X X/* X * we're done with the last round, what does player want to do next? X */ Xand_now() X{ X if (gotit > 0) { X int foo = (death_time - time_left); X printf("Your score: %d word%s in %D min. %D sec. (%2.2f words/min.)\n", X num_of_words, (num_of_words == 1) ? "" : "s", foo / 60, X foo % 60, (float)(words_given / (foo / 60.0))); X high_score(0,0); X } X printf("\nRETURN to Play again, (C)hange skill level, (S)cores, (Q)uit: "); X while(the_pope_is_catholic) X switch(getchar()) { X case ' ' : case '\t' : break; X case '\n' : /* play again, no changes */ X return; X case 'C' : case 'c' : /* get new level of play */ X while(getchar() != '\n'); get_level(); return; X case 'Q' : case 'q' : /* quit */ X quit(); X case 'S' : case 's' : /* look at the scores */ X high_score(1,0); X default : while(getchar() != '\n'); X printf("<cr>, 'c', 's', or 'q': "); X } X} X Xstruct scores { X char sc_name[NAMELEN]; /* this is what they put on the high scores */ X char sc_login[8]; /* this is for their login names */ X long sc_time; /* time taken for that game */ X int sc_words; /* how many words did they play with */ X int sc_level; /* the level of play for that person */ X} top_ten[10]; /* we only want 10 high scores. */ X Xhigh_score(Read, names) Xshort Read, names; /* should we Read the scores, or attempt to enter one */ X{ X struct scores *scp, *temp; /* scp is a score pointer, and temp is */ X /* for temporary storage */ X FILE *scorefp; /* file descriptor of the score file */ X X /* X * fill all ten entries with nothing in case the high score file X * isn't completely filled. X */ X for (scp = top_ten; scp < &top_ten[10]; scp++) { X scp->sc_name[0] = 0; X scp->sc_login[0] = 0; X scp->sc_time = 0; X scp->sc_words = 0; X scp->sc_level = 0; X } X X /* X * open score file for concurrent read/write access and X * read the top ten file into the array X */ X if ((scorefp = fopen(SCOREFILE, "r+")) == 0) X { perror(SCOREFILE); return; } X (void) fread((char *)top_ten, sizeof(struct scores), 10, scorefp); X X if (Read) { /* Print the list */ X printf("Top Jumblers:\n"); X printf("Level\tWords\t\tTime\t words/min\tName\n"); X for (scp = top_ten; scp < &top_ten[10]; scp++) X /* print only those scores that are valid (not 0) */ X if (scp->sc_words >= WORDS_NEEDED && scp->sc_login[0]) { X printf("%s\t%3d\t %2D Min. %2D sec. %2.2f\t%s", X (scp->sc_level == 1) ? X "Expert" : (scp->sc_level == 2) ? X "Hard" : (scp->sc_level == 3) ? X "Medium" : "Easy", X scp->sc_words, scp->sc_time / 60, scp->sc_time % 60, X (float)(scp->sc_words / (scp->sc_time / 60.0)), scp->sc_name); X if (names) X printf("(%s)", scp->sc_login); X putchar('\n'); X } X else break; X } X /* check to see if current score made it */ X else if (num_of_words >= WORDS_NEEDED) { X int count = 0; X signal(SIGQUIT, SIG_IGN); /* we don't want them to leave just yet */ X signal(SIGINT, SIG_IGN); X for (scp = top_ten; scp < &top_ten[10]; scp++) X if (++count && value_cmp(scp)) /* check function value_cmp */ X break; /* if it returns true, current score made it */ X if (scp < &top_ten[10]) { X /* X * move all the other scores down one in the list X */ X for (temp = &top_ten[9]; temp > scp; temp--) X *temp = *(temp-1); X /* X * enter currnet values into list X * and get his name X */ X scp->sc_words = num_of_words; X scp->sc_level = level; X scp->sc_time = death_time - time_left; X (void) strcpy(scp->sc_login, getlogin()); X printf("You made the top ten! (#%d) Enter a name (%d chars): ", X count, NAMELEN); X fgets(scp->sc_name, NAMELEN, stdin); X scp->sc_name[strlen(scp->sc_name) - 1] = 0; X /* X * if they didn't type anything, don't enter the score X * else, rewind the file and enter the new score list X */ X if (!strlen(scp->sc_name)) X printf("No name, no entry.\n"); X else { X rewind(scorefp); X if (fwrite((char *)top_ten, sizeof(struct scores), 10, scorefp) <= 0) X perror(SCOREFILE); X } X } X /* X * They didn't make the top ten, so apologize X * Reset the signal interrupt handlers and close the score file X */ X else printf("Good job. Sorry you didn't make the top ten.\n"); X signal(SIGQUIT, quit); X signal(SIGINT, quit); X (void) fclose(scorefp); X } X} X X/* X * used to compare the current values of the game just played with X * whatever the values are in the current high score entry. If the X * time for the entry is 0, return true because it's a garbage score. X * Also, chekc for difficulty levels -- more difficult levels always X * win over less difficult levels. X * next, check to see if the average words per minute is better than X * that of the current score entry. X */ Xvalue_cmp(entry) Xstruct scores *entry; X{ X if(!entry->sc_time) return 1; X if(level != entry->sc_level) return(level < entry->sc_level); X return (num_of_words / (float)(death_time - time_left) >= X entry->sc_words / (float)(entry->sc_time)); X} X X/* quit -- ignore signals, close files, go away */ Xquit() X{ X signal(SIGQUIT, SIG_IGN); X signal(SIGINT, SIG_IGN); X putchar('\n'); X (void) fclose(dictionary); X exit(0); X} X X/* X * extra crdit given to those brave enough to request more words than X * needed as incentive to play for higher scores. The extra credit is X * given in time (seconds). X * return the actual amount of time awarded X */ Xunsigned Xextra_credit() X{ X int extra; X if (level == 4) extra = 1 + random() % 5; X else extra = ((words_given - WORDS_NEEDED) * ((-1 * level) + 4) * 3); X printf("%d min. and %d sec. bonus time.\n", extra / 60, extra % 60); X return extra; X} X X/* ordinate() adds "th" etc... on the end of numbers */ Xchar * Xordinate(num) Xint num; X{ X if(num % 100 < 21 && num % 100 > 3) return "th"; X switch(num % 10) { X case 1 : return "st"; X case 2 : return "nd"; X case 3 : return "rd"; X default : return "th"; X } X} X X/* XIf you're on a PDP, use this! if You're on a sun, it'll crash your system! Xlong random() X{ X return rand() * 65535L + rand() * 256L + rand(); X} X*/ X END_OF_jumble.c if test 19914 -ne `wc -c <jumble.c`; then echo shar: \"jumble.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0