home *** CD-ROM | disk | FTP | other *** search
- /* Performs the following functions.
- 1) Allows the user to input data through a text file.
- 2) Reads in data from the SAT.dat file
- 3) "Randomizes" the data
- 4) Saves the data in randomized order
- 5) Gives the user a multiple choice quiz
-
- SAT Quizzer 0.3 is written by Phil Sarin, and is a complete recoding of SAT
- Quizzer 0.22, also by Phil Sarin.
-
-
- I guess it's time for me to explain how this works. The program uses three
- main methods of storing and accessing data.
-
- 1) The array of linked lists. (allwords vocabulary)
-
- I use this structure in main(), initwords(), getdatafile(),
- gettextfile(), and assemblelist(). The constant NUMSLOTS
- determines the size of the array. This structure might bring
- the idea of chaining (in hash functions) to mind. That is how
- I thought it up.
-
- I wanted to be able to use the computer- generated random
- numbers for a more randomized effect. However, if I simply
- picked a random number every time the program asked a
- question, I would have problems..especially since every
- question should be asked only once. Imagine after
- question 392 out of 393. The program would have to keep
- picking random numbers until it found the array index of the
- one word which had not been asked.
-
- So, I thought up the chaining method. Now, there are NUMSLOTS
- (say 10 for example) array indices which each have a linked
- list. When a random number is generated, I just take an item
- off of chain 0 - 9, depending on the number. This way, when
- word 392 out of 393 has been asked, the computer only needs to
- generate numbers until the right number out of 10 is chosen.
- The advantage: it's a lot quicker to find 1/10 than 1/393.
-
-
- 2) The singly linked list. assemblelist(), putdatafile(), and quiz().
- (wordlist listofwords)
-
- Before the program even starts asking questions, it takes the
- array of linked lists and starts generating random numbers
- between 0 and 9. Each time, one item is removed from a
- corresponding chain, and placed on a singly linked list. This
- list is written back to disk. Thus, it is written back in a
- different order than it was read in.
-
- The singly linked lists is a very programmer-friendly and easy
- structure to use. It was very easy to insert items on it in
- assemblelist(). Additionally, both putdatafile(), and quiz()
- simply went word to word down the entire list. The entire
- thing is dynamic, so the limitations are purely hardware
- dependent. I used this structure because of the ease of
- insertion, and the ease of scrolling through the data.
-
- 3) The dynamic array. quiz(), and showchoices() (ptrarray nodeptrs)
-
- This structure helped me overcome the limitations with earlier
- versions of SAT Quizzer. In order to generate multiple choice
- questions with any tolerable amount of speed, I needed to be
- able to somehow index into my data. Indexing is virtually
- impossible with a linked list. In the earlier Pascal versions
- of SAT Quizzer, I had used an array of pointers to overcome
- this problem. In Pascal, I had to set a maximum limit to the
- number of words allowed in an array. In C, using calloc(), I
- overcame this problem. This dynamic array would also be an
- array of pointers. Each slot in the dynamic array would point
- to a corresponding node in the singly linked list. This way,
- in showchoices(), I could generate a random number between
- 1 and numwords, and easily index into it using the dynamic
- array.
-
-
- I can't possibly go over every nuance of every function. The
- explanation of the data structures should clarify most questions one
- might have about the program.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
- #include "defines.h"
- #include "typedefs.h"
- #include "prototypes.h"
-
- int currentslot = 0; /* For getdatafile and gettextfile. */
- int numwords = 0;
-
- void main(void)
- {
-
- allwords vocabulary;
- wordlist listofwords;
-
- initwords(vocabulary);
- initrandom();
-
- printf("Would you like to use the words which are already in SAT");
- printf("Quizzer\'s database? ");
- if(toupper(getchln()) != 'N')
- getdatafile(vocabulary);
-
- printf("Would you like to input words through a text file? ");
- if(toupper(getchln()) != 'N')
- gettextfile(vocabulary);
-
-
- listofwords = assemblelist(vocabulary);
- putdatafile(listofwords);
- quiz(listofwords);
-
- }
-
- char getchln(void)
- /* Returns a char read from the keyboard and flushes an EOLN if the char is
- not an EOLN. */
- {
-
- char typedin, returnval;
-
- typedin = returnval = getchar();
- while(typedin != '\n')
- typedin = getchar();
-
- return returnval;
-
- }
-
- void initwords(allwords newwords)
- /* Initializes every slot in the newwords array to NULL. */
-
- {
-
- int i;
-
- for(i = 0; i < NUMSLOTS; i++)
- newwords[i] = NULL;
-
- }
-
- void initrandom(void)
- /* Initializes the rand() function with a clock seed. */
- {
-
- int utime;
- long ltime;
-
-
- ltime = time(NULL);
- utime = (unsigned int) ltime / 2;
-
- srand(utime);
-
- }
-
- void getdatafile(allwords vocabulary)
- /* Reads in vocabulary from a binary data file. */
-
- {
-
- FILE *infile;
- wordlist currentword;
- struct entry wordfromfile; /* Used for debugging. I'll leave it in. */
-
- putchar('\n');
- printf("Opening data file...\n");
-
- if((infile = fopen(DATAPATH, "rb")) == NULL)
- printf("Cannot open file. A new file will be made.\n");
- else {
- printf("Reading...\n");
- while(!feof(infile)) {
-
- if(fread(&wordfromfile, sizeof wordfromfile, 1,infile)
- != 1)
- break; /* Don't know why, but EOF is
- unexpectedly encountered here.
- That's why there's a break, and not
- an exit. */
-
- currentword = wordalloc();
- currentword->info = wordfromfile;
- currentword->next = vocabulary[currentslot];
- vocabulary[currentslot] = currentword;
- currentslot = (currentslot + 1) % NUMSLOTS;
- }
-
- }
-
- printf("Closing data file...\n\n");
- fclose(infile);
-
- }
-
- void gettextfile(allwords vocabulary)
- /* Reads in vocabulary from a text file created as such:
-
- partofspeech,word,definition
-
- i.e.
-
- adj,loud,noisy
-
- */
- {
-
- FILE *textfile;
- char textpath[20], inchar;
- wordlist currentword;
- int currentletter;
-
- printf("Please type in the name of the text file. ");
- gets(textpath);
-
- printf("\nOpening text file...\n");
-
- if((textfile = fopen(textpath, "r")) == NULL)
- printf("Could not open file.\n");
- else {
- printf("Reading...\n");
- while(!feof(textfile)) {
-
- currentword = wordalloc();
- /**** Find part of speech. ****/
-
- fgetc(textfile);
- fgetc(textfile);
-
- /* The third letters are all distinct. */
-
- switch(toupper(fgetc(textfile))) {
- case 'U' :
- currentword->info.partofspeech = noun;
- break;
- case 'R' :
- currentword->info.partofspeech = verb;
- break;
- case 'J' :
- currentword->info.partofspeech = adj;
- break;
- default :
- currentword->info.partofspeech = other;
- }
-
- /* Flush out until comma. */
-
- while(fgetc(textfile) != ',') ;
-
- /**** Get word. ****/
-
- for(inchar = fgetc(textfile), currentletter = 0;
- inchar != ',' && currentletter < MAXWORD;
- inchar = fgetc(textfile), currentletter++)
- currentword->info.word[currentletter] =
- inchar;
- /* The loop inputs char by char into the word until
- a comma is encountered. */
-
- currentword->info.word[currentletter] = '\0';
-
- /**** Get meaning. ****/
-
- fgets(currentword->info.definition, MAXMEANING,
- textfile);
- currentletter = strlen(currentword->info.definition);
-
- /* Check to see if letters were truncated because the
- string in the data file was too long. Flush to
- a new line if they were. If they weren't, remove
- the '\n' from the string and replace with '\0'. */
-
- if(currentword->info.definition[currentletter-1]=='\n')
- currentword->info.definition[currentletter - 1]
- = '\0';
- else
- while(fgetc(textfile) != '\n' &&
- !feof(textfile))
- ;
-
- /**** Attach word to data structure. ****/
-
- currentword->next = vocabulary[currentslot];
- vocabulary[currentslot] = currentword;
-
- currentslot = (currentslot + 1) % NUMSLOTS;
-
- }
-
- }
-
- printf("Closing text file...\n\n");
-
- fclose(textfile);
-
- }
-
- wordlist wordalloc()
- /* Allocates enough space for a data object of type struct node. */
-
- {
-
- return (wordlist) malloc(sizeof(struct node));
-
- }
-
- wordlist assemblelist(allwords vocabulary)
- /* Returns the pointer to a linked list. */
-
- {
-
- wordlist nextnode, listsofar = NULL;
- short done, slottouse;
-
-
- printf("\nRandomizing...\n");
-
- for(slottouse = 0, done = 1; slottouse < NUMSLOTS && done; slottouse++)
- done = vocabulary[slottouse] == NULL;
-
- while(!done) {
-
- for(slottouse = rand() % NUMSLOTS; vocabulary[slottouse] ==
- NULL; slottouse = rand() % NUMSLOTS) ;
- numwords++;
- nextnode = vocabulary[slottouse];
- vocabulary[slottouse] = vocabulary[slottouse]->next;
- nextnode->next = listsofar;
- listsofar = nextnode;
- for(slottouse = 0, done = 1; slottouse < NUMSLOTS && done;
- slottouse++)
- done = vocabulary[slottouse] == NULL;
-
- }
-
- return listsofar;
-
- }
-
- void putdatafile(wordlist listofwords)
- /* Saves the data file to disk. */
-
- {
-
- FILE *outfile;
-
- printf("\nOpening file...\n");
- if((outfile = fopen(DATAPATH, "wb")) == NULL) {
- printf("Error opening file.\n");
- exit(1);
- }
-
- printf("Writing...\n");
- while(listofwords) {
-
- if(fwrite(&(listofwords->info), sizeof listofwords->info, 1,
- outfile) != 1) {
- printf("Error writing to disk.\n");
- exit(1);
-
- }
-
- listofwords = listofwords->next;
-
- }
-
- printf("Closing file...\n\n");
- fclose(outfile);
-
- }
-
- void quiz(wordlist listofwords)
- /* Generates multiple choice questions. */
-
- {
-
- char rightanswer, answer;
- ptrarray nodeptrs, p;
- wordlist q;
- int right = 0, numdone = 0;
-
- nodeptrs = calloc(numwords, sizeof(wordlist));
- for(p = nodeptrs, q = listofwords; q; p++, q = q->next)
- *p = q;
-
- while(listofwords) {
- printpos(listofwords->info.partofspeech);
- printf(". %s\n", listofwords->info.word);
- putchar('\n');
- rightanswer = showchoices(nodeptrs,
- listofwords->info.definition, listofwords->
- info.partofspeech);
- printf("\nAnswer: ('a' - 'd', 'q' to quit) ");
-
- if((answer = tolower(getchln())) == 'q')
- break;
-
- numdone++;
-
- if(answer == rightanswer) {
- printf("Right!\n");
- ++right;
- }
- else
- printf("Sorry, the answer is %c.\n", rightanswer);
- putchar('\n');
- listofwords = listofwords->next;
-
- }
-
- printf("Thanks for using SAT Quizzer. You got %d out of %d right.\n",
- right, numdone);
-
- }
-
- void printpos(postype postoprint)
- {
-
- switch(postoprint) {
- case noun :
- printf("noun");
- break;
- case verb :
- printf("verb");
- break;
- case adj :
- printf("adj");
- break;
- case other :
- printf("adv. or prep");
- break;
- }
-
- }
-
- char showchoices(ptrarray nodeptrs, meaningtype correctmeaning, postype
- correctpos)
-
- /* Prints out all the multiple choice options which the user will have. This
- procedure is not very intuitively named unfortunately. It returns the letter
- of the correct answer. */
-
-
- {
-
- short ok, i, j, answernum, randindex;
- meaningtype options[NUMOPTIONS], testmeaning;
- ptrarray p;
- postype testpos;
-
- for(i = 0; i < NUMOPTIONS; i++)
- options[i][0] = '\0';
-
- answernum = rand() % 4;
- strcpy(options[answernum], correctmeaning);
-
- /* Fill in "dummy" choices and print them out. */
-
- for(i = 0, ok = 0; i < NUMOPTIONS; i++, ok = 0) {
- if(i != answernum) {
-
- while(!ok) {
-
- randindex = rand() % numwords;
- p = nodeptrs + randindex;
- strcpy(testmeaning, (*p)->info.definition);
- testpos = (*p)->info.partofspeech;
-
- for(j = 0, ok = testpos == correctpos; j < i &&
- ok; j++)
- ok = strcmp(testmeaning, options[j]) &&
- testpos == correctpos;
-
- ok = ok && strcmp(testmeaning,
- options[answernum]);
-
- }
- strcpy(options[i], testmeaning);
- }
-
- printf("\t%c. %s\n", (char) (i + 'a'), options[i]);
-
- }
-
- return (char) (answernum + 'a');
-
- }
-