//Name: Joseph Ho Zi Hao
//Student ID: 7083336
//Tutorial Group: T03

#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdlib.h>
#include <iomanip>

using namespace std;
//function prototype in the Weather Information Processing System (WIPS)

//to read in and process a config file
void mainMenu();

//to display the city map, cloud coverage(cloudiness index + LMH symbols)
//and atmospheric pressure map(cloudiness index + LMH symbols)

void readConfigFile(string filename, int &xIdx, int &yIdx, string readFiles[3], int**& IdArray, string**& NameArray, int**& cloudCover, int**& pressure);
void city2DArray(string filename, int**& IdArray, string**& NameArray, int xIdx, int yIdx);
void grid2DArray(string filename, int**& GridArray, int xIdx, int yIdx);
void display2DArray(int** displayOn, int cols, int rows);
void display2DArray(string** displayOn, int cols, int rows);
void cloudPressure(int** displayOn, int cols, int rows);
void cloudPressureLMH(int** displayOn, int cols, int rows);
bool haveName(string* name, string MatchName, int size);
double calcAvg(string** NameArray, int** GridArray, int cols, int rows, string cityName);
char getLMH(double avg);
int getProbabb(char avg1, char avg2);
void displayGraphics(int probability);

//option 7: show weather forecast summary report
void summaryReport(string** NameArray, int** IdArray, int** cloudArray, int** pressureArray, int cols, int rows);

//to de-allocate memory
void deallocateMemory(int** IdArray, string** NameArray, int** cloudArray, int** pressureArray, int xIdx, int yIdx);

//vector function to separate a string with a delimiter from extra resources
vector<string> tokenizeString (string input, string delimiter)
{
	size_t pos = 0;
	string token;
	vector<string> result;

	while ((pos = input.find(delimiter)) != string::npos) 
	{
    	token = input.substr(0, pos);
    	result.push_back (token);
		input.erase(0, pos + delimiter.length());
	}

	result.push_back (input);

	return (result);
}

