Tuesday, November 28, 2017

Yet Another Chapter Summary

This was one long road to reach the end of this first chapter about classes in C++! It has taken the better part of three months to get there, and it wasn't an easy journey. 

The main chapter was rather easy to follow, and for the first time I managed to answer all Quiz-questions correctly and having been able to solve the Exercise section without major trouble, I felt well prepared for the Programming Challenges section.

When I began with the first Challenge, it is about writing a Date class, the trouble began. While conceptually being able to work it out, and having solved a similar problem with structures, the great difficulty for me was to translate it all to a class with the setters and getters and constructor and what else a class consists of.

The main difficulty was to work out a way to write such a class, and what the getters and setters actually do, I could not readily understand this. It took two days until I managed to translate something into code that would work, and another six or seven to solve it. Getting past this first challenge, the second, the third, and numerous others felt equally as difficult as the first one.

It wasn't until challenge 13.14 that writing a classes header and implementation files became less difficult. Slowly I began to understand how everything has to go together to form one unity. This doesn't mean that it was done correctly, just that things were working, the output was correct, there were no crashes or other problems of that nature. I also started noticing how much more convenient it is to work with classes. Being able to write code for a sub-set of a bigger problem, testing it in isolation to see if it works, then keep doing the same for another sub-set of the problem until the big problem is solved is a huge advantage. If one part does not fit in the big picture, instead of having to start all over, there is only this function that needs to be changed. Eventually I became a bit more comfortobale working with one or two class files up to that point in time. 

As you will notice, past a certain point I started working with more than one class and implementation file. The first time was for the Cash Register challenge, it contains three header and two implementation files. Now, as you might expect, this working with many class files brought about a new set of problems. How to get those seperate entities to work together?

Having particular ideas what each should do was one thing, they don't behave any differently to what has come before. If everything works in isolation, putting it all together in the driver should be no problem. In fact, it isn't, if you know how, which I didn't at that point. Below is my thought process:

"Well, wouldn't it be great if a member variable or a function inside one class could be used in another?", "Of course! But how?", "Why don't you put the #include "classOne.h" into the "classTwo.h" file, and see what it does?", "Great! Let's do it!"

But, but, but, where is there a problem with that? The problem starts when this person learns that this does indeed work. 

"So, if this works, wouldn't it also be great to find a possibility to work with two or more classes in such way, that they update each other?", "Yes, yes, yes! This is what is needed for the current challenge!"

This idea and thought process came about while working on the "A Game of 21" challenge. The idea was to have the game, menu and player class a way of sharing a players' information. The game class had a player object and dice object in it, and I saw the need to have the game and menu class both get that name. When I tried linking menu and game class in a way such that the one contains an include of the other, was the point that I learned the hard way about 'Circular dependencies.'

Consider this example:

#include "cTwo"

class cOne
{
   // ........
}

#include "cOne"

class cTwo
{
   // .........
}

This is the way it was, and it became clear that it wouldn't work. Let me explain in a little more detail why I saw the need of a construct like this. One file had a player object, and via call this player objects' name variable would be set. Yet, when trying to retrieve the players' name from outside the class, or within the menu class, the name returned empty. You can imagine the reason why this is so. Because the player object was instantiated game class local, there is no way of another class to even know about the existence of it, much less what it might contain in terms of data. 

Consider this:

The game class contains a player object.
The game class makes a call to a player class function that sets the players' name.
The game class now has a name for the player, and can make another call to a function that returns this players' name.

The menu class, for instance, if it contains an include of the player class, if it accesses the getPlayerName() function, what does it get? An empty string. There doesn't exist any data for the menu class retrievable from the player class. The idea of working around it was to set the variable to holding the name to static, which, in itself, was causing another problem entirely. In the end I gave up on the idea and started looking for a better way to write the classes.

Such and other problems were keeping me busy for a very long time. In the end I do feel that a great number of challenges could have been solved in a better way than I was able to do it. Yet, I have also learned many new things, and I do feel alot more confident working with classes. I just hope that the next chapter and its challenges will be a lot easier now that I have a basic grasp of things.

With this, it is time to move on to another chapter, and soon enough, time to solve more programming challenges. To my visitors regular and new, thank you for coming by! And to my fellow students, well, I hope you have had an easier start with classes than me, and that you are also able to move on to the next chapter soon, if you are still working on the challenges. Keep it up, never give up! 頑張ってね!

Programming Challenge 13.20 - Patient Fees

Example Files: PatientFees.7z

PatientAccount.h


#ifndef PATIENT_ACCOUNT_H_
#define PATIENT_ACCOUNT_H_

#include <string>
using std::string;

#include <vector>
using std::vector;

class Patient
{
    private:
        const double DAILY_RATE = 45.99;

        const vector<int> patientID{ 153565, 453245, 243343 };
        const vector<string> patientName{ "Marie J. Holden", "Larry J. Ingols", "Esther P. Reese" };

        int    recordID;                        // Stores a patients' record ID
        string performedSurgery;            // Holds the name of a performed surgery
        string administeredMedication;    // Holds the name of the administered medication
        int    numDaysStay;                    // Holds the number of days of stay of a patient
        double surgeryCharge;                // Holds the surgery charge
        double medicationCharge;            // Holds the medication charge
        double stayCharge;                    // Holds the charge for a given number of days
        double totalCharge;                    // Holds the total charges
       
    public:
        Patient();

        void outputRecords();
        void setRecordID();
        void setNumDaysStay();
        void setSurgeryCharge(double);
        void setPerformedSurgery(string);
        void setAdministeredMedication(string);
        void setMedicationCharge(double);
        void calcCharges();

