Friday, May 19, 2017

A String Of Words

 
Copyright: My own work.

 

“I don't know half of you half as well as I should like; and I like less than half of you half as well as you deserve.”                                     Lord of the Rings


This quote summarizes my feeling towards Strings, C-Strings, String objects, ... better than I ever could. Translation: I learned about many aspects of strings and their member functions, but could not deepen my understanding. Many were just left unused in my effort to solve any one Programming Challenge, and those I touched, I hardly scratched the surface, yet would like to learn more about them.

A month plus some days ago I thought differently. Virtually every Challenge past 10.02 was a struggle. In theory what is presented in the Chapter should suffice to solve the challenge. It should, but didn't, because many functions wouldn't work without producing security warnings. As I said in a different chapter summary, I take warnings as errors and treat them as such. For instance take strtok, which takes two arguments, versus strtok_s I had to use in Programming Challenge 10.3 to get an accurate count of words. Another example would be Programming Challenge strcat. This is explained in the book, and looks sufficiently easy to use, but also causes a warning when used in VS. Instead I had to use strcat_s and learn how to use it correctly. Learning by doing was the only way to find out how things work this time around. And, surprisingly, maybe except the Morse Code Challenge, I learned solely about the topic the chapter was about. In the previous one's I learned about a myriad other things besides C++, which I truly enjoy, because one can never know enough, just sometimes too much. 

Speaking of Challenge 03, would you believe that this was the one that caused me to consider skipping the Challenges and moving on to the next chapter? Yes, true, I was stuck and started contemplating whether it is worth it. In the books TOC this chapter was on a side branch, pointing to chapters 10 on the left and 12 on the right hand side. It was not, as you probably think, a case of giving up in the face of a set of tough challenges ahead. It was rather just thinking whether it is truly worth it. What potential use will this chapter have in my future endeavor, creating my own game? After some deliberation with myself I decided that it is worth doing it. I wasn't able to see, as opposed to say with arrays what good they would be for, but why should I care? So I kept working, even though it has taken longer and longer from Challenge to Challenge to finish any one of them.

The most I struggled with this last one. It has taken the better part of 7 days to even find a way to achieve the desired output. From day one I was working to get correct results. Every time it looked like it would work, there was a range of digits that, due to the way I had written that part of code, would not display. For instance everything from 1 to 99, 100 to 199, 1100 to 9999 (and in some revisions up to 99,999.99) would show be displayed perfectly, but 1000 to 1100 would not. The output, if there even was one, would be something like "one thousand hundred eleven one," or "one thousand eleven hundred" and the like.

In one of my earliest attempts I tried solving it by accessing substrings to assign the index to the appropriate string array containing the number words, which looked like this:

 if (numStore < 20)
    {
        toWord.append(oToNine[stoi(amount.substr(1,0))]);
    }

    else if (numStore > 9)
    {
        toWord.append(toTwenty[stoi(amount.substr(1, 1))]);
    }
    else if (numStore > 19)
    {
        toWord.append(tenMult[stoi(amount.substr(0, 1))] +
            oToNine[stoi(amount.substr(1, 1))]);
    }

With lower numbers, this approach could have worked, but getting at the hundreds and thousands, it was a totally different story. Not only would the substring positions constantly change, requiring lots of chained lines of code, it would also have been of very limited use if the next Challenge, had there been any, would be to extend it so amounts above and beyond $9,999.99 would be allowed. After starting over again, the conclusion was that using substrings was part to solve the problem, but simply not in this way, or for this purpose. 

It didn't matter that I changed the approach so that it looks like in the final revision uploaded to this blog, there still remained one problem, a range of numbers would not translate correctly. For instance, consider the following function.

string toThousand(string amount, string *oToNine)
{
    string toWord;

    int tAmnt = stoi(amount);
    if (tAmnt % 100 < 100)
    {
        int wHundred = stoi(amount.substr(0,1));

        toWord.append(oToNine[wHundred] + " hundred ");
    }
    else
    {
        int tHundred = stoi(amount.substr(1, 1));

        toWord.append(oToNine[tHundred] + " hundred ");
    }
    return toWord;
}

With such conditions there would always be some overlap, so that instead of 110, "one hundred ten eleven" would be displayed. Or some other such nonsense that simply wasn't correct. Yet, this part in bold was what eventually led me in the direction of a promising solution. Still it was a long way to get there. Leading to detours such as this piece of code:

 getNum <= 99 ? mTen = ones(stoi(amount)) : mTen = tens(stoi(amount.substr(1, 1)));
 getNum < 10 ? toWord.append(one = ones(stoi(amount.substr(0,1)))) : amount;
 getNum % 10 == 0 ? toWord.append(mTen = tenMult(stoi(amount.substr(0, 1)))) : amount;
 getNum % 10 != 0 ? toWord.append(mTen = tenMult(stoi(amount.substr(0,1))) + one = ones(getNum % 10)) : amount;