//main function of this program
int main()
{
	char option = ' '; //For user to press Enter to return back to the main menu
	string fileNames[3];
	int gridX_Idx, gridY_Idx;
	gridX_Idx = gridY_Idx = 0; //initialize both to 0

	int** cityId = NULL;
	string** cityName = NULL;
	int** cloudCover = NULL;
	int** pressure = NULL;

	while(true)
	{
    	mainMenu();
    	cin >> option;
    	cout << endl;
   	 
    	switch(option)
    	{
        	case '1':
        	{
            	string filename;
            	cout << "[ Read in and process a configuration file ]" << endl;
		  cout << "Please enter config filename : ";
            	cin >> filename;
            	readConfigFile(filename, gridX_Idx, gridY_Idx, fileNames, cityId, cityName, cloudCover, pressure);
            	break;
        	}
        	case '2':
        	{
            	if(cityName != NULL)
                	display2DArray(cityId, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '3':
        	{
            	if(cityName != NULL)
                	cloudPressure(cloudCover, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '4':
        	{
            	if(cityName != NULL)
                	cloudPressureLMH(cloudCover, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '5':
        	{
            	if(cityName != NULL)
                	cloudPressure(pressure, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '6':
        	{
            	if(cityName != NULL)
                	cloudPressureLMH(pressure, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '7':
        	{
            	if(cityName != NULL)
                	summaryReport(cityName, cityId, cloudCover, pressure, gridX_Idx, gridY_Idx);
            	else
                	cout << "No record stored from input file. Select option 1 to input again " << endl;
            	break;
        	}
        	case '8':
        	{
            	if(cityName != NULL)
                	deallocateMemory(cityId, cityName, cloudCover, pressure, gridX_Idx, gridY_Idx);
            	break;
        	}
        	default:  cout << "Choose the correct option " << endl;
		break;
    	}

    	if(option == '8')
    	{
        	cout << "The End! " << endl;
		break;
    	}

    	if(option >= '2' && option <= '7')
    	{
        	string temp = "";
        	getline(cin, temp);
        	cout << endl << "Press <enter> to go back main menu ... ";
        	cin.ignore();
        	cin.clear();
    	}
	}
	return 0;
}

//function definition of the main menu
void mainMenu()
{
	int studentID = 7083336;
	string studentName = "Joseph Ho Zi Hao";
	
	cout << "Student ID   : " << studentID << endl;
	cout << "Student Name : " << studentName << endl;
	cout << "---------------------------------------------------------" << endl;
	cout << "Welcome to Weather Information Processing System!" << endl;
	cout << endl;
	cout << "1)  Read in and process a configuration file " << endl;
	cout << "2)  Display city map " << endl;
	cout << "3)  Display cloud coverage map (cloudiness index) " << endl;
	cout << "4)  Display cloud coverage map (LMH symbols) " << endl;
	cout << "5)  Display atmospheric pressure map (pressure index) " << endl;
	cout << "6)  Display atmospheric pressure map (LMH symbols) " << endl;
	cout << "7)  Show weather forecast summary report " << endl;
	cout << "8)  Quit " << endl;
	cout << endl;
	cout << "Please enter your choice : ";
}

//function definition of reading in and processing of a config file
void readConfigFile(string filename, int &xIdx, int &yIdx, string readFiles[3], int**& IdArray, string**& NameArray, int**& cloudArray, int**& pressureArray)
{
	ifstream inFile(filename.c_str());
	string str;
	int a = 0;
	int count = 1;
    
	//read data from the input file
	if(inFile)
	{
    	while(getline(inFile, str))
    	{
        	if(!str.empty() && (str[0] != '/'))
        	{
            	if(count == 1)
            	{
                  string xLine = str;
                  vector<string> tokenStringVector = tokenizeString(xLine, "-");
                  string gridX_Idx = tokenStringVector[1];
		  xIdx = std::stoi(gridX_Idx) + 1;
                  tokenStringVector.clear();
                  cout << endl << "Reading in GridX_IdxRange : 0-" << gridX_Idx << "... done!" << endl;
	   	  count++;
            	}
            	else if(count == 2)
            	{
                  string yLine = str;
                  vector<string> tokenStringVector = tokenizeString(yLine, "-");
                  string gridY_Idx = tokenStringVector[1];
 		  yIdx = std::stoi(gridY_Idx) + 1;
                  tokenStringVector.clear();
                  cout << "Reading in GridY_IdxRange : 0-" << gridY_Idx << "... done!" << endl;
	   	  count++;
	  	  cout << endl << "i'm storing data from input file : " << endl;
       	 
            	}
            	else
            	{
                	readFiles[a] = str;
                	a++;
            	}
        	}
    	}
    	inFile.close();

    	city2DArray(readFiles[0], IdArray, NameArray, xIdx, yIdx);
    	grid2DArray(readFiles[1], cloudArray, xIdx, yIdx);
    	grid2DArray(readFiles[2], pressureArray, xIdx, yIdx);
    	cout << endl << "All the records are successfully stored! Going back to main menu ..." << endl << endl;
	}

	else
	{
    	  cout << "i am unable to open the input file (" << filename << ")" << endl;
     	  string temp = "";
     	  getline(cin, temp);
     	  cout << "Press <enter> to go back main menu ...";
     	  cin.ignore();
	}    
}

//function definition of city map
void city2DArray(string filename, int**& IdArray, string**& NameArray, int xIdx, int yIdx)
{
	ifstream inFile; //input the file
	inFile.open(filename.c_str());
	string str;
	int x, y;
	x = y = 0; //initialize to 0 for both x & y
    
	if(inFile.good())
   	cout << filename << " ... done!" << endl;
   	else
   	cout << "i failed to store data from input file.." << endl;

//allocation of dynamic memory for various variables
IdArray = new int *[yIdx];
	NameArray = new string *[yIdx];

	for(int i=0; i < yIdx; i++)
	{
    	  IdArray[i] = new int[xIdx];
    	  NameArray[i] = new string[xIdx];

    	for(int j=0; j < xIdx; j++)
    	{
          IdArray[i][j] = -1;
          NameArray[i][j] = "";
    	}
	}

	if(inFile.is_open())
	{
    	while(!inFile.eof())
    	{
          getline(inFile, str);
	  if(!str.empty())
	      	{
	        vector<string> tokenStringVector = tokenizeString(str, "-"); 
	        string grid = tokenStringVector[0]; // starting [1,1] to ...
	        x = atoi(grid.substr(1, grid.find(',') - 1).c_str());  
	        grid = grid.substr(grid.find(',') + 2); 
	        y = atoi(grid.substr(0, grid.find(']')).c_str()); 

	        IdArray[y][x] = std::stoi(tokenStringVector[1]); 
	        NameArray[y][x] = tokenStringVector[2]; //"Big_City"...
	    	}
    	}
    	  inFile.close();
	}
	else
	{
    	cout << "i am unable to open the input file (" << filename << ")!" << endl;
	}
}

//other function definitions
void grid2DArray(string filename, int**& gridArray, int xIdx, int yIdx)
{
	ifstream inFile;
	inFile.open(filename.c_str());
	string str;
	int x , y;
	x = y = 0;
	if(inFile.good())
    	cout << filename << " ... done!" << endl;
   	else 
   		cout << "i failed to store data from input file!" << endl;
	gridArray = new int *[yIdx];

	for(int i=0; i < yIdx; i++)
	{
    		gridArray[i] = new int[xIdx];

    	for(int j=0; j < xIdx; j++)
        	gridArray[i][j] = -1;
	}

	if(inFile.is_open())
	{
    	while(!inFile.eof())
    	{
        	getline(inFile, str);

        	if(!str.empty())
        	{
            	vector<string> tokenStringVector = tokenizeString(str, "-");
           	 
            	string grid = tokenStringVector[0]; //starting [0,0] to ...
            	x = atoi(grid.substr(1, grid.find(',') - 1).c_str()); // 0
            	grid = grid.substr(grid.find(',') + 2); 
            	y = atoi(grid.substr(0, grid.find(']')).c_str()); 

            	gridArray[y][x] = std::stoi(tokenStringVector[1]); //41...
        	}
    	}
    	inFile.close();
	}
	else
	{
    	cout << "i am unable to open the input file (" << filename << ")!" << endl;
	}
}

void display2DArray(int** displayOn, int cols, int rows)
{
	cout << setw(5) << left << "";
	for(int i=0; i < cols + 2; i++)
	{
    	cout << setw(5) << left << "#";
	}
	cout << endl << endl;

	for(int i=rows-1; i >= 0; i--)
	{
    	cout << setw(5) << left << i << setw(5) << left << "#";

    	for(int j=0; j < cols; j++)
    	{
        if(displayOn[i][j] != -1)
            cout << setw(5) << left << displayOn[i][j];
        else
            cout << setw(5) << left << "";
    	}
    	cout << setw(5) << left << "#" << endl << endl;
	}
	cout << setw(5) << left << "";
	for(int i=0; i < cols + 2; i++)
	{
    	cout << setw(5) << left << "#";
	}
	cout << endl << endl;
	cout << setw(10) << left << "";
	for(int i=0; i < cols; i++)
	{
    	cout << setw(5) << left << i;
	}
	cout << endl;
}

void cloudPressure(int** displayOn, int cols, int rows)
{
	int** singDigit = new int *[rows];

	for(int i=0; i < rows; i++)
	{
    		singDigit[i] = new int [cols];

    	for(int j=0; j < cols; j++)
    	{
        	singDigit[i][j] = displayOn[i][j] / 10;
    	}
	}
	display2DArray(singDigit, cols, rows);

	//deallocate singdigit array of cloud cover value
	for(int i=0; i < rows; i++)
       	delete[] singDigit[i];

	delete[] singDigit;
}

void cloudPressureLMH(int** displayOn, int cols, int rows)
{
	string** LMHArray = new string *[rows];

	for(int i=0; i < rows; i++)
	{
    	LMHArray[i] = new string[cols];

    	for(int j=0; j < cols; j++)
    	{
        	if(displayOn[i][j] >= 0 && displayOn[i][j] < 35)
            	LMHArray[i][j] = "L";
        	else if(displayOn[i][j] >= 35 && displayOn[i][j] < 65)
            	LMHArray[i][j] = "M";
        	else
            	LMHArray[i][j] = "H";
       	}
	}
	display2DArray(LMHArray, cols, rows);
}

void display2DArray(string** displayOn, int cols, int rows)
{
	cout << setw(5) << left << "";
	for(int i=0; i < cols + 2; i++)
	{
    	cout << setw(5) << left << "#";
	}
		cout << endl << endl;

	for(int i=rows-1; i >= 0; i--)
	{
    	cout << setw(5) << left << i << setw(5) << left << "#";

    	for(int j=0; j < cols; j++)
    	{
          if(displayOn[i][j] != "")
          	cout << setw(5) << left << displayOn[i][j];
          else
            cout << setw(5) << left << "";
    	}
    	cout << setw(5) << left << "#" << endl << endl;
	}
	cout << setw(5) << left << "";
	for(int i=0; i < cols + 2; i++)
	{
    	  cout << setw(5) << left << "#";
	}
	cout << endl << endl;
	cout << setw(10) << left << "";
	for(int i=0; i < cols; i++)
	{
    	  cout << setw(5) << left << i;
	}
	cout << endl;
}

bool haveName(string* name, string MatchName, int size)
{
	for(int i=0; i < size; i++)
	{
    	if(name[i] == MatchName)
        	return true;
    	else if((name[i] == "") || (name[i] != MatchName))
        	return false;
	}
	return false;
}

double calcAvg(string** NameArray, int** gridArray, int cols, int rows, string cityName)
{
	double sum = 0;
	int count = 0;

	bool aboveEmpty, belowEmpty, rightEmpty, leftEmpty = false;
    
	for(int i=0; i < rows; i++)
	{
    	for(int j=0; j < cols; j++)
    	{
	        if(NameArray[i][j] == cityName)
	        {
	            //to add in the designated bright yellow area
	            sum += gridArray[i][j];
	            count++;

	            //to add in surrounding area to bright yellow area
	            if((i + 1 < rows) && (NameArray[i+1][j] != cityName))
	               	aboveEmpty = true;
	            if((i > 0) && (NameArray[i-1][j] != cityName))
	               	belowEmpty = true;
	            if((j + 1 < cols) && (NameArray[i][j+1] != cityName))
	               	rightEmpty = true;
	            if((j > 0) && (NameArray[i][j-1] != cityName))
	               	leftEmpty = true;

	            //to sum up surrounding area
	            if(aboveEmpty == true)
	            {
	               	sum += gridArray[i+1][j];
	               	count++;

	               	if(rightEmpty == true)
	               	{
	                	sum += gridArray[i+1][j+1];
	                	count++;
	                }
	           	 
	                if(leftEmpty == true)
	                {
	                    sum += gridArray[i+1][j-1];
	                    count++;
	                }
	            }
	            	if(belowEmpty == true)
	            	{
	                	sum += gridArray[i-1][j];
	                	count++;

	                 if(rightEmpty == true)
	                 {
	                    sum += gridArray[i-1][j+1];
	                    count++;
	                 }

	                  if(leftEmpty == true)
	                  {
	                    sum += gridArray[i-1][j-1];
	                    count++;
	                  }
	            	}

	            	if(rightEmpty == true)
	            	{
	                	sum += gridArray[i][j+1];
	                	count++;
	            	}

	            	if(leftEmpty == true)
	            	{
	                	sum += gridArray[i][j-1];
	                	count++;
	            	}
        	}
    	}
	}
	double avg = sum / count;
	return avg;
}

char getLMH(double avg)
{
	if(avg >= 0 && avg < 35)
    	return 'L';
	else if (avg >= 35 && avg < 65)
    	return 'M';
	else
    	return 'H';
    
}

int getProbb(char ACC, char AP)
{
	if(AP == 'L' && ACC == 'H')
    	return 90;
	else if(AP == 'L' && ACC == 'M')
    	return 80;
	else if(AP == 'L' && ACC == 'L')
    	return 70;
	else if(AP == 'M' && ACC == 'H')
    	return 60;
	else if(AP == 'M' && ACC == 'M')
    	return 50;
	else if(AP == 'M' && ACC == 'L')
    	return 40;
	else if(AP == 'H' && ACC == 'H')
    	return 30;
	else if(AP == 'H' && ACC == 'M')
    	return 20;
	else if(AP == 'H' && ACC == 'L')
    	return 10;
	else
    	return 0;
}

void displayGraphics(int getProbb)
{
	int a = getProbb;
	if(a == 90)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl << "\\\\\\\\\\" << endl;
	}
	else if(a == 80)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl << " \\\\\\\\" << endl;
	}
	else if(a == 70)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl << "  \\\\\\" << endl;
	}
	else if(a == 60)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl << "   \\\\" << endl;
	}
	else if(a == 50)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl << "    \\" << endl;
	}
	else if(a == 40)
	{
    	cout << "~~~~" << endl << "~~~~~" << endl;
	}
	else if(a == 30)
	{
    	cout << "~~~" << endl << "~~~~" << endl;
	}
	else if(a == 20)
	{
    	cout << "~~" << endl << "~~~" << endl;
	}
	else if(a == 10)
	{
    	cout << "~" << endl << "~~" << endl;
	}
}

//function definition for option 7: display forecast summary report
void summaryReport(string** NameArray, int** IdArray, int** cloudArray, int** pressureArray, int cols, int rows)
{
	int a = 0;
    
	string* cityName = new string [4];
    
	for(int i=0; i < 4; i++)
    	cityName[i] = "";

	for(int i=0; i < rows; i++)
	{
    	for(int j=0; j < cols; j++)
    	{
        	if(NameArray[i][j] != "")
        	{
            	if(!haveName(cityName, NameArray[i][j], 4))
            	{
                	cityName[a] = NameArray[i][j];
                	double avgCC = calcAvg(NameArray, cloudArray, cols, rows, cityName[a]);
                	double avgP = calcAvg(NameArray, pressureArray, cols, rows, cityName[a]);

                	cout << "City Name  : " << cityName[a] << endl;
                	cout << "City ID    : " << IdArray[i][j] << endl;
                	cout << "Ave. Cloud Cover (ACC)     : " << fixed << setprecision(2) << avgCC << " (" << getLMH(avgCC) << ")" << endl;
                	cout << "Ave. Pressure    (AP)      : " << fixed << setprecision(2) << avgP << " (" << getLMH(avgP) << ")" << endl;
               	 
                	int probability = getProbb(getLMH(avgCC), getLMH(avgP));
               	 
                	cout << "Probability of Rain (%)    : " << fixed << setprecision(2) << probability << endl;
                	displayGraphics(probability);
                	a++;
                	cout << endl;
            	}
        	}
    	}
	}
	delete[] cityName;
	delete[] IdArray;
    delete[] NameArray;
}

void deallocateMemory(int** IdArray, string** NameArray, int** cloudArray, int** pressureArray, int cols, int rows)
{
	if(cols <= 0)
    	return;

	for(int i=0; i < rows; i++)
	{
    	delete[] IdArray[i];
    	delete[] NameArray[i];
    	delete[] cloudArray[i];
    	delete[] pressureArray[i];
	}

	delete[] IdArray;
	delete[] NameArray;
	delete[] cloudArray;
	delete[] pressureArray;
} 

C++ Online Compiler

Write, Run & Share C++ code online using OneCompiler's C++ online compiler for free. It's one of the robust, feature-rich online compilers for C++ language, running on the latest version 17. Getting started with the OneCompiler's C++ compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C++ and start coding!

Read inputs from stdin

OneCompiler's C++ online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.

#include <iostream>
#include <string>
using namespace std;

int main() 
{
    string name;
    cout << "Enter name:";
    getline (cin, name);
    cout << "Hello " << name;
    return 0;
}

About C++

C++ is a widely used middle-level programming language.

  • Supports different platforms like Windows, various Linux flavours, MacOS etc
  • C++ supports OOPS concepts like Inheritance, Polymorphism, Encapsulation and Abstraction.
  • Case-sensitive
  • C++ is a compiler based language
  • C++ supports structured programming language
  • C++ provides alot of inbuilt functions and also supports dynamic memory allocation.
  • Like C, C++ also allows you to play with memory using Pointers.

Syntax help

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition If-Else is used.

if(conditional-expression) {
   //code
}
else {
   //code
}

You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.

2. Switch:

Switch is an alternative to If-Else-If ladder.

switch(conditional-expression){    
case value1:    
 // code    
 break;  // optional  
case value2:    
 // code    
 break;  // optional  
......    
    
default:     
 code to be executed when all the above cases are not matched;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement){  
  //code  
} 

4. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while (condition) {  
// code 
}  

5. Do-While:

Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.

do {  
 // code 
} while (condition); 

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity. Function gets run only when it is called.

How to declare a Function:

return_type function_name(parameters);

How to call a Function:

function_name (parameters)

How to define a Function:

return_type function_name(parameters) {  
 // code
}