        int getRecordID() const
        { return recordID; }

        double getNumDaysStay() const
        { return numDaysStay; }

        double getStayCharge() const
        { return stayCharge; }

        string getAdministeredSurgery() const
        { return performedSurgery; }

        double getSurgeryCharge() const
        { return surgeryCharge; }

        string getAdministeredMedication() const
        { return administeredMedication; }

        double getMedicationCharge() const
        { return medicationCharge; }

        double getTotalCharge() const
        { return totalCharge; }

        double getDailyRate() const
        { return DAILY_RATE; }

        int getPatientID(int pID)
        { return patientID[pID]; }

        string getPatientName(int pID)
        { return patientName[pID]; }
};

#endif

PatientAccount.cpp


#include "PatientAccount.h"

#include<iomanip>
using std::left;
using std::right;
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Patient::Patient() - Default Constructor
   ********************************************************** */

Patient::Patient()
{
    recordID = 0;
    performedSurgery = "";
    administeredMedication = "";
    numDaysStay = 0;
    surgeryCharge = 0.0;
   medicationCharge = 0.0;       
    stayCharge = 0.0;
    totalCharge = 0.0;
}

/* **********************************************************
            Patient::outputRecords()
    This function outputs a list of patient ID numbers and
    names.
   ********************************************************** */

void Patient::outputRecords()
{
    int cnt = 1;

    auto itID = patientID.begin();
    auto itName = patientName.begin();

    for (; itID != patientID.end() && itName != patientName.end(); ++itID, ++itName)
    {
        cout << (cnt++) << ": " << setw(24) << left << (*itID)
                                        << right << (*itName) << "\n";
    }
}

/* **********************************************************
            Patient::setRecordID()
    This function asks the user to enter a number to retrieve
    that particular patients' record.
   ********************************************************** */

void Patient::setRecordID()
{
    int tempRecID = 0;

    cout << "\n\nPATIENT RECORD DEPARTMENT\n\n";
    cout << "   Patient ID" << setw(27) << "Patient Name\n";
    cout << "------------------------------------------\n";

    outputRecords();

    cout << "\nEnter patients record number (1-3): ";
    cin >> tempRecID;

    while (tempRecID <= 0 || tempRecID > patientID.size())
    {
        cout << "Enter patients record number (1-3): ";
        cin >> tempRecID;
    }

    recordID = tempRecID - 1;
}

/* **********************************************************
            Patient::setNumDaysStay()
    This function asks the user to enter the numbers of days
    a patient stayed in the hospital.
    ********************************************************** */

void Patient::setNumDaysStay()
{
    cout << "\nEnter number of days of stay (min: 1 day): ";
    cin >> numDaysStay;

    while (numDaysStay <= 0)
    {
        cout << "Enter number of days of stay (min: 1day): ";
        cin >> numDaysStay;
    }
    cout << "\n\n";
}

/* **********************************************************
            Patient::setPerformedSurgery() : string
    This function accepts a string object, holding the name of
    the surgery having been performed. It gets assigned to the
    performedSurgery member variable.
   ********************************************************** */

void Patient::setPerformedSurgery(string sType)
{
    performedSurgery = sType;
}

/* **********************************************************
            Patient::setAdministeredMedication() : string
    This function accepts a string object, holding the name of
    the medication administered to a patient. It gets assigned
    to the administeredMedication member variable.
   ********************************************************** */

void Patient::setAdministeredMedication(string mType)
{
    administeredMedication = mType;
}

/* **********************************************************
            Patient::setSurgeryCharge() : double
    This function accepts a double, holding the cost of the
    surgery performed on the patient. It gets assigned
    to the surgeryCharge member variable.
   ********************************************************** */

void Patient::setSurgeryCharge(double sChrg)
{
    surgeryCharge = sChrg;
}

/* **********************************************************
            Patient::setSurgeryCharge() : double
    This function accepts a double, holding the cost of the
    medication administered to the patient. It gets assigned
    to the medicationCharge member variable.
   ********************************************************** */

void Patient::setMedicationCharge(double medChrg)
{
    medicationCharge = medChrg;
}

/* **********************************************************
            Patient::calcCharges()
    This function calculates the charges the patient has to
    pay.
    ********************************************************** */

void Patient::calcCharges()
{
    stayCharge = (numDaysStay * DAILY_RATE);
    totalCharge = (surgeryCharge + medicationCharge + stayCharge);
}

Surgery.h


#ifndef SURGERY_H_
#define SURGERY_H_

#include "PatientAccount.h"

#include <string>
using std::string;

#include <vector>
using std::vector;

class Surgery
{
    private:
    const    vector<string> surgeryType{ "Pneumonectomy", "Otoplasty", "Neurosurgery", "Gastropexy", "Cardiotomy" };
   const vector<double> charge{ 1460.75, 1250.35, 2750.95, 1760.45, 4730.25 };

        Patient &patient;

    public:
        // Constructor accepting a reference to a Patient class object
        Surgery(Patient &p) : patient(p)       
        {
        }

        void outputProcedures();
        void setSurgeryType();
        void updatePatientRecord(int);
};

#endif

Surgery.cpp


#include "Surgery.h"

#include <iomanip>
using std::left;
using std::right;
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Surgery::outputProcedures()
    This function outputs the surgical procedure names and
    charges.
   ********************************************************** */

