/* CS 1720 1/12/03 speant 14 hours on this assignment This program makes MadLib stories based on the storyline in a chosen input file and users answers fill-in-the-blank questions in the same file. */ #include #include // for story input file #include // for the various string functions (find, at, replace) #include // for toupper function #include // for atoi function #include using namespace std; char openingMenu(); int getData(const int, string*&, string[], int &); void createStory(string *, string[], int, int); void printPretty(string[], int); /* Main: calls other functions and loops through the program each time the user chooses to play the game instead of quitting. */ int main() { const int MAXLINES = 25; char choice; string * answers; string storylines[MAXLINES]; int blanks, numOfLines = 0; /* Variables: MAXLINES -- the maximum length the story can be (size of storylines array) choice -- records the user's choice to play the game or quit the program *answers -- points to a dynamically allocated array to record the user's fill-in-the-blank answers storylines[] -- stores seperately each line of the story blanks -- number of answers required by the user numOfLines -- records how many lines long the story body is */ cout << "\t\tMAD LIBS LAB\n\n"; choice = openingMenu(); while (toupper(choice)!='Q') { numOfLines = getData(MAXLINES, answers, storylines, blanks); createStory(answers, storylines, blanks, numOfLines); printPretty(storylines, numOfLines); choice = openingMenu(); delete [] answers; } return 0; } /* openingMenu function: Displays the choices to play or quit to the user, obtains and verifies the user's response, and returns this value (letter) to the choice value in main. */ char openingMenu() { char letter; /* Variables: letter -- records the choice to play or quit as entered by the user */ cout << "Play MadLibs or Quit?" << endl; cout << "Enter your choice (P or Q): "; cin >> letter; while (toupper(letter) != 'P' && toupper(letter) != 'Q') { cout << "Invalid choice, enter P (to play) or Q (to quit) only: "; cin >> letter; } return letter; } /* getData function: First gets the name of the input file from the user and verifies it. Then displays the fill-in-the-blank prompts from the file, storing the user's responses in "answers." Last, the lines of the story are stored in storylines[]. The variable "blanks" is assigned its value here (see main) and the value of "lineCount" is returned to "numOfLines" in main. */ int getData(const int MAXLINES, string *& answers, string storylines[], int& blanks) { const int MAXNAME = 80; string answerType; ifstream inFile; char fileName[MAXNAME]; int lineCount = 0; /* Variables: MAXNAME -- maximum length of the fileName Cstring input by the user answerType -- temporary storage for fill-in-the-blank prompts to user lineCount -- counts # of lines in story */ cout << "\nType the name of the input file: \n"; cin.ignore(); cin.getline(fileName, MAXNAME); inFile.open(fileName); while (inFile == NULL) { inFile.clear(); cout << "Error opening file. Retype the name of the input file: \n"; cin.getline(fileName, MAXNAME); inFile.open(fileName); } inFile >> blanks; answers = new string[blanks]; assert(answers != NULL); inFile.ignore(); for (int i=0; i < blanks; i++) { getline(inFile,answerType); cout << "\nType in a " << answerType << endl; getline(cin, answers[i]); } while (!inFile.eof()&& (lineCount < MAXLINES)) { getline(inFile, storylines[lineCount]); lineCount ++; } inFile.close(); return lineCount; } /* createStory function: Scans each line of storylines[] for occurences of '*'s. When found, the next two character numbers are converted to an integer which corresponds to the appropriate index in the answer array. The answer at that index is inserted into the story in place of the *'d number. */ void createStory(string *answers, string storylines[], int blanks, int numOfLines) { const int REPLACE = 3; const int SIZE = 3; const int TENS = 10; int start, position, number, length; char digitA[SIZE]; /* Variables: REPLACE -- # of characters to replace with the answer in the storyline (i.e. *01) SIZE -- size of "digit" cstrings, including null terminator TENS -- used with the atoi number in the "tens" place to get the final number start -- string index of where to start searching for '*' position -- string index location of any '*' for in storylines[] number -- the number converted from the string array corresponding to index in answer array length -- total number of positions in each line of story to be searched for '*' digitA[] -- character digits of number */ for (int i=0; i < numOfLines; i++) { start = 0; length = storylines[i].length(); while (start < length) { position = storylines[i].find('*', start); if (position >= 0) { digitA[0] = storylines[i].at((position+1)); digitA[1] = storylines[i].at((position+2)); digitA[2] = '\0'; number = atoi(digitA); assert(number < 0 || number > blanks); storylines[i].replace(position, REPLACE, answers[number-1]); start = position; } else start = length; } } } /* printPretty function: Prints out the story from the storylines array, making sure that no words are cut off at the end of lines by inserting a newline opperator at the closest space to the edge of the page. The variable "phrases" is a copy of "numOfLines" from main (holds the number of elements in storylines[]. */ void printPretty(string storylines[], int phrases) { const int MAXPOS = 80; int position, oldPos, numPositions, numOfLines, difference; string newLine = "\n"; /* Variables: MAXPOS -- maximum number of characters that can be displayed on one line position -- index of the newest occurence of a space character in the storyline oldPos -- index of the second newest occurence of a space character in the storyline numPositions -- number of characters/positions in the ith element of storylines numOfLines -- one less than the number of lines the ith element of storylines needs to display properly on the screen difference -- difference between the maximum subscript displayed on a line and oldPos, the position where a newline is inserted. newLine -- inserted in a storyline which is too long for one line */ cout << "\n\nYOUR MADLIBS STORY:" << endl << endl; for(int i=0; i < phrases; i++) { numPositions = storylines[i].length(); numOfLines = numPositions/MAXPOS; oldPos = 0; position = 0; difference = 0; position = storylines[i].find(' ', position); for (int j=0; j <= numOfLines; j++) { while ( (position < ((j+1)*MAXPOS-difference)) && (position > 0) ) { oldPos = position; position = storylines[i].find(' ', (position+1)); } difference = (j+1)*MAXPOS-oldPos; if (position >= 0) storylines[i].replace(oldPos, 1, newLine); } cout << storylines[i] << endl << endl; } }