Or how about this "beauty"? (Which actually works the way it was written and delivered the correct results for this limited range of numbers between 1 and 99. Hence this is also what I described in my last chapter summary when writing about chained conditional statements.)

  getNum < 10                                 ? one = ones(stoi(amount)) :
  getNum >= 10 && getNum < 20  ? mTen = tens(stoi(amount.substr(1,1))) :
  getNum >= 20                               ? mTen = tenMult(stoi(amount.substr(0,1))),
                                                           one = ones(stoi(amount.substr(1,1))) : amount;

Suffice to say that both of the above was very limited in use, and still another step leading my to a solution. When it finally clicked and I found that when using the modulo operator, not for the conditional statements, but for altering the amounts directly, this would be the way to go and it was. Seven days of hard work with hundreds and hundreds lines of failed code, plus an additional two or almost three days, to arrive at the final solution to the problem that actually worked was a long way to go. It has taken less time than the Monkey Business Challenge and its successor of late, the Median function one, but it felt to me as it has taken twice as long as both taken together!

Now, with all this behind me, my summary is still positive. On the whole it was worth every bit of effort to solve the Challenges and never give up just because the solution wouldn't come easy. I foresee that it will take longer still to get past the upcoming chapters, not even thinking about the Challenges lying in wait for me, but I will not skip any of it. Now past half the book and on my way to Chapter 11, I can only hope, as I always do, that it will not be as bad as this one.

With this, I will mentally prepare myself for whatever there may come, and it is once again my pleasure to thank my regular visitors for coming by, as well as a warm welcome to all my new and future visitors. I would also like to thank all my visitors past and present for their continued interest in my humble interpretation of the Rock-Paper-Scisscors game. I hope you enjoy it! For my fellow learners I hope that you will not be covered head to heel in a web of strings, loosing all hope to ever solve any of the Challenges. Never give up, you can do it, if I could! As for me, I will be back soon, with some more code.

Programming Challenge 10.19 - Check Writer

Include File: "EvalDate.h"

/* Check Writer - This program display a simulated paycheck. The program asks
   the user to enter the date, the payee's name, and the amount of the check
    (up to $10,000). It then displays a simulated check with the dollar amount
    spelled out, as in the following example:
  
                                                                            * Date: 11/24/2014
        * Pay to the Order of: Mori Yuki                              $1920.85
        * One thousand nine hundred twenty and 85 cents

    The numeric value is formatted in fixed-point notation with two decimal
    places of precision. The decimal place is always displayed, even when the
    number is zero or has no fractional part. String class objects are used in
    this program.

    Input Validation: No negative dollar amounts, or amounts over $10,000 are
    accepted. */

#include "Utility.h"
#include "EvalDate.h"

char     tryAgain();
void   getData(string &, string &, string &);
void   checkRecipient(string &);
void   checkDate(string);
void     checkAmount(string &);
string removePunct(string &);
string toHundred(const string *, const string *, int);
string toThousand(string, const string *, int);
string toTenThousand(string, const string *, int);
string numToWord(string);
string formatCheck(string, string &, string);
void   displayCheck(string, const string, const string, const string);

int main()
{
    string amount;
    string dueDate;
    string recipient;
    string centAmount;
    string wordAmount;
    char   again = ' ';

    do
    {
        amount.clear();
        dueDate.clear();
        recipient.clear();
        wordAmount.clear();
        centAmount.clear();

                         getData(amount, dueDate, recipient);
        wordAmount = formatCheck(amount, wordAmount, centAmount);
                         displayCheck(amount, dueDate, recipient, wordAmount);

        again = tryAgain();

        if (again == 'N')
        {
            cout << "\n\tThe Ishikawa Bank wishes to thank you for doing\n"
                  << "\tbusiness with us! Have a nice day!\n\n";
        }

    } while (again != 'N');

    pauseSystem();
    return 0;
}

/* **********************************************************
   Definition: getData

    This function asks for the recipient's name, the check's
    date, and the amount. Various tests are performed on each
    item, before the contents is passed back.
   ********************************************************** */