void Surgery::outputProcedures()
{
    int cnt = 1;

    auto itSurgery = surgeryType.begin();
    auto itCharge = charge.begin();

    for (; itSurgery != surgeryType.end() && itCharge != charge.end(); ++itSurgery, ++itCharge)
    {
        cout << (cnt++) << ": " << setw(30) << left << (*itSurgery)
                                        << right << "$ " << (*itCharge) << "\n";
    }
}

/* **********************************************************
            Surgery::setSurgeryType()
    This function asks the user to enter a number for the
    type of surgery having been performed.
   ********************************************************** */

void Surgery::setSurgeryType()
{
    int sProcNum = 0;

    cout << "\n\nBILLING SYSTEM - SURGERY DEPARTMENT\n\n";
    cout << setw(3) << "   Type of Surgery" << setw(25) << "Cost\n";
    cout << "------------------------------------------\n";

    outputProcedures();

    cout << "\nEnter number: ";
    cin >> sProcNum;

    while (sProcNum <= 0 || sProcNum > surgeryType.size())
    {
        cout << "Enter number: ";
        cin >> sProcNum;
    }

    updatePatientRecord(sProcNum - 1);
}

/* **********************************************************
            Surgery::updatePatientRecord()
    This function updates two patient class member variables.
    It assigns to them the name of a surgery and a charge.
   ********************************************************** */

void Surgery::updatePatientRecord(int typeNum)
{
    patient.setPerformedSurgery(surgeryType[typeNum]);
    patient.setSurgeryCharge(charge[typeNum]);
}

Pharmacy.h


#ifndef PHARMACY_H_
#define PHARMACY_H_

#include "PatientAccount.h"

#include <string>
using std::string;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;

class Pharmacy
{
    private:
    const vector<string> medicationName{ "Albendazole 200 mg", "Pyrazinamide 400 mg",
                                                   "Ketamine 20 ml", "Bisacodyl 5 mg", "Lamotrigine 100 mg" };
    const vector<double> charge{ 12.35, 15.99, 12.13, 16.53, 25.99 };

     Patient &patient;

    public:
        // Constructor accepting and initializing a reference to a Patient object
        Pharmacy(Patient &p) : patient(p)
        {
        }

        void outputMedication();
        void setMedicationType();
        void updatePatientRecord(int);
};

#endif

Pharmacy.cpp


#include "Pharmacy.h"

#include <iomanip>
using std::left;
using std::right;
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Pharmacy::outputMedication()
    This function outputs the medication names and charges.
   ********************************************************** */

void Pharmacy::outputMedication()
{
    int cnt = 1;

    auto itMedication = medicationName.begin();
    auto itCharge = charge.begin();

    for (; itMedication != medicationName.end() && itCharge != charge.end(); ++itMedication, ++itCharge)
    {
        cout << (cnt++) << ": " << setw(31) << left << (*itMedication)
                                        << right << "$  " << left << (*itCharge) << "\n";
    }
}

/* **********************************************************
            Pharmacy::outputMedication()
    This function asks the user to enter a number to retrieve
    the type of medication having been administered.
   ********************************************************** */

void Pharmacy::setMedicationType()
{
    int productNum = 0;

    cout << "\n\nBILLING SYSTEM - PHARMACOLOGY DEPARTMENT\n\n";
    cout << setw(3) << "   Name of Medicine" << setw(24) << "Cost\n";
    cout << "------------------------------------------\n";

    outputMedication();

    cout << "\nEnter product ID: ";
    cin >> productNum;

    while (productNum <= 0 || productNum > medicationName.size())
    {
        cout << "Enter product ID: ";
        cin >> productNum;
    }

    updatePatientRecord(productNum-1);
}

/* **********************************************************
            Pharmacy::updatePatientRecord()
    This function updates two patient class member variables.
    It assigns to them the name of a medication and a charge.
   ********************************************************** */

void Pharmacy::updatePatientRecord(int typeNum)
{
    patient.setAdministeredMedication(medicationName[typeNum]);
    patient.setMedicationCharge(charge[typeNum]);
}

PatientFees.cpp


#include "PatientAccount.h"
#include "Surgery.h"
#include "Pharmacy.h"

#include <iomanip>
using std::right;
using std::left;
using std::setw;
using std::fixed;
using std::setprecision;

#include <iostream>
using std::cin;
using std::cout;

const enum Options { CHECKOUT = 'C', PRINT_FORM = 'P', QUIT = 'Q' };

void outputCheckoutReport(Patient &);

int main()
{
    const int NUM_RECORDS = 3;

    char choice = ' ';

    Patient patient;
    Pharmacy medication(patient);
    Surgery surgery(patient);

    do
    {
        cout << "\nMt. RAKUTEI HOSPITAL - FRONT DESK\n\n";
        cout << "[C] PATIENT CHECKOUT\n"
              << "[P] PRINT CHECKOUT FORM\n"
             << "[Q] QUIT\n\n";

        cout << "Select Option: ";
        cin >> choice;
        cin.ignore();

        switch (choice)
        {
            case CHECKOUT:
            {
                patient.setRecordID();
                surgery.setSurgeryType();
                medication.setMedicationType();
                patient.setNumDaysStay();
                patient.calcCharges();
            } break;

            case PRINT_FORM:
            {
                outputCheckoutReport(patient);
            } break;
        }
    } while (choice != QUIT);

    return 0;
}

