Thursday, March 22, 2018

Programming Challenge 17.3 - Capital Quiz

Example Files: CapitalQuiz.7z

Notice: The original Ascii-Art was taken from http://www.chris.com/ascii/joan/www.geocities.com/SoHo/7373/flag.html © by Joan G. Stark. http://www.ascii-art.com/

FileLoader.h


#ifndef FILE_LOADER_H_
#define FILE_LOADER_H_

#include <fstream>
#include <map>
#include <string>

class FileLoader
{
    private:
        std::string      fileName;
        std::ifstream flagFile;
        std::ifstream quizFile;

        std::map<std::string, std::string> quiz;
      
    public:
        FileLoader();

        bool loadHeader();
        bool loadQuiz();

        std::map<std::string, std::string> getQuiz()
        { return quiz; }
};

#endif

FileLoader.cpp


#include "FileLoader.h"

#include <iostream>
#include <string>

/* **********************************************************
            FileLoader::FileLoader() - Constructor
   ********************************************************** */

FileLoader::FileLoader()
{
    loadHeader();
    loadQuiz();
}

/* **********************************************************
            FileLoader::loadHeader()
    If the file is opened successfully, a header graphic is
    loaded and displayed. Otherwise the function exits with
    an error message.
   ********************************************************** */

bool FileLoader::loadHeader()
{
    bool status = true;

    flagFile.open("Flag.txt");

    if (flagFile.fail())
    {
        std::cout << "\nFile Open Error: Unable to load flag file.\n";
        std::cout << "Please exit this program and try again ..." << std::endl;
        status = false;
    }
    else
    {
        std::string output{};

        while (getline(flagFile, output))
        {
            std::cout << output << "\n";
        }
    }

    flagFile.close();
    return status;
}

/* **********************************************************
            FileLoader::loadQuiz()
    If loaded successfully, a key value pair is read in from
    the file and inserted into the map. Otherwise an error
    message is displayed and the function exits.
   ********************************************************** */

bool FileLoader::loadQuiz()
{
    bool status = true;
    quizFile.open("Capitals.txt");

    if (quizFile.fail())
    {
        std::cout << "\nFile Open Error: Unable to load " << fileName << " file.\n";
        std::cout << "Please exit this program and try again ..." << std::endl;
        status = false;
    }
    else
    {
        std::string firstVal{};
        std::string secondVal{};

        while (getline(quizFile, firstVal, ':') && getline(quizFile, secondVal))
        {
            std::map<std::string, std::string>::iterator it = quiz.begin();
            quiz.insert(it, std::pair<std::string, std::string>(firstVal, secondVal));
        }
    }

    quizFile.close();
    return status;
}

Capital.h


#ifndef CAPITAL_QUIZ_H_
#define CAPITAL_QUIZ_H_

#include "FileLoader.h"

#include <map>
#include <string>

class Capital
{
    private:       
        FileLoader  loader;
        static int    points;

        std::map<std::string, std::string> capitals;
        std::map<std::string, std::string>::iterator it;

    public:
        Capital()
        { capitals = loader.getQuiz(); }

        void presentQuestion();
        void getAnswer();
        void evaluateAnswer(std::string);
        void removeQuestion();

        int getMapSize() const
        { return capitals.size(); }

        int getPoints() const
        { return points; }

        bool operator < (const Capital &) const;
};

#endif

Capital.cpp


#include "Capital.h"

#include <algorithm>
#include <iostream>

int Capital::points = 0;

/* **********************************************************
            Capital::presentQuestion()
    This function selects a random question and outputs it to
    screen.
   ********************************************************** */

void Capital::presentQuestion()
{
    std::advance(it = capitals.begin(), rand() % capitals.size());
    std::cout << "\nWhat is the capital of " << it->first << "?\n";
}

/* **********************************************************
            Capital::getAnswer()
    The user is asked to enter his or her answer. The answer
    is evaluated by call to the appropriate function.
   ********************************************************** */

void Capital::getAnswer()
{
    std::string answer{};

    std::cout << "Your answer: ";
    getline(std::cin, answer);

    evaluateAnswer(answer);
}

/* **********************************************************
            Capital::evaluateAnswer() : std::string
    This function evaluates the answer passed to it by value.
    If it is correct, 5 points are assigned to the player's
    score, and the question is removed from the map. Otherwise
    a point is deducted, iff the score is greater 0, and the
    question remains in the queue.
   ********************************************************** */

void Capital::evaluateAnswer(std::string answer)
{
    if (it->second == answer)
    {
        std::cout << "\nCorrect (^-^)\n";
        points += 5;
        removeQuestion();
    }
    else
    {
        std::cout << "\nWrong (;-;)\n";
        std::cout << "The capital of " << it->first << " is " << it->second << "\n\n";

        points > 0 ? points -= 1 : points = 0;
    }
}

/* **********************************************************
            Capital::removeQuestion()
    Erases a key value pair from the map.
   ********************************************************** */

void Capital::removeQuestion()
{
    if (capitals.size() > 0)
    {
        capitals.erase(it);
    }
}

/* **********************************************************
            Overloaded < operator   
   ********************************************************** */

bool Capital::operator < (const Capital &right) const
{
    bool status = false;

    if (capitals < right.capitals)
    {
        status = true;
    }
    return status;
}

CapitalQuiz.cpp


#include "Capital.h"

#include <iostream>
#include <ctime>

int main()
{
    Capital capitalQuiz;

    char choice{};

    srand((unsigned int)time(NULL));

    do
    {
        capitalQuiz.presentQuestion();
        capitalQuiz.getAnswer();

        if (capitalQuiz.getMapSize() > 0)
        {
            std::cout << "Do you wish to continue? (y/N): ";
            std::cin >> choice;
            std::cin.ignore();

            while (toupper(choice) != 'Y' && toupper(choice) != 'N')
            {
                std::cin.sync();
                std::cout << "Do you wish to continue? (y/N): ";
                std::cin >> choice;
                std::cin.ignore();
            }

            if (toupper(choice) == 'N')
            {
                std::cout << "\nWell Done! You earned " << capitalQuiz.getPoints() << " points!\n";
                std::cout << "Thank you for playing this quiz!" << std::endl;           
            }
        }
        else
        {
            std::cout << "\nWell Done! You answered all questions and earned: "
                         << capitalQuiz.getPoints() << " points!\n";
            std::cout << "Thank you for playing this quiz!" << std::endl;
        }
    } while (toupper(choice) != 'N' && capitalQuiz.getMapSize() > 0);

    std::cin.ignore();
    return 0;
}

Example Output:




No comments:

Post a Comment