void getData(string &amount, string &dueDate, string &recipient)
{
    cout << "\n\n\t\t\tISHIKAWA BANK - CHECK WRITER\n\n"
          << "\n\tPlease enter the recipient's name: ";
    getline(cin, recipient);

        while (recipient.empty())
        {
            cout << "\n\tDear customer, the name field must not be empty!\n\n"
                << "\tPlease enter the recipient's name: ";
            getline(cin, recipient);
        }

    checkRecipient(recipient);

    cout << "\n\tPlease enter today's date, or date you would like\n"
          << "\tthe check cashed (Ex: 05/08/2017): ";
    getline(cin, dueDate);

    checkDate(dueDate);

    cout << "\n\tPlease enter the desired amount: $";
    getline(cin, amount);

    checkAmount(amount);
}

/* **********************************************************
   Definition: checkRecipient

    This function performs various checks on the string object
    containing the recipient's name.
   ********************************************************** */

void checkRecipient(string &recipient)
{
    for (size_t index = 0; index < recipient.length(); index++)
    {
        while (!isalpha(recipient.at(0)) || ispunct(recipient[index]) ||
                isdigit(recipient.at(index)) || isspace(recipient.at(0)))
        {
            cout << "\n\tDear customer, the name field must not be empty, and\n"
                  <<  "\tit must not contain any numbers or punctuation marks!\n\n"
                  << "\n\tPlease enter the recipient's name: ";
            getline(cin, recipient);
        }
    }
}

/* **********************************************************
    Definition: checkDate

    This function checks whether the date and date-format is
    correct. The function performing the checks is contained
    in the header file: "EvalDate".
    ********************************************************** */

void checkDate(string dueDate)
{
    while (evalDate(dueDate) == false)
    {
        cout << "\n\tDear customer, the entered date, and/or\n"
              << "\tdate-format seems to be invalid.\n\n"
              << "\tPlease enter today's date, or date you would like\n\n"
              << "\tthe check cashed (Ex: 05/08/2017): ";
        getline(cin, dueDate);

        evalDate(dueDate);
    }
}

/* **********************************************************
   Definition: checkAmount

    Checks for validity of the entered amount. It must not be
    lower than 0.00 or higher than 9999.99.
   ********************************************************** */

void checkAmount(string &amount)
{
    while (stod(amount) <= 0.00 || stod(amount) > 9999.99)
    {
        cout << "\n\tInput Failure! Dear customer, you entered an amount\n"
              << "\tlower than 1 or greater than 9999.99. The maximum\n"
              << "\tamount is $9999.99.\n\n"
              << "\n\tPlease enter the desired amount:\t\t$";
        getline(cin, amount);
    }
}

/* **********************************************************
   Definition: numToTword

    This function "converts" numbers between 1 and 9999.99 to
    words. This is achieved by accessing two arrays containing
    number words, by their subscript index. The result is
    stored in a string object. This string object is returned.
   ********************************************************** */

string numToWord(string amount)
{
    const string oToTwenty[] = { "", "one ", "two ", "three ", "four ", "five ",
                                          "six ", "seven ", "eight ", "nine ", "ten",
                                          "eleven ", "twelve ", "thirteen ", "fourteen ",
                                          "fifteen ", "sixteen ", "seventeen ", "eighteen ",
                                          "nineteen " };

    const string tenMult[]   = { "", "", "twenty ", "thirty ", "fourty ", "fifty ",
                                          "sixty ", "seventy ", "eighty ", "ninenty " };

    int     numStore = stoi(amount);
    string numWord;
    string words;

    if (amount.length() < 3)
    {
        words = toHundred(oToTwenty, tenMult, numStore);
    }
    else if (amount.length() == 3)
    {
        words = toThousand(amount, oToTwenty, numStore) +
                  toHundred(oToTwenty, tenMult, numStore % 100);
    }
    else if (amount.length() == 4)
    {
        if (numStore % 1000 < 100)
        {
            words = toTenThousand(amount, oToTwenty, numStore) +
                      toHundred(oToTwenty, tenMult, numStore % 100);
        }
        else
        {
            words = toTenThousand(amount, oToTwenty, numStore) +
                      toThousand(amount, oToTwenty, numStore) +
                      toHundred(oToTwenty, tenMult, numStore % 100);
        }
    }
  
    return numWord.append(words);
}

/* **********************************************************
  Definition: toHundred

    This function gets the index positions of the "tens" and
    "ones" place stored in amount. It covers amounts between
    1 and 99. The position is stored, and the result appended
    in a string object. The string object is returned.
    ********************************************************** */

string toHundred(const string *oToTwenty,
                      const string *tenMult, int numSize)
{
    string numStore;
  
    numSize < 20 ? numStore.append(oToTwenty[numSize])   :
                        numStore.append(tenMult[numSize / 10] +
                                             oToTwenty[numSize % 10]);

    return numStore;
}