void outputCheckoutReport(Patient &patient)
{
    string eLine = "------------------------------------------\n";
    string qLine = "==========================================\n\n";

    cout << fixed << setprecision(2);
    cout << "\n\nPATIENT CHECKOUT REPORT\n\n";
    cout << "Patient ID" << setw(33) << right << "Patient Name\n";
    cout << eLine;
    cout << setw(27) << left << patient.getPatientID(patient.getRecordID())
          << setw(5) << right << patient.getPatientName(patient.getRecordID()) << "\n";
    cout << qLine;

    cout << "Type of Surgery\n";
    cout << eLine;
    cout << setw(33) << left << patient.getAdministeredSurgery()
          << right << "$ " << patient.getSurgeryCharge() << "\n";
    cout << qLine;
   
    cout << "Administered Medication\n";
    cout << eLine;
    cout << setw(33) << left << patient.getAdministeredMedication()
          <<  "$  " << setw(6) << right << patient.getMedicationCharge() << "\n";
    cout << qLine;

    cout << "Days of Stay" << setw(31) << "Daily Rate\n";
    cout << eLine;
    cout << setw(35) << "$ " << setw(7) << right << patient.getDailyRate() << "\n";
    cout << eLine;
    cout << setw(33) << left << patient.getNumDaysStay()
           << "$  " << setw(6) << right << patient.getStayCharge() << "\n";
    cout << qLine;

    cout << setw(33) << left << "Total Charge: "
          << "$ " << right << patient.getTotalCharge() << "\n";
    cout << qLine;
}


Example Output:




Sunday, November 26, 2017

Programming Challenge 13.19 - Trivia Game

Example Files: TriviaGame.7z

Question.h


#ifndef QUESTION_H_
#define QUESTION_H_

#include <string>
using std::string;

#include <array>
using std::array;

#include <vector>
using std::vector;

class Questions
{
    private:   
        vector<string> questions;
        vector<string> answers;

        bool isCorrect;

    public:
        Questions()
        {
        }

        void setQuestions(string qTemp)
        { questions.push_back(qTemp); }

        void setAnswers(vector<string> aTemp)
        { answers = aTemp; }

        void displayQuestion(int);
        void displayAnswers();
        void evaluateAnswer(int, int);

        bool getCorrect() const
        { return isCorrect; }
};

#endif

Question.cpp


#include "Question.h"

#include <iostream>
using std::cout;

/* **********************************************************
            Questions::displayQuestion() : int
    This function accepts an integer as argument. The question
    to be output is determined by the integer value passed to
    it as index.
    ********************************************************** */

void Questions::displayQuestion(int qNum)
{
    cout << "Question: " << questions[qNum] << "\n\n";
}

/* **********************************************************
            Questions::displayAnswers()
    This function outputs the trivia answers.
    ********************************************************** */

void Questions::displayAnswers()
{
    int cntA = 1;

    for (auto answer : answers)
    {
        cout << "Answer " << (cntA++) << ": " << answer << "\n";
    }
}

/* **********************************************************
            Questions::evaluateAnswers() : int, int
    This function accepts two integer values as argument. It
    evaluates the answer, held by the uAnswer variable, and
    compares these to the vector holding the correct answers.
    ********************************************************** */

void Questions::evaluateAnswer(int uAnswer, int qNum)
{
    const vector<int> correctAnswers{ 0, 3, 1, 2, 1, 2, 2, 0, 1, 2 };

    if (uAnswer-1 == correctAnswers[qNum])
    {
        isCorrect = true;
        cout << "\nCORRECT!\n\n\n";
    }
    else
    {
        cout << "\nWRONG!\n";
        cout << "The correct answer is " << (correctAnswers[qNum] + 1) << ": "
              << (answers[correctAnswers[qNum]]) << "\n\n\n";
    }   
}

Player.h


#ifndef PLAYER_H_
#define PLAYER_H_

#include <string>
using std::string;

class Player
{
    private:
        string playerName;        // Holds a players name
        int     score;                // Holds a players score

    public:   
        Player() : playerName(""), score(0)
        {}

        void setPlayerName();
        bool isPlayerName(string, int);

        void setScore()
        { ++score; }

        string getPlayerName() const
        { return playerName; }

        int getScore() const
        { return score; }
};

#endif

Player.cpp


#include "Player.h"

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Player::setPlayerName()
    This function asks the player to enter his or her name.
    The input is validated.
    ********************************************************** */

void Player::setPlayerName()
{
    static int playerNum = 1;
    string      tempName = "";
   
    cout << "Please enter your name, Player " << playerNum << ": ";
    getline(cin, tempName);

    while (isPlayerName(tempName, playerNum) == false)
    {
        getline(cin, tempName);
    }

    ++playerNum;
}

/* **********************************************************
            Player::isPlayerName()
    This function validates the players input.
    ********************************************************** */

bool Player::isPlayerName(string tempName, int playerNum)
{
    if (tempName.empty() || tempName.at(0) == ' ')
    {
        cout << "Please enter your name Player " << (playerNum) << ": ";
        return false;
    }
    else
    {
        playerName = tempName;
        return true;
    }
}

Game.h


#ifndef GAME_H_
#define GAME_H_

#include "Player.h"
#include "Question.h"

#include <vector>
using std::vector;

class Game
{
    private:
        static constexpr int NUM_QUESTIONS = 10;
        static constexpr int NUM_PLAYERS = 2;

        int numCorrect;
        int playerNum;

        vector<Questions> trivia;
        vector<Player> player;

    public:
        Game() : trivia(NUM_QUESTIONS), player(NUM_PLAYERS)
        {
            loadQuestions();
            loadAnswers();
        }

        void setupPlayers();
        void loadQuestions();
        void loadAnswers();
        void play();
        void switchPlayers(int);
        bool isValidInput(int);
        void displayScore();
        void announceWinner();
       
