home *** CD-ROM | disk | FTP | other *** search
- /*
- * May 28, 1991
- * _ . . _ _ __
- * /_)_(_/_/_)_</_/ (_
- * /
- * '
- *
- * _/_
- * ______ __. _ / _ __ ______ o ____ __/
- * / / / <_(_/|_/_)_<__</_/ (_ / / / <_<_/ / <_(_/_
- *
- *
- *
- *
- * Another public domain game
- * by
- * Harry Karayiannis
- *
- *
- *
- * This is my implementation of the famous game of Master-Mind. I have
- * tried to make the code as portable as possible, so it can compile
- * on any machine with minimal changes. This particular file is meant
- * to be compiled on any ATARI ST with any of the following compilers
- * o gcc
- * o Mark Williams C (I used this one)
- * o Sozobon C
- * o Megamax C
- * o Laser C
- * o Alcyon C
- * o Turbo C (just replace the header file OSBIND.H with TOS.H)
- *
- * To compile it on a different machine, just remove the line
- * " #include <osbind.h> "
- * and replace the function Random(), with the one provided by
- * your compiler. Also, you should **rewrite** the function: disk_free()
- * ---------
- * (If you don't know how to code the function disk_free() on your
- * computer, just use the following code:
- *
- * long disk_free()
- * {
- * return( (long)sizeof(hi_table) );
- * }
- *
- * It will work, unless your disk does not have room to save the table
- * of scorers (normally this is 132 bytes, but it will change if you
- * change the values of the macros defined below)
- * )
- *
- *
- *
- *
- * ==================================================================
- * Disclaimer
- * ==================================================================
- * "I make no warranty with respect to this file, or the programs
- * it describes, and disclaim any implied or explicit suggestions of
- * usefulness for any particular purpose. Use this software only if
- * you are willing to assume all risks and damages, if any, arising
- * as a result, even if it is caused by negligence or other fault."
- * ==================================================================
- */
-
-
-
- #include <stdio.h>
- #include <ctype.h>
-
- /*
- * the following header file is only included for
- * the machine depended call: Random(). If you
- * compile the program on a computer other than the
- * ST, you may have to use a different header file
- * (or none: I think Turbo C on the IBM PC has a
- * random function in its standard library)
- */
- #include <osbind.h>
-
-
- /* MACRO Definitions
- * -----------------
- * if you don't like the current values of the following
- * macros you can change them. The game will be still running fine
- */
- #define MAXTURN 12 /* Maximum # of turns */
- #define MAXNAME 10 /* Maximum # of letters in player's name */
- #define MAXSYMB 5 /* Maximum # of symbols in hidden pattern */
- #define MAXTABL 11 /* Maximum # of entries in table of hi-scores */
-
- /*
- * the following macro clears the screen on a VT52 terminal (ST screen).
- * you should modify it according to your terminal's escape sequences
- * (if you are using Turbo C on an IBM PC (or compatible), you should
- * use the function ClrScr() instead)
- */
- #define clear() putchar(27); putchar('E');
-
-
-
- /* TYPE Definitions
- * ---------------- */
- typedef struct{ /* current player's name and score */
- int score;
- char name[MAXNAME];
- }REC_TYPE;
-
-
-
- /* GLOBAL Variables
- * ---------------- */
- long seedval; /* used for the random-value calculation */
- FILE *seedfile; /* file to keep the seed-value */
- FILE *hi_file; /* file holding the High Scores */
- FILE *lastgame; /* file keeping last player's performance */
- int tab_changed; /* TRUE when table-of-scores has been changed */
- REC_TYPE hi_table[MAXTABL]; /* table of high scorers */
-
-
-
- /* ======================================================================== *
- * main *
- * ======================================================================== */
-
- main()
- {
- /* VARIABLE Declarations
- * --------------------- */
- REC_TYPE lastrec; /* last player's record */
-
- char name[MAXNAME]; /* player's name */
- char secret[MAXSYMB]; /* the hidden pattern */
- char inptrn[MAXSYMB]; /* the input (guessing) pattern */
- char hlpsecret[MAXSYMB]; /* - look in function check() - */
- char hlpinptrn[MAXSYMB]; /* - look in function check() - */
- char answer[2];
-
- int same, identical; /* - look in function check() - */
- int errid; /* error id */
- int score, turn, found;
-
-
- /* FUNCTION References
- * ------------------- */
- long getseed();
- void gethitab();
- void welcome(), readstr(), strupper();
- void init(), info(), error_check();
- void check(), give_hints(), comments(), show_hitab();
- void upd_table(), upd_lastfile(), upd_tabfile(), upd_seed();
- REC_TYPE *getlastgame();
-
-
-
- gethitab(hi_table); /* get/init the hi-table */
- lastrec = *getlastgame(); /* get/init last player's record */
- seedval = getseed(); /* get/init value of seed */
- strcpy(answer,"Y");
- tab_changed = 0; /* init flag to FALSE */
- do{
- init(secret, hlpsecret, &score); /* set initial values */
- welcome(hi_table); /* show welcome screen */
- if ( answer[0] != 'A' ){
- printf("\tWhat is your name? ");
- readstr(name,MAXNAME);
- strupper(name);
- }
- else{
- printf("\tPress <Return> to start the game ");
- rewind(stdin);
- getchar();
- }
- info(lastrec,name);
- found = 0;
- turn = 1;
- printf(" ????? Enter guess # 1: ");
- do{
- readstr(inptrn,MAXSYMB);
- strupper(inptrn); /* convert pattern to uppercase */
- error_check(inptrn,&errid,&turn); /* check for any errors */
-
- if ( !strcmp(inptrn,"Q") || !strcmp(inptrn,"QUIT") ){
- score = turn = 0;
- break;
- }
-
- if ( !strcmp(inptrn,"R") )
- strcpy(inptrn," ");
-
- strcpy(hlpsecret,secret);
- strcpy(hlpinptrn,inptrn);
- check(hlpsecret, hlpinptrn, &identical, &same);
- score = score - turn*100 + (5*identical + 3*same);
- printf("%5d %s ", score, inptrn);
- give_hints(identical,same);
- if ( !strcmp(secret,inptrn) ){
- found = 1; /* TRUE */
- break;
- }
- turn++;
- if ( turn<=MAXTURN )
- printf(" Enter guess #%2d: ", turn);
- }while( turn<=MAXTURN && !found );
-
- if (!found){
- printf("\nThe hidden pattern was <%s>", secret);
- score = 0;
- }
- puts("\n----------------------------------------------------------------\
- ---------------");
- printf("FINAL SCORE:%-5d >>> ", score);
- comments(turn);
- puts("------------------------------------------------------------------\
- -------------");
- upd_table(hi_table, name, score);
- strcpy(lastrec.name, name);
- lastrec.score = score;
- printf("Do you wanna play again (y/n/a)? ");
- rewind(stdin);
- gets(answer);
- strupper(answer);
- seedval = Random();
- }while( answer[0] == 'Y' || answer[0] == 'A' );
-
- puts("\n\n");
- show_hitab(hi_table);
- puts("\n\n");
- upd_lastfile(lastrec);
- upd_tabfile(hi_table);
- upd_seed();
- exit(0);
- }
-
-
-
- /* ======================================================================== *
- * gethitab *
- * ======================================================================== */
-
- void gethitab( hi_table )
- REC_TYPE hi_table[];
- {
- /*
- * load (or initialize) the table of scorers into the array 'hitable[]'
- */
-
- register int i;
-
- /* load the table */
- if ( hi_file=fopen("TABLE.DAT","rb") ){
- for (i=0; i<MAXTABL; i++)
- fscanf(hi_file, "%s%d", hi_table[i].name, &hi_table[i].score);
- fclose(hi_file);
- }
- /* if not on disk, initialize it */
- else
- for (i=0; i<MAXTABL; i++){
- strcpy(hi_table[i].name,"harryk");
- hi_table[i].score = 1100;
- }
- }
-
-
-
- /* ======================================================================== *
- * getseed *
- * ======================================================================== */
-
- long getseed()
- {
- /*
- * get the seed value from the disk
- */
-
- long temp;
-
- if ( seedfile=fopen("SEED.DAT","rb") ){
- fscanf(seedfile, "%ld", &temp);
- fclose(seedfile);
- return(temp);
- }
- return( 11224 );
- }
-
-
-
- /* ======================================================================== *
- * getlastgame *
- * ======================================================================== */
-
- REC_TYPE *getlastgame()
- {
- /*
- * get the name and the score of the last player
- */
-
- REC_TYPE *temp;
-
- /* load name and score from disk */
- temp = (REC_TYPE *) malloc( sizeof(REC_TYPE) );
- if ( lastgame=fopen("LAST.DAT","rb") ){
- fscanf(lastgame, "%s%d", temp->name, &(temp->score) );
- fclose(lastgame);
- }
- /* if not on disk, initialize it */
- else{
- strcpy(temp->name,"harryk");
- temp->score = 1100;
- }
-
- return(temp);
- }
-
-
-
- /* ======================================================================== *
- * welcome *
- * ======================================================================== */
-
- void welcome( table )
- REC_TYPE table[]; /* table of scorers */
- {
- /*
- * display welcome screen and table of scorers
- */
-
- void show_hitab();
-
-
- clear();
-
- /* display the welcome screen */
- puts("\0");
- puts(" () _ _ _ __ __ _ __ ");
- puts(" /\\ ' ) / ' ) ) / ` ' ) ) ");
- puts(" / ) / / /--' /-- /--' ");
- puts(" /__/_ (__/ / (___, / \\_ ");
- putchar('\n');
- puts(" _ _ _ __ () ______ __ _ __ _ _ _ _ _ __ __ ");
- puts(" ' ) ) ) / ) /\\ / / ` ' ) ) ' ) ) ) | ) ' ) ) / )");
- puts(" / / / /--/ / ) --/ /-- /--' / / / ,---|/ / / / / ");
- puts(" / ' (_/ ( /__/_ (_/ (___, / \\_ / ' (_ \\_/ \\ / (_/__/_ ");
- putchar('\n');
-
- /* display the table of scorers */
- show_hitab( table );
- }
-
-
-
- /* ======================================================================== *
- * info *
- * ======================================================================== */
-
- void info( last, name )
- REC_TYPE last; /* information about the last player */
- char name[]; /* name of the current player */
- {
- /*
- * display some useful information for the gameplay
- */
-
- clear();
- printf("Last Player was: %10s - %5d pts\t * - Right symbol,right place\n",
- last.name, last.score);
- printf("Current Player: %10s \t\t# - Right symbol,wrong place\n",
- name);
- puts("----------------------------------------------------------------------\
- ---------");
- puts("SCORE PATTERN HINTS (valid symbols -> A, B, C, D, E, F, G, H)");
- puts("----------------------------------------------------------------------\
- ---------");
- }
-
-
-
- /* ======================================================================== *
- * readstr *
- * ======================================================================== */
-
- void readstr( str, max )
- char str[]; /* the string to be read */
- short max; /* the maximum number of chars to be read */
- {
- /*
- * read a string up to 'max' characters long
- */
-
- register short i;
-
- rewind(stdin);
- for (i=0; (str[i]=getchar()) != '\n' && i<max; i++);
- str[i] = '\0';
- }
-
-
-
- /* ======================================================================== *
- * strupper *
- * ======================================================================== */
-
- void strupper( str )
- char *str;
- {
- /*
- * convert the string 'str' to uppercase
- */
-
- register int i;
-
- for (i=0; str[i] != '\0'; i++)
- if ( islower(str[i]) )
- str[i] = toupper(str[i]);
- }
-
-
-
- /* ======================================================================== *
- * init *
- * ======================================================================== */
-
- void init( secret, hlpsecret, score )
- char secret[]; /* the hidden pattern */
- char hlpsecret[]; /* temporary pattern */
- int *score; /* the score */
- {
- /*
- * initialization code
- * --NOTE--
- * this function uses the machine depended call: Random()
- * when compiling on a machine other than the ST, you should modify
- * the routine so it uses the appropriate function for generating
- * random numbers
- */
-
- register int i;
-
-
- /* generate a random hidden-pattern */
- srand(seedval);
- for (i=0; i<MAXSYMB; i++)
- secret[i] = Random()%8 + 65;
- secret[i] = '\0';
- strcpy(hlpsecret,secret);
-
- /* initialize the score */
- *score = 10125;
- }
-
-
-
- /* ======================================================================== *
- * error_check *
- * ======================================================================== */
-
- void error_check( pattern, id, turn )
- char pattern[]; /* the guessing pattern */
- short *id; /* error id */
- int *turn; /* current turn */
- {
- /*
- * do some error checking on input (guessing pattern)
- */
-
- void strupper(), show_error(), readstr();
- short set_errid();
-
-
- /* if the player types either 'Q' or 'QUIT' (note that the pattern
- * has been already converted to uppercase), then the program stops
- */
- if ( !strcmp(pattern,"Q") || !strcmp(pattern,"QUIT") )
- return;
-
- /* if the user types 'R', show him the current error message */
- else if ( !strcmp(pattern,"R") ){
- show_error(0);
- (*turn)--;
- }
-
- /* when an error occurs, we set the error-id & display x's under the
- * column labelled PATTERN; also, we don't increase the variable 'turn'
- */
- else
- while ( (*id=set_errid(pattern)) != 0 ){
- printf(" xxxxx Enter guess #%2d: ", *turn);
- readstr(pattern,MAXSYMB);
- strupper(pattern);
- if ( !strcmp(pattern,"R") )
- show_error(*id);
- if ( !strcmp(pattern,"Q") || !strcmp(pattern,"QUIT") )
- break;
- }
- }
-
-
-
- /* ======================================================================== *
- * set_errid *
- * ======================================================================== */
-
- short set_errid( pattern )
- char pattern[]; /* guessing pattern */
- {
- /*
- * set the error-id:
- * 0: no errors
- * 1: guessing pattern does not consist of 5 symbols
- * 2: guessing pattern includes illegal symbols
- */
-
- register short i=0;
-
-
- if ( strlen(pattern) != MAXSYMB )
- return(1);
- else
- for (i=0; i<MAXSYMB; i++)
- if ( pattern[i]<'A' || pattern[i]>'H' )
- return(2);
-
- return(0);
- }
-
-
-
- /* ======================================================================== *
- * show_error *
- * ======================================================================== */
-
- void show_error( id )
- short id; /* the error-id */
- {
- /*
- * display an error message, according to the error-id
- */
-
- switch (id){
- case 1: printf("\t\t\t\tERR1> You should enter %d symbols\n",MAXSYMB);
- break;
- case 2: puts("\t\t\t\tERR2> Valid symbols are letters from A to H");
- break;
- default:puts("\t\t\t\t**** NO ERRORS! Keep playing");
- }
- }
-
-
-
- /* ======================================================================== *
- * check *
- * ======================================================================== */
-
- void check( hlpsecret, hlpinptrn, identical, same )
- char hlpsecret[];
- char hlpinptrn[];
- int *identical;
- int *same;
- {
- /*
- * compare the hidden-pattern against the guessing-pattern.
- * the function discovers how many common symbols are placed correctly (*)
- * and how many are not (#). The first number is assigned to the variable
- * 'indentical', the second number is assigned to the variable 'same' (notice
- * that both variables are passed as pointers to the function, so they maintain
- * their values). The strings 'hlpsecret' and 'hlpinptrn' are used in order not
- * to touch the original strings 'secret' and 'pattern', because we need their
- * original contents to be printed on the screen.
- * ----------------------------------------------
- * The algorithm for calculating 'identical' and 'same' is really simple:
- * first we count the correctly placed symbols; every time we find one we
- * replace it with the charcter '!' in the hidden pattern, and with ':' in
- * the guessing pattern. We do that because we do not want to count them
- * again when searching for misplaced symbols. Then we rescan the 2 patterns
- * counting common symbols; again we use the trick with the chars '!' and ':'
- * because this way we will never count the same symbol twice.
- */
-
- int index, member();
- register int i;
-
- /* initialize 'identical' and 'same' */
- *identical = *same = 0;
-
- /* calculate 'identical' */
- for (i=0; i<MAXSYMB; i++)
- if ( hlpsecret[i] == hlpinptrn[i] ){
- hlpsecret[i] = '!';
- hlpinptrn[i] = ':';
- (*identical)++;
- }
-
- /* calculate 'same' */
- for (i=0; i<MAXSYMB; i++){
- index = member(hlpsecret, hlpinptrn[i]);
- if ( index != -1 ){
- hlpsecret[index] = '!';
- hlpinptrn[i] = ':';
- (*same)++;
- }
- }
-
- }
-
-
-
- /* ======================================================================== *
- * member *
- * ======================================================================== */
-
- int member( str, ch )
- char *str, ch;
- {
- /*
- * return the index of the character 'ch' in the string 'str'.
- * if 'ch' is not member of 'str' the function returns -1
- */
-
- register int i;
-
- for (i=0; i<MAXSYMB; i++)
- if ( ch==str[i] )
- return(i);
-
- return(-1);
- }
-
-
-
- /* ======================================================================== *
- * give_hints *
- * ======================================================================== */
-
- void give_hints( identical, same )
- int identical, same;
- {
- /*
- * display the hint-pattern on the screen.
- * the function outputs 'identical' stars and 'same' sharp signs
- */
-
- register int i;
-
- /* print stars */
- for (i=0; i<identical; i++)
- putchar('*');
-
- /* print sharp signs */
- for (i=0; i<same; i++)
- putchar('#');
-
- /* pad the rest with spaces */
- for ( i=(identical+same); i<MAXSYMB; i++ )
- putchar(' ');
-
- }
-
-
-
- /* ======================================================================== *
- * upd_table *
- * ======================================================================== */
-
- void upd_table( table, name, score )
- REC_TYPE table[]; /* table of scorers */
- char name[]; /* name of current player */
- int score; /* final score of current player */
- {
- /*
- * update the table of scorers
- */
-
- void insert();
-
- if ( score > table[9].score )
- {
- tab_changed = 1; /* TRUE */
- insert( table, name, score );
- if ( score==table[0].score )
- puts("C O N G R A T U L A T I O N S !!! You are the TOP-SCORER!!");
- else
- puts("You just entered SUPER MASTER MIND's Top-10 chart !!!!!!");
- puts("-------------------------------------------------------------------\
- ------------");
- }
- }
-
-
-
- /* ======================================================================== *
- * insert *
- * ======================================================================== */
-
- void insert( table, name, score )
- REC_TYPE table[]; /* table of scorers */
- char name[]; /* name of current player */
- int score; /* final score of current player */
- {
- /*
- * insert current player in the table of scorers
- */
-
- register int i, place;
-
- /* find where to put the new entry (store the index in 'place') */
- place=0;
- while( table[place].score > score )
- place++;
-
- /* shift the entries, after 'place', one location to the right */
- for ( i=MAXTABL-1; i>place; i-- ){
- strcpy(table[i].name,table[i-1].name);
- table[i].score = table[i-1].score;
- }
-
- /* put current player in the table of scorers */
- strcpy(table[place].name, name);
- table[place].score = score;
- }
-
-
-
- /* ======================================================================== *
- * upd_lastfile *
- * ======================================================================== */
-
- void upd_lastfile( record )
- REC_TYPE record;
- {
- /*
- * update the file with the data of the last player
- */
-
- long disk_free();
-
-
- if (disk_free() < (long)sizeof(record) )
- {
- puts("\tDISK ERROR: there is not enough space to save file LAST.DAT");
- return;
- }
-
- if ( lastgame=fopen("LAST.DAT","wb") )
- {
- fprintf(lastgame, "%s %d", record.name, record.score);
- fclose(lastgame);
- return;
- }
- puts("\tFILE ERROR: cannot open file LAST.DAT (data are not saved)");
- }
-
-
-
- /* ======================================================================== *
- * upd_tabfile *
- * ======================================================================== */
-
- void upd_tabfile( table )
- REC_TYPE table[];
- {
- /*
- * update the file with the table of scorers
- */
-
- register int i;
- long disk_free();
-
-
- if ( tab_changed ) /* table has been changed */
- {
- if (disk_free() < (long)sizeof(table) )
- {
- puts("\tDISK ERROR: there is not enough space to save file TABLE.DAT");
- return;
- }
-
- if ( hi_file=fopen("TABLE.DAT","wb") ){
- for (i=0; i<MAXTABL; i++)
- fprintf(hi_file, "%s %d", table[i].name, table[i].score);
- fclose(hi_file);
- return;
- }
- puts("\tFILE ERROR: cannot open file TABLE.DAT (data are not saved)");
- }
- }
-
-
-
- /* ======================================================================== *
- * upd_seed *
- * ======================================================================== */
-
- void upd_seed()
- {
- /*
- * update the file with the seed value
- * --NOTE--
- * again, this function uses the machine depended function: Random();
- * when compiling on a machine different than an ST, replace it with
- * the function provided by the BIOS
- */
-
- long disk_free();
-
- if (disk_free() < (long)sizeof(seedval) )
- {
- puts("\tDISK ERROR: there is not enough space to save file SEED.DAT");
- return;
- }
-
- if ( seedfile=fopen("SEED.DAT","wb") )
- {
- fprintf(seedfile, "%ld", Random());
- fclose(seedfile);
- return;
- }
- puts("\tFILE ERROR: cannot open file SEED.DAT (data are not saved)");
- }
-
-
-
- /* ======================================================================== *
- * disk_free *
- * ======================================================================== */
-
- long disk_free()
- {
- /*
- * return the number of free bytes on the disk
- * --NOTE--
- * This function is NOT PORTABLE. It only works on the ST.
- * To compile it on a different machine you should modify it
- */
-
-
- struct {
- unsigned long d_freeAUs; /* free Allocation Units */
- unsigned long d_manyAUs; /* how many AUs on disk */
- unsigned long d_secsize; /* sector size */
- unsigned long d_secperAU; /* sectors per AU */
- }disk;
-
- int drive;
- long free_bytes;
- long free_sectors;
-
-
- drive = Dgetdrv();
- Dfree(&disk, drive+1);
- free_sectors = disk.d_freeAUs * disk.d_secperAU;
- free_bytes = free_sectors * disk.d_secsize;
-
- return(free_bytes);
- }
-
-
-
- /* ======================================================================== *
- * comments *
- * ======================================================================== */
-
- void comments( turn )
- int turn;
- {
- /*
- * print an appropriate message, depending on how
- * many turns it took to find the hidden pattern
- */
-
- switch(turn){
- case 0:printf("RIGHT..THIS IS TOO MUCH FOR YOU, ISN'T IT?");
- break;
- case 1:
- case 2:printf("THAT WAS LUCK! YOU SHOULD TAKE A TRIP TO LAS VEGAS!");
- break;
- case 3:
- case 4:printf("ARE YOU GENIOUS OR JUST LUCKY? CAN YOU DO IT AGAIN?");
- break;
- case 5:
- case 6:printf("THAT WAS IMPRESSIVE! GOOD PERFORMANCE, NICE SCORE!");
- break;
- case 7:
- case 8:printf("SOME PEOPLE CANNOT DO BETTER THAN AVERAGE....RIGHT?");
- break;
- case 9:
- case 10:printf("NOT GOOD ENOUGH! WHY DON'T YOU GIVE IT ANOTHER TRY?");
- break;
- case 11:
- case 12:printf(" AT LAST YOU GOT IT; BUT IT WAS EASY, WASN'T IT?");
- break;
- default:printf("I BET YOUR GPA IS AROUND 2.0! YOU HAVE TO LIVE WITH IT!");
- break;
- }
- putchar('\n');
- }
-
-
-
- /* ======================================================================== *
- * show_hitab *
- * ======================================================================== */
-
- void show_hitab( table )
- REC_TYPE table[];
- {
- /*
- * display the table of scorers
- */
-
- register short i;
-
- puts("\t*->>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<-*");
- puts("\t| T O P S C O R E R S |");
- puts("\t*->>>>>>>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<<<<<<<<<<-*");
-
- for (i=0; i<MAXTABL-1; i++)
- printf("\t| Number #%2d: %-10s with %5d points |\n",
- i+1, table[i].name, table[i].score);
-
- puts("\t*==================================================*");
- }
-