/* **********************************************************
   Definition: toThousand

    This function gets the index position of the "hundreds"
    place stored in amount. This is achieved by storing the
    subscript positions contained in amount, and erasing the
    contents before it. The result is appended to a string
    object. This string object is returned.
   ********************************************************** */

string toThousand(string amount, const string *oToTwenty, int numSize)
{
    string numStore;
  
    /* This if/else statement covers all sums above and below
        below 1000. Depending on which, the corresponding subscript
        position is extracted and stored in numSize. numSize, after
        performing a calculation on it, points to the appropriate
        position in the string array containing the digit in word-
        form. */
    if (numSize > 999)
    {
        numSize = stoi(amount.erase(2, 3));
        numStore.append(oToTwenty[numSize % 1000 % 10] + "hundred ");
    }
    else
    {
        numSize = stoi(amount.erase(1, 2));
        numStore.append(oToTwenty[numSize] + "hundred ");      
    }

    return numStore;
}

/* **********************************************************
   Definition: toTenThousand

    This function gets the index position of the "thousands"
    place stored in amount. This is achieved by storing the
    first subscript position contained in amountm and erasing
    the remaining contents. The result is appended to a string
    object. This string object is returned.
   ********************************************************** */

string toTenThousand(string amount, const string *oToTwenty, int numSize)
{
    string numStore;

    numSize = stoi(amount.erase(1, 3));

    return numStore.append(oToTwenty[numSize] + "thousand ");
}

/* **********************************************************
   Definition: removePunct

    This function does three things:

        * If the user enters an amount like "256.60", the
          cent amount is stored in a string object, and the
          '.' is erased.
        * If the user enters an amount like "256" without '.',
          '00' is appended to 'centAmount'.
        * If the user enters an amount like "256.2", a '0' is
          appended.

    The cent amount stored in the string object is returned.
   ********************************************************** */

string removePunct(string &amount)
{
    string centAmount;
  
    for (size_t index = 0; index < amount.length(); index++)
    {
        if (ispunct(amount.at(index)))
        {
            centAmount.append(amount, index + 1, 3);  
            amount.erase(index, 3);          
        }  
    }

    if (centAmount.empty())
    {
        centAmount.append("00");
    }
    else if (centAmount.length() == 1)
    {
        centAmount.append("0");
    }

    return centAmount;
}

/* **********************************************************
   Definition: formatCheck

    This function formats the check output, and stores the
    result in a string object. The string object is returned.
   ********************************************************** */

string formatCheck(string amount, string &wordAmount, string centAmount)
{
    centAmount = removePunct(amount);
    wordAmount = numToWord(amount);

    wordAmount.append("dollar(s) and " + centAmount + " cents");
    wordAmount.at(0) = toupper(wordAmount.at(0));

    return wordAmount;
}

/* **********************************************************
   Definition: displayCheck

    This function outputs the formatted check to screen.
   ********************************************************** */

void displayCheck(string amount, const string dueDate,
                        const string recipient, const string wordAmount)
{
    cout << fixed << showpoint << setprecision(2);
    cout << "\n\t" << setw(68) << setfill('-') << "\n\n";
    cout << setfill(' ') << "\n" << setw(64) << right
          << "Date: " << dueDate << "\n"
          << "\tPay to the order of: " << setw(28) << left << recipient
          << setw(2) << right << "$" << stod(amount) << "\n\n\t"
          << wordAmount << "\n\n\t"
          << "Ishikawa Bank\n\t"
          << "2-1-124 Chuo-ku\n\t"
          << "Tokyo, 105-0062\n\n\t"
          << "For: Donation" << setw(24) << "Your Signature: "
          << setw(31) << setfill('_') << "\n"
          << "\n\n\t" << setw(68) << setfill('-') << "\n";
}

/* **********************************************************
   Definition: tryAgain

    This function asks the user if he or she wishes to write
    another check. The decision is returned.
   ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to write another check? (y/N): ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to write another check? (y/N): ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

Example Output:





Wednesday, May 10, 2017

Programming Challenge 10.18 - Phone Number List

Example File: phoneNumbers.txt
/* Phone Number List - This program has an array of at least 10 string objects that
   hold people's names and phone numbers. The following strings are used:
  
    "Alejandra Cruz, 555-1223"        "Joe Looney, 555-0097"      
    "Geri Palmer, 555-8787"            "Li Chen, 555-1212"              
    "Holly Gaddis, 555-8878"        "Sam Wiggins, 555-0998"
    "Bob Kain, 555-8712"                "Tim Haynes, 555-7676"      
    "Warren Gaddis, 555-4939"        "Jean James, 555-4939"          
    "Ron Palmer, 555-2783"

    The program asks the user to enter a name or partial name to search for
    in the array. Any entries in the array that match the string entered are
    displayed. For example, if the user enters "Palmer" the program displays
    the following names from the list:

        "Geri Palmer, 555-8787"            "Ron Palmer, 555-2783" */