        int getPlayerNum() const
        { return playerNum; }
};

#endif

Game.cpp


#include "Game.h"

#include <iomanip>
using std::left;
using std::right;
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

#include <limits>
using std::numeric_limits;
using std::streamsize;

#include <fstream>
using std::fstream;
using std::ios;

/* **********************************************************
            Game::loadQuestions()
    This function reads the trivia questions from a text file
    into a temporary string object. The contents is passed to
    a function of the Question class.
    ********************************************************** */

void Game::loadQuestions()
{
    string tempQ = "";

    fstream readQuestions("triviaQ.txt", ios::in);

    if (readQuestions.fail() == false)
    {
        while (getline(readQuestions, tempQ))
        {
            for (int i = 0; i < trivia.size(); ++i)
            {
                trivia[i].setQuestions(tempQ);
            }
        }
        readQuestions.close();
    }
    else
    {
        cout << "File processing error ... Please close the program and try again.\n";
    }
}

/* **********************************************************
            Game::loadAnswers()
    This function reads the trivia answers from a text file,
    and passes these to a temporary vector. The contents of
    is then passed to a function of the Question class.
    ********************************************************** */

void Game::loadAnswers()
{
    vector<string> tempA(4);

    fstream readAnswers("triviaA.txt", ios::in);

    if (readAnswers.fail() == false)
    {
        for (int i = 0; i < trivia.size(); ++i)
        {
            for (int j = 0; j < tempA.size(); ++j)
            {
                getline(readAnswers, tempA[j], ',');
            }
            trivia[i].setAnswers(tempA);
        }
        readAnswers.close();
    }
    else
    {
        cout << "File processing error ... Please close the program and try again.\n";
    }
}

/* **********************************************************
            Game::setupPlayers()
    This function makes a call to the Player class, to set the
    player names.
    ********************************************************** */

void Game::setupPlayers()
{
    for (int i = 0; i < NUM_PLAYERS; ++i)
    {
        player[i].setPlayerName();
    }
}

/* **********************************************************
            Game::play()
    This function allows each player in turn to answer five
    trivia questions. I outputs a question and four answers,
    then asks the player to indicate his answer, by entering
    a numeric value in the range of 1-4. If it is correct, the
    players' score counter will increase by a value of 1.
   ********************************************************** */

void Game::play()
{
    int answer = 0;

    for (int i = 0; i < trivia.size(); ++i)
    {
        switchPlayers(i);

        trivia[i].displayQuestion(i);
        trivia[i].displayAnswers();

        cout << "Your answer (1-4): ";
        cin >> answer;

        while (isValidInput(answer) == false)
        {
            cout << "Your answer (1-4): ";
            cin >> answer;
        }

        trivia[i].evaluateAnswer(answer, i);

        if (trivia[i].getCorrect() == true)
        {
            player[getPlayerNum()].setScore();
        }
    }
}

/* **********************************************************
            Game::switchPlayers() : int
    This function accepts an integer value as argument. If the
    value is 0, player ones turn is announced. If the value is
    half the size of available trivia-questions, the players
    are switched, and the next players' turn is announced.
   ********************************************************** */

void Game::switchPlayers(int qNum)
{
    if (qNum == 0)
    {
        cout << "\n\nYour Turn " << player[getPlayerNum()].getPlayerName() << "\n\n";
    }
  
    if (qNum == trivia.size() / 2)
    {
        ++playerNum %= NUM_PLAYERS;
        cout << "\nYour Turn " << player[getPlayerNum()].getPlayerName() << "\n\n";
    }
}

/* **********************************************************
            Game::isvalidInput() : int
    This function accepts an integer as argument. It validates
    the players' input. If it is outside bounds, or of any
    other type than integer, the function returns false, else
    true is returned.
   ********************************************************** */

bool Game::isValidInput(int answer)
{
    if (answer < 1 || answer > 4)
    {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');

        return false;
    }
    else
    {
        return true;
    }

    return false;
}

/* **********************************************************
            Game::displayScore()
    This function outputs the players' names and their score.
   ********************************************************** */

void Game::displayScore()
{
    cout << "\nPlayer Name" << setw(25) << "Score\n\n";

    for (int i = 0; i < NUM_PLAYERS; ++i)
    {  
       cout << setw(15) << left << player[i].getPlayerName()
              << setw(19) << right << player[i].getScore() << "\n";
    }

}

/* **********************************************************
            Game::displayScore()
    This function outputs a congratulatory message, declaring
    the player with the highest score the winner. If both
    players have the same score, both are announced winner.
   ********************************************************** */

void Game::announceWinner()
{
    playerNum = 0;

    if (player[getPlayerNum()].getScore() > player[getPlayerNum() + 1].getScore())
    {
        cout << "\nCongratulations, ";
        cout << player[getPlayerNum()].getPlayerName() << "!\n\n";
        cout << "You are the winner of our $10.000 prize!\n\n";
    }
    else if (player[getPlayerNum() + 1].getScore() > player[getPlayerNum()].getScore())
    {
        cout << "\nCongratulations, ";
        cout << player[getPlayerNum() + 1].getPlayerName() << "!\n";
        cout << "You are the winner of $10.000!\n\n";
    }

    if (player[getPlayerNum()].getScore() == player[getPlayerNum() + 1].getScore())
    {
        cout << "\nWe have a tie! Both ";
        cout << player[getPlayerNum()].getPlayerName() << " and "
              << player[getPlayerNum() + 1].getPlayerName() << " win $2.000!\n\n";
    }
}

TriviaGame.cpp


#include "Game.h"

#include <iostream>
using std::cout;

int main()
{
    Game game;

    cout << "WELCOME TO TRIVIA WORLD!\n\n";

    game.setupPlayers();
    game.play();
    game.displayScore();
    game.announceWinner();

    cout << "This concludes todays quiz!\n"
         << "Don't forget to tune in for another round of TRIVIA WORLD!\n\n";

    return 0;
}


Example Output:







Tuesday, November 21, 2017

Happy 1st Birthday

It has been very quiet around here the past two months, but the completion of A Game of 21 marks the end of it. There has been many reasons, time issues, my incapability to get the game the way I want it, personal reasons also that kept me from finishing it earlier. I do hope that my visitors enjoy playing it, it would make me very happy!

Now, though, it is time for a little celebration. Four days ago, this blog turned one year old, so:

Picture courtesy of PublicDomainPictures.net

Looking back at the beginnings, there was so much this person learned about the C++ language since. What is and isn't possible, the fun one can have, how creative one can get with the language, and so many different things, about so many different topics related to programming challenge problems on the side. I must admit it was fun for the most part, very difficult sometimes, but my motivation never ceased as there is this one goal: To one day write and publish a game, however humble it may be.

Enough of that, and another aspect that is very important: You, my visitors, from all over the world, you are making it worthwhile to continue learning hard, and to share the fruits of the effort with all of you! I sincerely like to thank you all for your visit!

For this person it is now high time to begin working on the two Programming Challenges still left for this chapter. So, back to the IDE it is, and on to whatever is ahead past that. And, as always, I wish my fellow learners that they be able to finish their programming challenges faster than I, and to say thanks to my visitors old and new, regular or otherwise!

Programming Challenge 13.18 - A Game Of 21

 Example File: AGameOfTwentyone.7z

Dice.h


#ifndef DICE_H_
#define DICE_H_

#include <string>
using std::string;

#include <vector>
using std::vector;

class Dice
{
    private:
        const int MIN_VALUE = 1;            // The lowest die value
        const int NUM_DICE = 2;                // The number of dice
        const int DIE_SIDES = 6;            // The number of die sides
        const int NUMELS = 5;                // The number of elements in a row of the diceGfx 2D-vector

        vector<vector<string>> diceGfx;    // Holding a graphic representation of a die
        vector<int> diceValues = {};        // Holding the dice values

    public:
        Dice();

        void seedRng();
        void roll();
        void outputDice();

        vector<int> getDiceValues() const
        { return diceValues; }
};

#endif


Dice.cpp


#include "Dice.h"

#include <cstdlib>
#include <ctime>

#include <iomanip>
using std::setw;

#include <iostream>
using std::cout;

/* **********************************************************
            Dice::Dice()
    This constructor, via initializer-list, initializes the
    diceValues vector and the diceGfx vector of vectors.
    ********************************************************** */

Dice::Dice() : diceValues { 0, 0 },
                    diceGfx { {},
                                 { "+-----+", "|     |", "|  O  |", "|     |", "+-----+" },
                                 { "+-----+", "| O   |", "|     |", "|   O |", "+-----+" },
                                 { "+-----+", "| O   |", "|  O  |", "|   O |", "+-----+" },
                                 { "+-----+", "| O O |", "|     |", "| O O |", "+-----+" },
                                 { "+-----+", "| O O |", "|  O  |", "| O O |", "+-----+" },
                                 { "+-----+", "| O O |", "| O O |", "| O O |", "+-----+" } }
{
    seedRng();
}

/* **********************************************************
    Dice::seedRng()
    This function seeds the random number generator.
    ********************************************************** */

void Dice::seedRng()
{
    srand(static_cast<unsigned int> (time(0)));
}

/* **********************************************************
            Dice::roll()
    This function simulates the rolling of two dice. When it
    is called, the diceValues vector is cleared, the roll of
    n-number of dice is simulated, and the values are pushed
    back into the vector.
    ********************************************************** */

void Dice::roll()
{
    diceValues.clear();

    for (int i = 0; i < NUM_DICE; i++)
    {
        diceValues.push_back((rand() % DIE_SIDES - MIN_VALUE + 1) + MIN_VALUE);
    }
}

/* **********************************************************
            Dice::outputDice()
    This function outputs the dice to screen.
    ********************************************************** */

void Dice::outputDice()
{
    cout << "\n";
    for (int i = 0; i < NUMELS; ++i)
    {
        for (int j = 0; j < NUM_DICE; ++j)
        {
            cout << setw(12) << diceGfx[getDiceValues()[j][i] << setw(17);
        }
        cout << "\n";
    }
    cout << "\n";
}


Player.h



#ifndef PLAYER_H_
#define PLAYER_H_

#include <string>
using std::string;

class Player
{
    private:
        string playerName;        // The players' name

        int roundScore;            // The players' round score
        int finalScore;            // The players' final score
        int highScore;                // The players' highscore

    public:
        Player();

        void setPlayerName();
        bool isPlayerName(string);

        void addRoundScore(int score)       
        { roundScore += score; }

        void addFinalScore()                       
        { finalScore = roundScore; }

        void setHighscore(int high)
        { highScore += high; }

        void resetScore()
        {
            roundScore = 0;
            finalScore = 0;
        }

        string getPlayerName() const
        { return playerName; }

        int getRoundScore() const
        { return roundScore; }

        int getFinalScore() const
        { return finalScore; }

        int getHighscore() const
        { return highScore; }
};

#endif

Player.cpp


#include "Player.h"

#include <iostream>
using std::cout;
using std::cin;

/* **********************************************************
            Player::Player() - Default constructor
    ********************************************************** */

Player::Player()
{
    playerName = "Player One";
    roundScore = 0;
    finalScore = 0;
    highScore = 0;
}

/* **********************************************************
            Player::setPlayerName()
    This function asks the player to enter his or her name.
    ********************************************************** */

void Player::setPlayerName()
{
    string tempName = "";

    cout << "\nAs you enter the ISN-RADIO BAR backroom, you notice, that the room is\n"
          << "almost empty, except for one person sitting behind a table, playing some\n"
          << "sort of game with dice. As you approach the table, he looks up and greets\n"
          << "you.\n\n";
    cout << "Aah, finally! I've been waiting all evening for a player to show up!\n"
          << "My name's Jack Black. Call me Jack, if you like. And what is your name?\n\n";
    cout << "You tell him, that he can call you: ";
   
    cin.ignore();
    getline(cin, tempName);

    while (isPlayerName(tempName) == false)
    {
        getline(cin, tempName);
    }
}

/* **********************************************************
            Player::isPlayerName()
    This function validates the players input.
    ********************************************************** */

bool Player::isPlayerName(string tempName)
{
    if (tempName.empty() || tempName.at(0) == ' ')
    {
        cout << "\nSorry, but I did not get your name.\n"
              << "Could you repeat it please? ";
        return false;
    }
    else
    {
        playerName = tempName;
        return true;
    }

    return false;
}


Dealer.h


#ifndef DEALER_H_
#define DEALER_H_

#include <string>
using std::string;

class Dealer
{
    private:
        string dealerName;        // The dealers' name
        int roundScore;            // The dealers' round score
        int finalScore;            // The dealers' final score
        int highScore;                // The dealers' highscore

    public:
        Dealer()
        {
            dealerName = "Jack Black";
            roundScore = 0;
            finalScore = 0;
        }

        void addRoundScore(int score)
        { roundScore += score; }

        void addFinalScore()
        { finalScore = roundScore; }

        void setHighscore(int high)
        { highScore += high; }

        void resetScore()
        {
            roundScore = 0;
            finalScore = 0;
        }

        string getDealerName() const
        { return dealerName; }

        int getRoundScore() const
        { return roundScore; }

        int getFinalScore() const
        { return finalScore; }

        int getHighscore() const
        { return highScore; }
};

#endif


Game.h

#ifndef GAME_H_
#define GAME_H_

#include "Dice.h"
#include "Dealer.h"
#include "Player.h"

class Game
{
    private:
        enum Choice { ROLL = 'R', HOLD = 'H' };
        enum Highscore { BLACK_JACK = 21, WIN = 2 };

        const int MAX_SCORE = 21;

        bool isPlayerTurn;
        bool isDealerTurn;
        bool isGameOver;
        char choice;
        int  score;

        Dice dice;
        Player player;
        Dealer dealer;

    public:
        Game();

        void run();
        void setup();
        void resetGame();
        void giveChoice();
        void firstTurn();
        void playerTurn();
        void dealerTurn();
        void switchPlayers();
        void calcScore();
        bool isWin();
        bool isWinDealer();
        void displayScoreboard();
        void displayHighscore();

        char getChoice() const
        { return toupper(choice); }

        bool getTurnStateDealer() const
        { return isDealerTurn; }

        bool getTurnStatePlayer() const
        { return isPlayerTurn; }

        int getScore() const
        { return score; }

        bool getGameState() const
        { return isGameOver; }       
};

#endif


Game.cpp


#include "Game.h"

#include <iomanip>
using std::setw;

#include <iostream>
using std::cin;
using std::cout;

/* **********************************************************
            Game::Game() - Default constructor
    ********************************************************** */

Game::Game()
{
    isDealerTurn = true;
    isGameOver = false;
}

/* **********************************************************
            Game::setup()
    This function makes a call to the player class, allowing
    the player to enter his or her player name.
    ********************************************************** */

void Game::setup()
{
    player.setPlayerName();
}

/* **********************************************************
            Game::run()
    This function represents the main gameloop. Upon entry, a
    call to the firstTurn function is made, the players are
    switched, and the players turn begins. If he or she or
    the artificial dealer wins or loses, the game is over, and
    the player asked, if he or she wishes to play again.
    ********************************************************** */

void Game::run()
{
    char again = ' ';

    do
    {
        firstTurn();
        playerTurn();

        if (getGameState() == false)
        {
            switchPlayers();
            dealerTurn();
        }

        if (getGameState() == true)
        {
            cout << "Do you wish to play another round? ";
            cin >> again;

            while (toupper(again) != 'Y' && toupper(again) != 'N')
            {
                cout << "Do you wish to play another round? ";
                cin >> again;
            }

            if (toupper(again) == 'Y')
            {
                resetGame();
            }
        }   
    } while (getGameState() == false);
}

/* **********************************************************
            Game::switchPlayer()
    This function switches dealer and player. If one is active
    the other is set to false, and vice versa.
    ********************************************************** */

void Game::switchPlayers()
{
    if (getTurnStateDealer() == true)
    {
        isDealerTurn = false;
        isPlayerTurn = true;
    }
    else
    {
        isPlayerTurn = false;
        isDealerTurn = true;
    }
}

/* **********************************************************
            Game::firstTurn()
    This function simulates the first turn for both dealer and
    player. After rolling the dice a score is calculated, and
    the result is passed to the appropriate member function of
    the dealer or player class.
    ********************************************************** */

void Game::firstTurn()
{
    dice.roll();
    calcScore();
    dealer.addRoundScore(getScore());

    switchPlayers();

    dice.roll();
    calcScore();
    player.addRoundScore(getScore());
}   
/* **********************************************************
            Game::displayScoreboard()
    This function outputs the dealer and player score.
    ********************************************************** */

void Game::displayScoreboard()
{
    if (getTurnStateDealer() == true)
    {
        cout << dealer.getDealerName() << "'s Score: "
              << dealer.getRoundScore() << " \n\n";
    }
    else
    {
        cout << player.getPlayerName() << "'s Score: "
              << player.getRoundScore() << " \n\n";
    }
}

/* **********************************************************
            Game::playerTurn()
    This function represents the players' turn. The player is
    given a choice to roll or hold. A player is able to roll
    the dice as long as no winning condition is met. If the
    player decides to 'H'old, which is possible at any time,
    his or her turn is over, his or her final score is set,
    and the function exits.
    ********************************************************** */

void Game::playerTurn()
{
    cout << "\n" << player.getPlayerName() << "'s Turn\n";
    displayScoreboard();

    do
    {   
        giveChoice();

        if (getChoice() == ROLL)
        {
            dice.roll();
            dice.outputDice();

            calcScore();
            player.addRoundScore(getScore());

            displayScoreboard();
        }

        if (getChoice() == HOLD)
        {
            cout << "\n" << player.getPlayerName() << " Stands!\n"
                             << player.getPlayerName() << "'s Turn is over ...\n\n";

            player.addFinalScore();
        }
    } while (isWin() == false && getChoice() != HOLD);
}

/* **********************************************************
            Game::giveChoice()
    This function asks the player during his or her turn, if
    they wish to roll or hold. The input is validated.
    ********************************************************** */

void Game::giveChoice()
{
    cout << "Do you wish to [R]oll or [H]old? ";
    cin >> choice;
   
    while (getChoice() != ROLL && getChoice() != HOLD)
    {
        cout << "Do you wish to [R]oll or [H]old? ";
        cin >> choice;
    }
}
/* **********************************************************
            Game::dealerTurn()
    This function represents the dealers' turn. The dice are
    rolled, the score calculated and passed to the appropriate
    member function of the dealer class, until a general or a
    specific winning condition unique to the dealer is met.
    ********************************************************** */

void Game::dealerTurn()
{
    cout << "\n" << dealer.getDealerName() << "'s Turn\n";
    displayScoreboard();

    do
    {
        dice.roll();
        dice.outputDice();

        calcScore();
        dealer.addRoundScore(getScore());

        displayScoreboard();
    } while (isWin() == false && isWinDealer() == false);
}

/* **********************************************************
            Game::calcScore()
    This function calculates and passes the score achieved to
    either the dealer or player classes member function.
    ********************************************************** */

void Game::calcScore()
{
    score = 0;

    for (auto points : dice.getDiceValues())
    {
        score += points;
    }   
}

/* **********************************************************
            Game::isWin()
    This function evaluates the basic winning conditions of
    this game. If a winning or losing condition is met, the
    winner or loser is announced, the isGameOver condition is
    set to true und is returned from the function.
    ********************************************************** */

bool Game::isWin()
{
    if (player.getRoundScore() == MAX_SCORE || dealer.getRoundScore() == MAX_SCORE)
    {
        cout << "BLACK JACK!\n";
   
        if (player.getRoundScore() == MAX_SCORE)
        {
            cout << player.getPlayerName() << " Wins!\n\n";       
            player.setHighscore(BLACK_JACK);
        }
        else
        {
            cout << dealer.getDealerName() << " Wins!\n\n";       
            dealer.setHighscore(BLACK_JACK);
        }
        return isGameOver = true;
    }
   
    if (player.getRoundScore() > MAX_SCORE || dealer.getRoundScore() > MAX_SCORE)
    {   
        if (player.getRoundScore() > MAX_SCORE)
        {
            cout << player.getPlayerName() << " Busts ...\n"
                  << dealer.getDealerName() << " Wins!\n\n";

            dealer.setHighscore(WIN);
        }
        else
        {
            cout << dealer.getDealerName() << " Busts ...\n"
                  << player.getPlayerName() << " Wins!\n\n";

            player.setHighscore(WIN);
        }
        return isGameOver = true;
    }

    return isGameOver = false;
}

/* **********************************************************
            Game::isWin()
    This function evaluates additional winnings conditions,
    specific to the dealer.
    ********************************************************** */

bool Game::isWinDealer()
{
    if (dealer.getRoundScore() > player.getFinalScore())
    {
        cout << dealer.getDealerName() << " Wins!\n";   
        dealer.setHighscore(WIN);
       
        return isGameOver = true;
    }
    else if (dealer.getRoundScore() == player.getFinalScore())
    {
        cout << "DRAW!\n\n";
        return isGameOver = true;
    }

    return isGameOver = false;
}

void Game::displayHighscore()
{
    cout << "\n" << setw(23) << "HIGHSCORE LIST\n\n";
    cout << setw(15) << dealer.getDealerName() << setw(20) << dealer.getHighscore() << "\n"
          << setw(15) << player.getPlayerName() << setw(20) << player.getHighscore() << "\n";
}

/* **********************************************************
            Game::isWin()
    This function evaluates additional winnings conditions,
    specific to the dealer.
    ********************************************************** */

void Game::resetGame()
{
    isGameOver = false;
    isDealerTurn = true;

    dealer.resetScore();
    player.resetScore();
}


Example Output: