/*
Programmer: Jennifer Leopold
Date: March 23, 2018
File: hw8_functs.cpp
Purpose: This file contains the definitions of the functions
for the program that plays telephone bingo.
*/
#include "hw8_functs.h"
using namespace std;
void sayHello()
{
cout << endl;
cout << BOJACK << ": Hello mother, this is "
<< BOJACK << ".\n";
cout << BEATRICE << ": Oh, hello " << BOJACK << ".\n";
return;
}
void sayGoodbye()
{
cout << BOJACK << ": Goodbye mother.\n";
cout << BEATRICE << ": Oh, goodbye " << BOJACK << ".\n";
return;
}
void initializePlayers(Player players[])
{
for (int i = 0; i < 2; i++)
{
cout << "Enter contestant #" << i+1 << "'s name: ";
cin.getline(players[i].name, MAX_NAME_LENGTH-1);
readInBingoCard(players[i].bingoCard, BINGO_CARD_FILES[i]);
players[i].winner = false;
}
return;
}
void readInBingoCard(BingoCardEntry b[][BINGO_CARD_DIM],
const char filename[])
{
ifstream fin;
fin.clear(); // reset connection
fin.open(filename);
if (!fin)
{
cout << "Cannot open " << filename << "!\n";
exit(1);
}
// Each of 5 lines contains 5 comma-separated words
for (int row = 0; row < BINGO_CARD_DIM; row++)
{
for (int col = 0; col < BINGO_CARD_DIM-1; col++)
{
// First 4 entries in the row have comma after them
fin.getline(b[row][col].word, MAX_WORD_SIZE-1, COMMA);
// "Wildcard" matches anything
if (strcmp(b[row][col].word, WILDCARD) == 0)
b[row][col].matched = true;
else b[row][col].matched = false;
}
// Last entry in the row doesn't have comma after it
fin >> b[row][BINGO_CARD_DIM-1].word;
fin.ignore(500, '\n');
// "Wildcard" matches anything
if (strcmp(b[row][BINGO_CARD_DIM-1].word, WILDCARD) == 0)
b[row][BINGO_CARD_DIM-1].matched = true;
else b[row][BINGO_CARD_DIM-1].matched = false;
}
fin.close();
return;
}
void getRandomMessage(const char filename[], char message[])
{
ifstream fin;
int numEntriesInFile, entryNum;
char msg[MAX_SENTENCE_SIZE];
fin.clear(); // reset connection
fin.open(filename);
if (!fin)
{
cout << "Cannot open " << filename << "!\n";
exit(1);
}
fin >> numEntriesInFile;
fin.ignore(500, '\n');
// Choose random number corresponding to a line in the file
entryNum = (rand() % numEntriesInFile) + 1;
// Read lines 1..entryNum in the file
// (last entry read will be the one we "select")
for (int i = 1; i <= entryNum; i++)
fin.getline(msg, MAX_SENTENCE_SIZE-1);
fin.close();
sanitizeMessage(msg, message);
return;
}
void sanitizeMessage(const char message[], char newMessage[])
{
char word[MAX_WORD_SIZE];
char newWord[MAX_WORD_SIZE];
char punctuation[2];
int i = 0, k;
// We will build a "new" message
strcpy(newMessage, "");
// Parse individual words from the original message
while (i < static_cast<int>(strlen(message)))
{
k = 0;
while ((!ispunct(message[i])) && (!isspace(message[i])))
{
word[k] = message[i];
i++;
k++;
}
word[k] = '\0';
// Change the word if it is a "bad" word, then
// add it on to the end of the newMessage we're building
sanitizeWord(word, newWord);
strcat(newMessage, newWord);
// Add the punctuation or whitespace char onto the
// end of the newMessage we're building
punctuation[0] = message[i];
punctuation[1] = '\0';
strcat(newMessage, punctuation);
// Advance past the punctuation or whitespace char
// that came after that last word
i++;
}
return;
}
void sanitizeWord(const char word[], char newWord[])
{
bool found = false;
int i = 0;
char lcWord[MAX_WORD_SIZE];
// First, convert all chars in word to lowercase
convertToLowercase(word, lcWord);
// See if this is considered a "bad" word; if so,
// change it to the recommended "good" word
while ((i < NUM_SUBSTITUTIONS) && (!found))
{
if (strcmp(lcWord, SUBSTITUTIONS[i].badWord) == 0)
{
found = true;
strcpy(newWord, SUBSTITUTIONS[i].goodWord);
}
else i++;
}
// If it wasn't a "bad" word, leave it as the original
if (!found)
strcpy(newWord, word);
else
{
// If the word was changed and originally started with
// an uppercase letter, make the new word start
// with an uppercase letter
if (isupper(word[0]))
newWord[0] -= 32;
}
return;
}
void convertToLowercase(const char word[], char lcWord[])
{
// Make a new word that has all the same chars as
// the given word, but are in lowercase
for (int i = 0; i < static_cast<int>(strlen(word)); i++)
lcWord[i] = tolower(word[i]);
lcWord[strlen(word)] = '\0';
return;
}
void matchWordsOnBingoCard(BingoCardEntry b[][BINGO_CARD_DIM],
const char msg[])
{
int i = 0, k;
char word[MAX_WORD_SIZE];
char lcWord[MAX_WORD_SIZE];
// Parse individual words from the msg
while (i < static_cast<int>(strlen(msg)))
{
k = 0;
while ((!ispunct(msg[i])) && (!isspace(msg[i])))
{
word[k] = msg[i];
i++;
k++;
}
word[k] = '\0';
// Convert the word to all lowercase letters
convertToLowercase(word, lcWord);
// See if the word is on the Bingo card
matchWordOnBingoCard(lcWord, b);
// Advance past the punctuation or whitespace char
// that came after that last word
i++;
}
return;
}
void matchWordOnBingoCard(const char word[],
BingoCardEntry b[][BINGO_CARD_DIM])
{
for (int row = 0; row < BINGO_CARD_DIM; row++)
for (int col = 0; col < BINGO_CARD_DIM; col++)
if (strcmp(b[row][col].word, word) == 0)
b[row][col].matched = true;
return;
}
bool checkForBingo(const BingoCardEntry b[][BINGO_CARD_DIM])
{
int winningRow, winningCol, winningDiag;
return(checkForBingoInRows(b, winningRow) ||
checkForBingoInColumns(b, winningCol) ||
checkForBingoInDiagonals(b, winningDiag));
}
bool checkForBingoInRows
(const BingoCardEntry b[][BINGO_CARD_DIM], int &winningRow)
{
int row = 0, col;
bool winner = false;
while ((row < BINGO_CARD_DIM) && (!winner))
{
col = 0;
winner = true;
while ((col < BINGO_CARD_DIM) && winner)
if (b[row][col].matched == true)
col++;
else winner = false;
if (!winner) row++;
}
// Record which row the Bingo occurred in
if (winner)
winningRow = row;
else winningRow = -1; // denotes no winning row
return(winner);
}
bool checkForBingoInColumns
(const BingoCardEntry b[][BINGO_CARD_DIM], int &winningCol)
{
int col = 0, row;
bool winner = false;
while ((col < BINGO_CARD_DIM) && (!winner))
{
row = 0;
winner = true;
while ((row < BINGO_CARD_DIM) && winner)
if (b[row][col].matched == true)
row++;
else winner = false;
if (!winner) col++;
}
// Record which column the Bingo occurred in
if (winner)
winningCol = col;
else winningCol = -1; // denotes no winning column
return(winner);
}
bool checkForBingoInDiagonals
(const BingoCardEntry b[][BINGO_CARD_DIM], int &winningDiag)
{
int i, j;
bool winner = true;
winningDiag = NONE;
// Check diagonal from upper left to lower right
i = 0;
while ((i < BINGO_CARD_DIM) && winner)
{
if (b[i][i].matched == true)
i++;
else winner = false;
}
if (winner) winningDiag = UPPERLEFT_TO_LOWERRIGHT;
if (!winner)
{
// Check diagonal from lower left to upper right
winner = true;
i = BINGO_CARD_DIM - 1;
j = 0;
while ((j < BINGO_CARD_DIM) && winner)
{
if (b[i][j].matched == true)
{
i--;
j++;
}
else winner = false;
}
}
if (winner) winningDiag = LOWERLEFT_TO_UPPERRIGHT;
return(winner);
}
void outputBingoCard
(const BingoCardEntry b[][BINGO_CARD_DIM], ostream &fout,
bool checkForWin)
{
bool wonByRow = false, wonByCol = false, wonByDiag = false;
int winningRow, winningCol, winningDiag;
char word[MAX_WORD_SIZE + 2];
if (checkForWin) // determine how Bingo game was won
{
wonByRow = checkForBingoInRows(b, winningRow);
wonByCol = checkForBingoInColumns(b, winningCol);
wonByDiag = checkForBingoInDiagonals(b, winningDiag);
}
for (int row = 0; row < BINGO_CARD_DIM; row++)
{
for (int col = 0; col < BINGO_CARD_DIM; col++)
{
fout << std::setw(15) << std::left;
if ((wonByRow && (row == winningRow)) ||
(wonByCol && (col == winningCol)) ||
(wonByDiag &&
(winningDiag == UPPERLEFT_TO_LOWERRIGHT) &&
(row == col)) ||
(wonByDiag &&
(winningDiag == LOWERLEFT_TO_UPPERRIGHT) &&
(row + col == BINGO_CARD_DIM - 1)))
{
strcpy(word, "[");
strcat(word, b[row][col].word);
strcat(word, "]");
fout << word;
}
else fout << b[row][col].word;
}
fout << endl;
}
return;
}
void outputResults(const Player players[])
{
ofstream fout;
char filename[MAX_LENGTH_FILENAME];
int winnerNum; // 0 or 1
cout << "\n*** Telephone Bingo Game Over ***\n\n";
if ((!players[0].winner) && (!players[1].winner))
cout << "No one won the Bingo game :(\n";
else if (players[0].winner && players[1].winner)
{
cout << "Bingo game ended in a tie!\n\n";
for (int i = 0; i < 2; i++)
{
outputBingoCard(players[i].bingoCard, cout);
cout << endl;
fout.open(WINNING_BINGO_CARD_FILES[i]);
outputBingoCard(players[i].bingoCard, fout);
fout.close();
}
cout << "\nSee the files '"
<< WINNING_BINGO_CARD_FILES[0] << "' and '"
<< WINNING_BINGO_CARD_FILES[1] << "'\n\n";
for (int i = 0; i < 2; i++)
{
cout << players[i].name << "'s prize: ";
outputRandomPrize();
}
}
else
{
winnerNum = players[0].winner? 0 : 1;
cout << players[winnerNum].name << ": BINGO!!!\n";
strcpy(filename, WINNING_BINGO_CARD_FILES[winnerNum]);
outputBingoCard(players[winnerNum].bingoCard, cout);
fout.open(filename);
outputBingoCard(players[winnerNum].bingoCard, fout);
fout.close();
cout << "\nSee the file '" << filename << "'\n\n";
cout << players[winnerNum].name << "'s prize: ";
outputRandomPrize();
}
return;
}
void outputRandomPrize()
{
ifstream fin;
int numEntriesInFile = 0, entryNum;
char prize[MAX_PRIZE_DESCRIPTION_LENGTH] = "nothing";
fin.clear(); // reset connection
fin.open(PRIZE_FILE);
if (!fin)
cout << "Cannot open " << PRIZE_FILE << "!\n";
else
{
// Read until end-of-file to determine # entries in file
while (fin.getline(prize, MAX_PRIZE_DESCRIPTION_LENGTH-1))
numEntriesInFile++;
fin.close();
// Re-open the file
fin.clear();
fin.open(PRIZE_FILE);
// Choose random number corresponding to a line in the file
entryNum = (rand() % numEntriesInFile) + 1;
// Read lines 1..entryNum in the file
// (last entry read will be the one we "select")
for (int i = 1; i <= entryNum; i++)
fin.getline(prize, MAX_PRIZE_DESCRIPTION_LENGTH-1);
fin.close();
}
cout << prize << endl;
return;
}