#include "Utility.h"

/* Asks the user if he or she wishes to perform another search,
    returns the answer */
char tryAgain();

/* Reads in a list of names and phone-numbers from a file,
   stores the numbers in a string array */
int getDirectory(string *);

/* Searches for a name input by the user, stores the search result,
   returns the result */
string searchDirectory(const string *, const string);

int main()
{
    const int MAX_ENTRIES = 150;
    int        fOpenErr = 0;
    char         again = ' ';
    string   *phoneDir = new string[MAX_ENTRIES];
    string    entry;
    string    name;

    cout << "\n\tPERSONAL PHONE DIRECTORY BUTLER\n\n";

    fOpenErr = getDirectory(phoneDir);
  
    if (fOpenErr != -1)
    {
        do
        {
            cout << "\n\tPlease enter a partial or full name to search for: ";
            getline(cin, name);

            entry = searchDirectory(phoneDir, name);

            cout << "\n\n\tName" << "\t\t\tPhone Number\n\t"
                  << "------------------------------------"
                  << entry
                  << "\n\t------------------------------------\n";

            again = tryAgain();

            if (again == 'N')
            {
                cout << "\n\tHave a nice day!\n";
            }

        } while (again != 'N');
    }

    delete[] phoneDir;
    phoneDir = nullptr;

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
   ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\tDo you wish to perform another search (y/N)? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to perform another search(y/N)? ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

/* **********************************************************
   Definition: getDirectory

    This function reads in a file called 'phoneNumbers.txt'.
    The contents of this file is stored in a string array.
    If the file cannot be openend, the user is informed by a
    message, and the function will exit with code -1.
   ********************************************************** */

int getDirectory(string *nameList)
{
    string   temp;
    ifstream phoneDir;

    phoneDir.open("phoneNumbers.txt");

    if (phoneDir && !phoneDir.eof())
    {
        for (size_t idx = 0; !phoneDir.eof(); idx++)
        {
            getline(phoneDir, temp);

            nameList[idx].append("\n\t" + temp);
        }
    }
    else
    {
        cout << "\n\tFile open error: The file 'phoneNumbers.txt' could not be\n"
              << "\topened or processed. Make sure that the filename is\n"
              << "\tcorrect and the file is not damaged or has been moved\n"
              << "\tfrom the program folder.\n\n"
              << "\tPress enter to exit this program ...";
        return -1;
    }

    phoneDir.close();

    return 0;
}

/* **********************************************************
   Definition: searchDirectory

    This function searches for a name input by the user. If
    a match is found, the result is stored in a string object.
    If there is no match, a message is stored in the string
    object, informing the user accordingly. The search result
    is returned.
   ********************************************************** */

string searchDirectory(const string *phoneDir, const string name)
{
    string result;

    for (size_t idx = 0; idx < phoneDir[idx].length(); idx++)
    {
        if (phoneDir[idx].find(name) != string::npos)
        {
            result.append(phoneDir[idx]);
        }
    }

    if (result.empty())
    {
        result.append("\n\tNo match was found in your directory!");
    }

    return result;
}

Example Output:




Sunday, May 7, 2017

Programming Challenge 10.17 - Morse Code Converter

Example Files: mAlpha.txt
                          mMorse.txt

/* Morse Code Converter - Morse code is a code where each letter of the
    English alphabet, each digit, and various punctuation characters are
    represented by a series of dots and dashes. This program asks the user
    to enter a string, and then converts that string to Morse code. */

#include "Utility.h"

/* Asks the user if he or she wants to repeat the process,
   returns the decision */
char tryAgain();

/* Reads in a file containing letters a-z, the numbers 0-9, and a set
    of punctuation characters,
    stores the contents in a char vector */
int getAlpha(vector<char> &);

/* Reads in a file containing the Morse code equivalents of letters
    a-z, the numbers 0-9, and a set of punctuation characters,
    stores the contents in a string vector */
int getMorse(vector<string> &);

/* Converts a sentence from English to Morse Code,
    returns the sentence */
string toMorse(const string, const vector<char>, const vector<string>);

int main()
{
    vector<char>   alpha;
    vector<string> morse;

    int     fOpenAlpha = 0,
             fOpenMorse = 0;
    char   again = ' ';
    string english,
             morseCode;

    cout << "\n\tMORSE CODE TRANSLATOR\n";

    fOpenAlpha = getAlpha(alpha);
    fOpenMorse = getMorse(morse);

    if (fOpenAlpha != -1 && fOpenMorse != -1)
    {
        do
        {
            cout << "\n\tEnter a sentence in English, and I will translate "
                      "it to Morse code for you:\n\t";
            getline(cin, english);

            cout << "\n\tHere is your sentence in Morse code:\n\n"
                  << (morseCode = toMorse(english, alpha, morse)) << "\n";  

            again = tryAgain();

            if (again == 'N')
            {
                cout << "\n\tHave a nice day!\n\n";
            }

        } while (again != 'N');
    }

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
   ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to try this again? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to try this again? ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

/* **********************************************************
   Definition: getAlpha

    This function reads in a file called 'mAlpha.txt', which
    contains the letters a-z, numbers 1 through 9, and a set
    of punctuation characters. The contents of this file is
    stored in a string vector. If the file cannot be openend,
    the user is informed by a message, and the function will
    exit with code -1.
   ********************************************************** */

int getAlpha(vector<char> &alpha)
{
    ifstream alphabet;
    char        mAlpha;

    alphabet.open("mAlpha.txt");

    if (alphabet && !alphabet.eof())
    {
        while (alphabet >> mAlpha)
        {
            alpha.push_back(mAlpha);
        }
    }
    else
    {
        cout << "\n\tFile open error: The file 'mAlpha.txt' could not be\n"
              << "\topened or processed. Make sure that the filename is\n"
              << "\tcorrect and the file is not damaged or has been moved\n"
              << "\tfrom the program folder.\n\n"
              << "\tPress enter to exit this program ...";

        return -1;
    }

    alphabet.close();

    return 0;
}

/* **********************************************************
   Definition: getMorse

    This function reads in a file called 'mMorse.txt', which
    contains the Morse code equivalents of the letters a-z,
    numbers 1 through 9, and a set of punctuation characters.
    The contents of this file is stored in a string vector.
    If the file cannot be openend, the user is informed by a
    message, and the function will exit with code -1.
   ********************************************************** */

int getMorse(vector<string> &morse)
{
    ifstream morseAlpha;
    string   mMorse;

    morseAlpha.open("mMorse.txt");

    if (morseAlpha && !morseAlpha.eof())
    {
        while (getline(morseAlpha, mMorse))
        {
            morse.push_back(mMorse);
        }
    }
    else
    {
        cout << "\n\tFile open error: The file 'mMorse.txt' could not be\n"
              << "\topened or processed. Make sure that the filename is\n"
              << "\tcorrect and the file is not damaged or has been moved\n"
              << "\tfrom the program folder.\n\n"
              << "\tPress enter to exit this program ...";

        return -1;
    }

    morseAlpha.close();

    return 0;
}

/* **********************************************************
   Definition: toMorse

    This function accepts a string object and two vectors as
    arguments. It translates a sentence into Morse code. The
    string object containing the translation is returned.
   ********************************************************** */

string toMorse(const string input, const vector<char> alpha,
                    const vector<string> morse)
{
    unsigned int startScan = 0,
                     index = 0;
    string         morseCode;

    for (startScan = index; startScan < input.length(); startScan++)
    {
        for (index = 0; index < morse.size(); index++)
        {
            if (tolower(input.at(startScan)) == alpha.at(index))
            {
                morseCode.append(morse.at(index) + " ");
            }
        }

        if (isspace(input.at(startScan)))
        {
            morseCode.insert(morseCode.length(), " ");
        }
    }

    return morseCode;
}

Example Output:





Thursday, May 4, 2017

Programming Challenge 10.16 - Pig Latin

/* Pig Latin - This program reads a sentence as input and converts each
    word to "Pig Latin." To convert a word to Pig Latin, the first letter
    is removed and placed at the end of the word, then the string "ay" is
    appended to the word. For example:
  
    * English:        I SLEPT MOST OF THE NIGHT
    * Pig Latin:    IAY LEPTSAY OSTMAY FOAY HETAY IGHTNAY */

#include "Utility.h"

/* Asks the user if he or she wants to repeat the process,
    returns the decision */
char tryAgain();

/* Converts each word to pig latin,
   returns the words */
string pigLatin(string);

/* Converts each word to uppercase */
void wordCapitalizer(string &);

/* Removes punctuation from a sentence */
void removePunct(string &);

/* Clears the input of the three string object */
void clearInput(string &, string &, string &);

int main()
{
    char   again = ' ';
    string word;
    string pigSentence;
    string englishSentence;

    cout << "\tPIG LATIN TRANSLATOR\n\n"
          << "\tEnter a sentence, and I will translate it for you "
          << "from English to Pig Latin:\n\t";

    do
    {
        while (cin >> word)
        {      
            englishSentence.append(word + " ");

            removePunct(word);
            wordCapitalizer(word);

            pigSentence.append(pigLatin(word));

            if (cin.get() == '\n')
            {
                cout << "\n\tThis was your original sentence:\n\t"
                      << englishSentence << "\n";

                cout << "\n\tThis is your sentence in Pig Latin:\n\t"
                      << pigSentence;

                break;
            }
        }

        again = tryAgain();

        if (again == 'Y')
        {
            cout << "\n\tPlease enter another sentence:\n\t";

            clearInput(word, pigSentence, englishSentence);
        }      
        else
        {
            cout << "\tHave a nice day!\n\n";
        }
    } while (again == 'Y');

    pauseSystem();
    return 0;
}

/* **********************************************************
   Definition: pigLatin

   This function stores the first letter of each word in a
    variable, then the first letter is erased, and in a final
    step the letter plus "AY " is appended to the word.
   ********************************************************** */

string pigLatin(string word)
{
    string tmp = word.substr(0, 1);
    string pLatin = "AY ";

    word.erase(word.begin());
    word.append(tmp + pLatin);

    return word;
}

/* **********************************************************
   Definition: removePunct

   This function erases all punctuation from the string.
   ********************************************************** */

void removePunct(string &sentence)
{
    for (unsigned int i = 0; i < sentence.length(); i++)
    {
        if (ispunct(sentence.at(i)))
        {
            sentence.erase(i++, 1);
        }
    }
}

/* **********************************************************
   Definition: wordCapitalizer

   This function converts a word to uppercase.
   ********************************************************** */

void wordCapitalizer(string &word)
{
    for (unsigned int index = 0; index < word.length(); index++)
    {
        if (isalpha(word.at(index)))
        {
            word.at(index) = toupper(word.at(index));
        }
    }
}

/* **********************************************************
   Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
   ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to try this again? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to try this again? ";
        cin >> again;
    }

    return toupper(again);
}

/* **********************************************************
   Definition: clearInput

   This function clears the contents in the string objects.
   ********************************************************** */

void clearInput(string &word, string &pigSentence,
                     string &englishSentence)
{
    word.clear();
    pigSentence.clear();
    englishSentence.clear();
}

Example Output:



Monday, May 1, 2017

Programming Challenge 10.15 - Character Analysis

Example File: text.txt

/* Character Analysis - This program reads the contents of a file called
    text.txt and determines the following:
   
        * The number of uppercase letters in the file
        * The number of lowercase letters in the file
        * The number of digits in the file */

#include "Utility.h"

/* Reads in the contents of the file 'text.txt',
    stores the contents in a string object */
int getText(string &);

/* Displays the text stored in the string object */
void displayText(const string);

/* Examines the string object, counts every occurence of
   uppercase and lowercase characters as well as digits,
    outputs the result */
void analyzeText(const string);

int main()
{
    int    fRead = 0;
    string fullText;

    fRead = getText(fullText);

    if (fRead == 0)
    {
        displayText(fullText);
        analyzeText(fullText);
    }

   pauseSystem();
   return 0;
}

/* **********************************************************
   Definition: getText

    This function opens and reads in the contents of a file
    called 'text.txt.' The content is read in and stored into
    a string object.
   ********************************************************** */

int getText(string &fullText)
{
    ifstream textFile;
    string   tmp;

    textFile.open("txt.txt");

    if (textFile)
    {
        while (getline(textFile, tmp) && !textFile == '\0')
        {
            fullText.insert(fullText.length(), "\t" + tmp + "\n");
        }   
    }
    else
    {
         cout << "\n\tFile open error: The file 'text.txt' could not be\n"
                << "\topened or processed successfully. Make sure that the\n"
                << "\tfilename is correct and the file is not damaged or has\n"
               << "\tbeen moved from the program folder.\n\n"
               << "\tPress enter to exit this program ...";

         return -1;
    }

    textFile.close();

    return 0;
}

/* **********************************************************
   Definition: displayText

    This function accepts a string object as argument. It
    ouputs the contents to screen.
   ********************************************************** */

void displayText(const string fullText)
{
    for (char i : fullText)
    {
        cout << i;
    }
}

/* **********************************************************
   Definition: analyzeText

    This function accepts a string object as argument. It
    finds and counts all upper- and lowercase characters, as
    well as digits. The result is output to screen.
   ********************************************************** */

void analyzeText(const string fullText)
{
    int lower = 0,
         upper = 0,
         digit = 0;

    for (char i : fullText)
    {
        islower(i) ? lower++ : i;
        isupper(i) ? upper++ : i;
        isdigit(i) ? digit++ : i;
    }

    cout << "\n\tThis text contains " << setw(4) << digit
          << " digits.";
    cout << "\n\tThis text contains " << setw(4) << upper
          << " uppercase characters.\n";
    cout << "\tThis text contains " << lower
          << " lowercase characters.\n";
}

Example Output:





Saturday, April 29, 2017

Programming Challenge 10.14 - Word Separator

/* Word Separator - This program accepts as input a sentence in which
   all words are run together, but the first character of each word is
    uppercase. The sentence is converted to a string in which the words
    are separated by spaces and only the first word starts with an
    uppercase letter. For example the string "StopAndSmellTheRose."
    Would be converted to "Stop and smell the roses." */

#include "Utility.h"

/* Introduces the functionality of this program to the user */
void intro();

/* Asks the user if he or she wants to repeat the process,
    returns the decision */
char tryAgain();

/* Searches for uppercase characters in a sentence,
   inserts spaces to separate the words at that position */
void separator(string &);

/* Replaces uppercase characters in a sentence with
   their lowercase equivalents */
void senDecapitalizer(string &);

/* Replaces lowercase characters at the beginning of sentences
   with their uppercase equivalent */
void senCapitalizer(string &);

int main()
{
    int     firstRun = 1;
    char   again = ' ';
    string sentence = " ";

    do
    {
        if (firstRun)
        {
            intro();
            firstRun = 0;
        }
        else
        {
            cout << "\n\n\tWORD SEPARATOR\n\n";
        }

        cout << "\tEnter a sentence:\n\t";

        getline(cin, sentence);

        separator(sentence);
        senDecapitalizer(sentence);
        senCapitalizer(sentence);

        cout << "\n\tThis is your sentence, correctly formatted:\n\t";
        cout << sentence;

        again = tryAgain();

        if (again == 'N')
        {
            cout << "\n\tHave a nice day!\n\n";
        }

    } while (again == 'Y');
    pauseSystem();
    return 0;
}

/* **********************************************************
   Definition: intro

    This function introduces the basic functionality of this
    program to the user.
   ********************************************************** */

void intro()
{
    cout << "\n\tWORD SEPARATOR\n\n"
          << "\tEnter a sentence without spaces, each word starting with\n"
          << "\tan uppercase letter, and I will separate the words.\n"
          << "\tA sentence such as:\n\n"
          << "\t'ThisSentenceDoesNotContainAnySpaces'\n\n"
          << "\twill be formatted, to look like this:\n\n"
          << "\t'This Sentence Does Not Contain Any Spaces.'\n\n"
          << "\tYou can repeat this process as often as you like to,\n"
          << "\tas long as you enter 'y' when asked.\n\n";
}

/* **********************************************************
   Definition: tryAgain

    This function asks the user if he or she wishes to try
    again. This decision is returned.
   ********************************************************** */

char tryAgain()
{
    char again = ' ';

    cout << "\n\n\tDo you wish to try this again? ";
    cin >> again;
    cin.ignore();

    /* Input validation */
    while (toupper(again) != 'Y' && toupper(again) != 'N')
    {
        cout << "\n\tDo you wish to try this again? ";
        cin >> again;
        cin.ignore();
    }

    return toupper(again);
}

/* **********************************************************
   Definition: separator

    This function searches for the occurence of uppercase
    characters in a sentence. If found, a space is inserted to
    separate the characters.
   ********************************************************** */

void separator(string &sentence)
{
    for (unsigned int index = 1; index < sentence.length(); index++)
    {
        if (isupper(sentence[index]))
        {
            sentence.insert((index++), " ");
        }
    }
}

/* **********************************************************
   Definition: senDecapitalizer

   This function replaces all uppercase characters found in
    a sentence by their lowercase equivalent.
   ********************************************************** */

void senDecapitalizer(string &sentence)
{
    for (unsigned int index = 1; index < sentence.length(); index++)
    {
        if (!isupper(sentence[index]))
        {
            sentence[index+1] = tolower(sentence[index+1]);
        }
    }
}

/* **********************************************************
   Definition: senCapitalizer

   This function converts letters at the beginning of each
    sentence to their uppercase equivalents.
   ********************************************************** */

void senCapitalizer(string &sentence)
{
    bool            isDelim = false;

    for (unsigned int index = 0; index < sentence.length(); index++)
    {
        if (sentence.at(index) == '.' || sentence.at(index) == '!' ||
            sentence.at(index) == '?')
        {
            isDelim = false;
        }

        if (isalpha(sentence.at(index)) && isDelim == false)
        {
            isDelim = true;
            sentence.at(index) = toupper(sentence.at(index));
        }
    }
}

Example Output: