/*
Assignment Program
Software develeopment
April 2020 semester 2.

Author: Mark Lawrence Edwin Vaughan (1909160)
*/

#include <string>
#include <iostream>
#include <sstream>



using namespace std;

/* class definitions */
#include<sstream>

enum geo_te : int { none, circle, square, rectangle, triangle }; // define enumeration type Geo_t

struct geom {
    int   gType;
    float area;
    float lenRad;
    float width;
    float height;
}; // Global type def.

class myIO {

#include<string>
#include<iostream>
#include <sstream>

    /* Variable Declarations */
    string buffer;

    /* Function declarations */
  
private:
    /* place private functions here... */
    

public:
    myIO() {};                                                          // Class Constructor

    string GetStr(string prompt) {
        string entry;

        std::cout << prompt << endl << ">:";                            // Display Prompt string
        getline(cin,entry);                                              // Obtain String entry from u
        return entry;                                                   // return string to calling procedure
     }// end GetStr

    int GetInt(string prompt) {
        int result;
        string s;                                                       // Tempoory String Variable
        stringstream buffer;
        s = GetStr(prompt);                                             // get an entered string
        buffer.str(s);

        buffer.str >> result;                                           // Convert string to return type
        buffer.clear;                                                   // Clear String buffer before garbage collection
        return result;
    }

    float GetFloat(string prompt) {
        float result;
        string s;                                                       // Tempoory String Variable
        stringstream buffer;

        s = GetStr(prompt);                                             // get an entered string
        buffer.str(s);                                                  // Transfer string to buffer variable

        buffer.str >> result;                                           // convert string to float value using overloaded operator
        buffer.clear;                                                   // Clear String buffer before garbage collection
        return result;
    }
    double GetDouble(string prompt) {
        double result;
        string s;                                                       // Tempoory String Variable
        stringstream buffer;

        s = GetStr(prompt);                                             // get an entered string
        buffer.str(s);                                                  // Transfer string to buffer variable

        buffer.str >> result;                                           // convert string to double value using overloaded operator
        buffer.clear;                                                   // Clear String buffer before garbage collection
        return result;
    }
    bool GetBool(string prompt) {
        bool result;
        string s;
        stringstream buffer;
        bool valid = false;
        char letter;
        
        prompt = prompt + " Y or N?";                               // ammend prompt to show Y/N reply
        do {
            s = GetStr(prompt);

            letter = s[0]; /* added to avoid string parameter in switch block */

            switch (letter) {
                case 'Y': {}
                case 'y':{
                    result = true;
                    valid = true;
                    break;
                } // Response was yes

                case 'N': {}
                case'n': {
                    result = false;
                    valid = true;
                    break;
                } // Response was false

                default: {
                    cout << "Invalid Entry - please try again..." << endl;
                } // invalid response
            }// End switch

        } while (!valid);                                               // repeat while answer is invalid
        return result;
    }; // End function GetBool

};// End Class myIO

const float PI = 3.1515928;

/* Global Variable declaration  - They are Martini Vars!*/

myIO Konsol;  //  Instantiate myIO Class.


/* Forward declarations */

void CalcArea(geom& shape);
void ScreenClear(int toScroll);
int EnterOrd(string propmt);
void ScreenClear(int toScroll);
void pressEnter();
void exercise2();
void exercise3();
void exercise4();




void CalcArea(geom& shape){
    float f; // Temp Variable 

    switch (shape.gType){
    case geo_te::none: // Zero value - no shape assignment
            // do nothing
            break;
    case geo_te::circle:{  // circle
            f = PI * pow(shape.lenRad,2);               // PI * radius to  the power of 2
            shape.area = f;
            break;
        }
    case geo_te::square:{ // Square
        f = pow(shape.lenRad,2);                        // Length of side to the power of 2
        shape.area = f;
        break;
        }
    case geo_te::rectangle: {// Rectangle
            f = (shape.lenRad * shape.width);
            shape.area = f;
            break;
        }
    case geo_te::triangle: {// Triangle
            /* Not implemented at this time */
            break;
        }
        default: { // ** coding error **
                cout << "Invalid gType in CalcArea function";
               exit(0); // Halt Program
        }

    }
};// end CalcArea

void ScreenClear(int toScroll){ // Clear consol screen routine
    for (int i=0; i<toScroll;i++){
        cout << endl;
    }
}//End function ScreenClear

int EnterOrd(string prompt){
    int v; // temp variable
    do{
        v = Konsol.GetInt(prompt); // call GetInt function
        /* if value is wrong display error message */
        if(v< 0 or v> 7){cout << "please enter a value between zero and seven" << endl;}
    }while(v<0 or v>7); // loop until valid entry made
    return v;

}// End function EnterOrd

void pressEnter(){
    cout << "Press <Enter> to Continue ..." << endl;
    cin;
}// End pressEnter

void exercise1() {
    /* Exercise 1 */

    string bookTitle;
    /*
    The variable bookTitle is set as a string as book names consist of
    a string of alphanumeric characters of varing length.  String
    types are most suited as they can hold upto 255 ASCII characters
    excluding the null character which is used as the end of string
    delimiter. Please note that the description refers to the older
    C-string type as opposed to the nre C++ String class.
    */

    float measure;
    /*
    The variable measure has been defined as a float type. Measurements
     are a numeric value that is positive and may be either fractional or
     whole. To store this type of data, float and double types can be used
     as they provide a means of holding whole andfractional values.  In
     this case a  float has been used as the memory used is four bytes as
     opposed to eight bytes for double types and the majority of real world
     measurements are less that 9000 units which is within the range specified
      for float types.
    */

    int prodCount;
    /*
    The ProdCount variable is specifed as an integer. As items are never fractional
    the integer type is used. Integer types can be either positive or negative in
    value and so can be used to count the number of products in a shoppomng basket
    and can also be used to deduct items when used in a discounting role. An eample
    of this would be a three for two deal where three items can be urchased and
    only pay for two.  For the purposes of calculation, three items can be charges
    but another entry where one item is deducted will correct the payment values
    to the correct amount.
    */
}// End exercise1

void exercise2() {
    // Constants Declaration
    const int MAXSHAPE = 3; // Maximum number of shapes

     // Variable Declarations
    geom arrayShape[MAXSHAPE];                                  // Shape Data Storage array
    int idx;                                                    // current array working element value
    float compArea;                                             // calculated compund shape area

                    /* enter shape data */
    idx = 0;                                                    // set working index to main shape
    arrayShape[idx].lenRad = Konsol.GetFloat("Enter main Shape Length");
    arrayShape[idx].width = Konsol.GetFloat("Enter Main Shape Width");

    idx = 1;                                                    //set working index to inner circle
    arrayShape[idx].lenRad = Konsol.GetFloat("Enter Inner Circle Length");
    arrayShape[idx].width = Konsol.GetFloat("Enter Inner Circle Width");

    idx = 2;                                                    // Set working index to inner rectangle
    arrayShape[idx].lenRad = Konsol.GetFloat("Enter Inner Rectangle Length");
    arrayShape[idx].width = Konsol.GetFloat("Enter Inner Rectangle Width");

    // Calculate Shape Areas
    for (idx = 0; idx < MAXSHAPE; idx++){
        /* Calculate Area and update area value in referenced storage array element */
        CalcArea(arrayShape[idx]);
    }; //End for loop


    // Calculate compund shape area
    compArea = arrayShape[0].area - (arrayShape[1].area + arrayShape[2].area);

    // Display Area cof counpund shape.
    std::cout << endl << "The Calculated area for the compund shape is: " << compArea << endl;

}; // End function exercise2

void exercise3(){
/*
Exercise 3 (30%)
(a)	Ask the user to enter an arbitrary set of prices in 
    GBP into an array and display all the entered prices. 
(b)	Add all the prices together and display the result.
(c)	Convert the overall total to Euros and display it.

 This exercise requires the user to enter an series of 
cash values into an array, add them up and display the 
result. It then as ks for the total to be converted to 
euro's and the result displayed. As the numer of entrys 
is not specified, the user must be asked for the number 
of entrys to be made and then entered. Other information 
required is the conversion rate for the Euro which is a 
float value and should be entered as euro against the pound.
*/

// Constants Declaration
const int MAXENTRY = 100;

// Variables Declaration
int noOfEntry;                                                  // number of entries
float euroEx;                                                   // Euro exchange rate
float arrValues[100];                                           // Storage array for cash values - limited to 100 entries
float totValue;                                                 // Combined totals of entrered values
float euroValue;                                                // Total Value(GBP) in Euros
string p;                                                       // Tempory variable for prompt string

            // ask user for number of entries
while(noOfEntry < 1 or noOfEntry >= MAXENTRY){                  // repeat until correct value is entered
    noOfEntry = Konsol.GetInt("How many values to be entered (1-100)?");
} // end while

            // ask user for exchange rate
while(euroEx <= 0){                                             // repeat until a valid value is entered.
    euroEx = Konsol.GetFloat("Enter Euro exchange rate against the pound.");
}
            // Enter values
for (int i = 0; i<noOfEntry; i++){
    p = "Enter amount(GBP) for entry NO:"+i;                    // Create prompt string
    do{
        arrValues[i] = Konsol.GetFloat(p);                             // call function to get a float value
    }while(arrValues[i] < 0);                                   // Range check for negative values or string entries.
}// End For loop

            // Calculate total of entered values and display
for (int i = 0;i < noOfEntry;i++){                             // Add up entrys
    totValue += arrValues[i];                                   // increment Running total with arrray entry.
}// End For loop

cout << "The Total Value of Entered sums is " << totValue <<" Pounds Stirling." << endl;

            // Convert total to Euros and display
    euroValue = totValue * euroEx; 
    cout << "The Total Value of Entered sums is " << euroValue << " in Euors."<< endl;

} // End exercise3

void exercise4(){
    /* Treasure Game - 2 Player game where player one enters 
    the location of 3 hidden treasures in a 8x8 grid. Player 
    2 then has three lives with which to find the treasures. 
    Game ends when all lives are lost or all treasures are 
    found. Turn results are displayed on an on screen grid.
    */

    /* Constant Declarations */
    const int MAXLIFE = 3;                                      // Max no of lives
    const int GRIDSIZE = 64;
    const int SCREENROW = 30;                                   // Default value for number of rows on a screen

    /* variable Declaratations */
    struct grid{
        /*
        Status of grid cell 
        0 = blank 
        1 = check(failed), 
        2 = check(confirmed )
        */
        int status; 
        bool isTreasure;                                        // Treasure placed here flag
        };
    
    grid gridData[GRIDSIZE];                                    // Array holding Playing area data
    int x,y;                                                    // temp grid variables
    int livesLeft = 3;  
    int treasureFound = 0;                                      // number of treasures found                                        // Number of lives left
    bool winstatus = false;                                     // Set true if all treasures are found

// Initilise grid
for (int i = 0;i < GRIDSIZE; i++){
    gridData[i].status = 0; 
    gridData[i].isTreasure = false; 
    }// End For loop

/* Display Instructions */

/* Enter palyer one treasure data and clear screen */
for (int i=0;i<3;i++){
    cout << "For Treasure location no:"<<i+1<<endl;
    x = EnterOrd("Enter the X Co-Ordinate (0-7).");
    y = EnterOrd("Enter the Y Co-Ordinate (0-7).");
    gridData[(x*8)+y].isTreasure = true;                // Set Grid treasure flag to true
}// End For loop

ScreenClear(SCREENROW);                                 // scroll screen up};


/* player 2 to play game */
do{
    /* display grid on screen */
    cout << " : 0 1 2 3 4 5 6 7" << endl;                         // display column header
    for(int i = 0;i < 8; i++){
        cout << i << ": ";                                  // display row header
        for(int j = 0;j<8;j++){
            switch (gridData[(i*8)+j].status){
                case 0:{
                    cout << "- ";                        // unchecked grid cell
                    break;
                }
                case 1:{
                    cout << "N ";                        // checked grid cell
                    break;
                }
                case 2: {
                    cout << "X ";                        // found  treasure grid cell
                    break;
                }
            }//End switch
        }// End J for loop
        cout << endl;                                   // move to next line on screen
    }// End i for loop

    /* enter guess co-ords */
    cout << "You have "<< livesLeft << " lives left" << endl;
    cout << " Enter your Guess."<< endl;
    x = EnterOrd("X:");
    y = EnterOrd("Y:");

    /* 
        check if treasure found and enter result
        into status field 
    */
    if (gridData[(x*8)+y].isTreasure = true){
        gridData[(x*8)+y].status = 2;                   // Set grid cell to check(confirmed)
        treasureFound +=1;                              // Add 1 to treasures found
        switch (treasureFound){
            case 1:{
                cout << "Congratulations You have Found the first Treasure!"<< endl;
                break;
            }
            case 2:{
                cout << "Congratulations You have Found the second Treasure!"<< endl;
                break;
            }
            case 3:{
                cout << "Congratulations You have Found the final Treasure!"<< endl;
                break;
            }
        }
        pressEnter();                               // Await user to press enter key.
    } // Treasure found
    else
    {
        gridData[(x*8)+y].status = 1;               // set grid cell to checked(failed)
        livesLeft -=1;                              // remove one life
        cout << "Sorry - there was no Treasure there."<< endl;
        pressEnter();                               // Await user to pres enter key
    }
    
    /* if all treasures found set winstatus to true */
    if(treasureFound == 3){winstatus = true;}

}while(!winstatus and livesLeft > 0);               // loop until all lives expired or treasures found

// End of Game - display results
cout << "The Game Has finished!  - ";
if(winstatus){                                      // if all treasures found
    cout << "Player 2 has Won!"<< endl;
    }// End if
else {                                              // display losing message
    cout << "Player 2 has lost"<< endl;
    if(treasureFound>0){                            // and throw a consolation prize
        cout << "But " << treasureFound << " Treasure(s) were found" << endl;
        }
    }// End else

} //End exercise4



int main(int argc, char* argv[]){
    bool active = true;
    int option = 0;
    myIO Konsol; //  Instantiate myIO Class.

    do {
    // clear screen
        ScreenClear(30);

    // display options
        cout << "Assignment Program Version 1.0 alpha" << endl;
        cout << "Options" << endl;
        cout << "=======" << endl << endl;
        cout << "1. Exercise 2 - Compound Area Calculation." << endl;
        cout << "2. Exercise 3 - Cash Value calculation using arrays." << endl;
        cout << "3. Exercise 4 - Treaasure Game." << endl;
        cout << "9. Quit Program." << endl;

    // get user response
        option = Konsol.GetInt("Enter option 1-3 or 9 to exit");
        switch (option) {
        case 1: {
            exercise2(); // execute Exercise No 2
            break;
        }
        case 2: {
            exercise3();
            break;
        }
        case 3: {
            exercise4();
            break;
        }
        case9: {
            active = false;
            break;
            }
        default: {
            cout << "Invalid Input - please try again." << endl;
            pressEnter();
            }
        }// end switch 
    } while (active); // Loop until option 9 is selected.

}// End of Run