Sunday, 8 September 2019

Github Repository for Principles and Practice

I have decided to move away from posting code on blogger as it's just getting more and more annoying with the code plug-in to keep code organised and somewhat readable with multiple file formats (and half the time it doesn't work anyway). So I have decided to step into the modern world and start a Git repository for the code. Whilst doing this, I am re-starting the entire book. When I started it 3 years ago, I had never programmed anything in my life and my comments on the blog posts on here are quite amusing to me now. 

I will try my best to only stick to using concepts introduced in each chapter (it's harder than I thought to not use other things; I kind of understand the users on Stack overflow now who tell you to just "use a map").

You can find the exercises and drills here:

Friday, 6 September 2019

Chapter 10 // Exercise 2 - Principles & Practice Using C++

Chapter 10 // Exercise 2

Write a program that creates a file of data in the form of the temperature Reading type defined in section 10.5. For testing, fill the file with at least 50 "temperature readings". Call this program store_temps.cpp and the file it creates raw_temps.txt.

Main.cpp

//--------------------------------------------//
//main.cpp
//--------------------------------------------//
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <conio.h>
using namespace std;
struct Reading
{
 int hour;
 double temperature;
};
int main()
{
 vector<Reading> temps;
 int hour;
 double temperature;
 cout << "Please enter temperatures in format HOUR TEMP. Example: 1 32.65    Press Ctrl+Z to stop.\n";
 while (cin >> hour >> temperature)
 {
  if (hour < 0 || hour > 23)
   cout << "Error. Hour out of range.\n" << endl;
  temps.push_back(Reading{ hour, temperature });
 }
 ofstream readOut{ "raw_temps.txt" };
 for (uint32_t i = 0; i < temps.size(); ++i)
  readOut << temps[i].hour << " " << temps[i].temperature << "\n";
 cout << "\nPress any key..."; _getch();
 return 0;
}




EDIT: 13/01/2020
New version on GitHub. This one has more error checking and actually parses the weird format instead of changing it. https://github.com/l-paz91/principles-practice/blob/master/Chapter%2010/Exercise%202

Thursday, 5 September 2019

Chapter 10 // Exercise 1 - Principles & Practice Using C++

Chapter 10 // Exercise 1

Write a program that produces the sum of all the numbers in a file of whitespace-separated integers.

Main.cpp
//--------------------------------------------//
//main.cpp
//--------------------------------------------//
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <conio.h>
using namespace std;
//create a file with white-space separated integers
void createFile()
{
 ofstream readOut{ "integers.txt" };
 if (!readOut)
  cout << "Error opening file" << endl;
 string integers;
 cout << "Enter a list of whitespace separated integers: (press enter when done)\n>>";
 getline(cin, integers);
 readOut << integers;
}
//read in from a file
vector<int> readInIntegersFromFile()
{
 vector<int> integers;
 ifstream readIn{ "integers.txt" };
 if(!readIn)
  cout << "Error opening file" << endl;
 int temp;
 while (!readIn.eof())
 {
  readIn >> temp;
  integers.push_back(temp);
 }
 return integers;
}
//add numbers together
int sumOfIntegers(vector<int>& v)
{
 int sum = 0;
 for (uint32_t i = 0; i < v.size(); ++i)
  sum += v[i];
 return sum;
}
int main()
{
 createFile();
 vector<int> integers = readInIntegersFromFile();
 int sum = sumOfIntegers(integers);
 cout << "Sum: " << sum << endl;
 cout << "\nPress any key..."; _getch();
 return 0;
}




EDIT: 13/01/2020

Tuesday, 3 September 2019

Chapter 10 // Drill 1, 2, 3, 4, 5, 6, 7 - Principles & Practice Using C++

Drill 1:
Start a program to work with points, discussed in section 10.4. Begin by defining the data type Point that has two coordinate members x and y.

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

struct Point
{
 double x, y;
};

int main()
{
 getchar();
 return 0;
}





Drill 2:
Using the code and discussion in section 10.4, prompt the user to input seven (,y) pairs. As the data is entered, store it in a vector of Points called original_points.

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

struct Point
{
 Point(double xcoor, double ycoor)
  : x(xcoor), y(ycoor) {}
 double x, y;
};

vector<Point> original_points;

int main()
{
 double x, y;
 cout << "Please enter 7 points (x,y) :" << endl;
 for (int i = 0; i < 7; ++i)
 {
  cout << "X: "; cin >> x;
  cout << "Y: "; cin >> y;
  original_points.emplace_back(x, y);
 }
 getchar();
 return 0;
}


Drill 3: 
Print the data in original_points to see what it looks like.
#include <iostream>
#include <vector>
#include <conio.h>
using namespace std;

struct Point
{
 Point(double xcoor, double ycoor)
  : x(xcoor), y(ycoor) {}
 double x, y;
};

ostream& operator<<(ostream& os, const vector<Point>& p)
{
 for (uint32_t i = 0; i < p.size(); ++i)
  os << "X: " << p[i].x << " | Y: " << p[i].y << endl;
 return os;
}

vector<Point> original_points;

int main()
{
 double x, y;

 cout << "Please enter 7 points (x,y) :" << endl;

 for (uint32_t i = 0; i < 7; ++i)
 {
  cout << "X: "; cin >> x;
  cout << "Y: "; cin >> y;
  original_points.emplace_back(x, y);
 }

 cout << original_points;

 _getch();
 return 0;
}

Drill 4:
Open an ofstream and output each point to a file named mydata.txt. On Windows, we suggest the .txt suffix to make it easier to look at the data with an ordinary text editor (such as WordPad)
#include <iostream>
#include <fstream>
#include <vector>
#include <conio.h>
using namespace std;

struct Point
{
 Point(double xcoor, double ycoor)
  : x(xcoor), y(ycoor) {}
 double x, y;
};

ostream& operator<<(ostream& os, const vector<Point>& p)
{
 for (uint32_t i = 0; i < p.size(); ++i)
  os << "X: " << p[i].x << " | Y: " << p[i].y << endl;
 return os;
}

vector<Point> original_points;
ofstream outFile{ "points.txt" };

int main()
{
 double x, y;

 cout << "Please enter 7 points (x,y) :" << endl;

 for (uint32_t i = 0; i < 7; ++i)
 {
  cout << "X: "; cin >> x;
  cout << "Y: "; cin >> y;
  original_points.emplace_back(x, y);
 }

 cout << original_points;
 outFile << original_points;

 _getch();
 return 0;
}

Drill 5:
Close the ofstream and then open an ifstream for mydata.txt. Read the data from mydata.txt and store it in a new vector called processed_points. 
//--------------------------------------------//
//main.cpp
//--------------------------------------------//

#include <iostream>
#include <fstream>
#include <vector>
#include <conio.h>
using namespace std;

// -----------------------------------------------------------------------------
struct Point
{
 Point(double xcoor, double ycoor)
  : x(xcoor), y(ycoor) {}
 double x, y;
};
// -----------------------------------------------------------------------------
//---VARIABLES---//
vector<Point> original_points, processed_points;
string filename = "mydata.txt";
ofstream outFile{ filename };
ifstream inFile{ filename };
// -----------------------------------------------------------------------------
//read in to a file
ostream& operator<<(ostream& os, const vector<Point>& p)
{
 for (uint32_t i = 0; i < p.size(); ++i)
  os << p[i].x << '\n' << p[i].y << endl;
 return os;
}
// -----------------------------------------------------------------------------
//read out from a file
ifstream& operator>>(ifstream& is, vector<Point>& p)
{
 double x, y;
 for (uint32_t i = 0; i < original_points.size(); ++i)
 {
  is >> x >> y;
  p.emplace_back(x, y);
 }
 return is;
}
// -----------------------------------------------------------------------------
//print out a vector of points
void printPointVector(const vector<Point>& p)
{
 for (uint32_t i = 0; i < p.size(); ++i)
  cout << "X: " << p[i].x << " | Y: " << p[i].y << endl;
 return;
}
// -----------------------------------------------------------------------------
int main()
{
 double x, y;
 cout << "Please enter 7 points (x,y) :" << endl;

 for (uint32_t i = 0; i < 7; ++i)
 {
  cout << "X: "; cin >> x;
  cout << "Y: "; cin >> y;
  original_points.emplace_back(x, y);
 }

 printPointVector(original_points);
 outFile << original_points;
 inFile >> processed_points;
 printPointVector(processed_points);

 cout << "\nPress any key..."; _getch();
 return 0;
}

OK so the problem I had here was that I was sending a whole bunch a characters to the outFile for formatting so it looked nice and readable. So, instead I created a new function for reading out to files and for printing those files. That way we can have nice pretty text on the screen but it's easy to read in and out of files. It's not great, however it beats parsing the file to ignore all the random characters. I did consider doing the parsing but thought to myself "is there a point, when the computer reads it in and outputs it all nice for you?" Isn't that the point of reading in from files? No one opens a jpg in notepad and goes "I wish this was more readable", so ultimately I decided to just leave things simplified.
Drill 6:
Print the data elements from both vectors. (NOT DONE)
This has been done in the previous exercise.
Drill 7:
Compare the two vectors and print Something's wrong! if the number of elements or the values of elements differ.

// -----------------------------------------------------------------------------
//compare the two vectors (added after ifstream& operator>>)

bool operator==(const vector<Point>& p1, const vector<Point>& p2)
{
 if (p1.size() != p2.size())
  return false;
 else
 {
  for (uint32_t i = 0; i < p1.size(); ++i)
  {
   if (p1[i].x != p2[i].x
    && p1[i].y != p2[i].y)
    return false;
  }
  return true;
 }
}


// -----------------------------------------------------------------------------

int main()
{
 double x, y;
 cout << "Please enter 7 points (x,y) :" << endl;

 for (uint32_t i = 0; i < 7; ++i)
 {
  cout << "X: "; cin >> x;
  cout << "Y: "; cin >> y;
  original_points.emplace_back(x, y);
 }

 printPointVector(original_points);
 outFile << original_points;
 inFile >> processed_points;
 printPointVector(processed_points);

 if (!(original_points == processed_points))
  cout << "Something's wrong!\n";

 cout << "\nPress any key..."; _getch();
 return 0;
}



Thursday, 22 August 2019

Chapter 9 // Exercise 16 - Principles & Practice Using C++

In this exercise I am using Visual Studio Community 2017 and the header file "std_lib_facilities.h" which can be found here:

http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h


Chapter 9 // Exercise 16



Define an input operator (>>) that reads monetary amounts with currency denominations, such as USD1.23 and DKK5.00, into a Money variable. Also define a corresponding output operator.

main.cpp

//----------------------------------//
// main.cpp
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

int main()
{
 Money amount1(c_GBP, 3.34);
 amount1.printMoney();

 Money amount2(c_USD, 786.789);
 amount1.printMoney();

 //read in new money
 cin >> amount1;
 cin >> amount2;

 //print new amounts
 cout << amount1 << endl;
 cout << amount2 << endl;

 cout << "\nPress any key to quit...";
 _getch();

 return 0;
}

moneyClass.h

//----------------------------------//
// moneyClass.h
//----------------------------------//
// for calculations involving money
//----------------------------------//
#ifndef _MONEYCLASS_H_
#define _MONEYCLASS_H_

//INCLUDES//
#include <string>
#include <iostream>
#include <iomanip>
#include <conio.h>

using namespace std;

//----------------------------------//
// ENUM: Currencies
//----------------------------------//
enum Currencies
{
 c_GBP,
 c_USD
};

//----------------------------------//
// CLASS: Money
//----------------------------------//
class Money
{
public:
 Money();
 Money(Currencies currency, float amount);
 ~Money();

 void printMoney();

 Currencies getCurrency() { return m_currency; }
 void changeCurrency(Currencies currency) { m_currency = currency; }
 long int   getOutPutMoney() { return m_outputMoney; }
 double     getInputMoney()  { return m_inputMoney; }

private:
 //variables//
 Currencies m_currency;
 long int m_outputMoney; //cents
 double m_inputMoney; //dollars

};

//OPERATOR OVERLOADS//
void operator+(Money& money1, Money& money2);
ostream& operator<<(ostream& os, Money& money);
istream& operator>>(istream& is, Money& money);

#endif // !_MONEYCLASS_H_


moneyClass.cpp

//----------------------------------//
// moneyClass.cpp
//----------------------------------//
// for calculations involving money
//----------------------------------//

//INCLUDES//
#include "moneyClass.h"

//VARIABLES//
double gbp2usd = 1.26;
double usd2gbp = 0.79;


Money::Money() {}

Money::Money(Currencies currency, float amount) 
{
 m_currency = currency;
 m_inputMoney = amount;
}

Money::~Money() {}

//print output as dollars
void Money::printMoney()
{
 m_outputMoney = round(m_inputMoney * 100.0f);

 switch (m_currency)
 {
 case c_USD:
  cout << "-----USD----" << endl;
  cout << "Dollars: $" << fixed << setprecision(2) << m_inputMoney << endl;
  cout << "Cents: " << fixed << setprecision(0) << m_outputMoney << endl;
  break;
 case c_GBP:
  cout << "-----GBP----" << endl;
  cout << "Pounds: £" << fixed << setprecision(2) << m_inputMoney << endl;
  cout << "Pennies: " << fixed << setprecision(0) << m_outputMoney << "p" << endl;
  break;
 default:
  cout << "Bad output";
  break;
 }
}

//OPERATOR OVERLOADS//

//add currencies together - converts money if not the same
void operator+(Money& money1, Money& money2)
{
 cout << "\n";
 if (money1.getCurrency() == money2.getCurrency())
  //currencies are the same, no conversion needed, just add
  cout << fixed << setprecision(2) << money1.getInputMoney() + money2.getInputMoney();
 else if (money1.getCurrency() == c_GBP && money2.getCurrency() == c_USD)
 {
  //return pounds
  cout << fixed << setprecision(2) << "£" << (money2.getInputMoney() * usd2gbp) + money1.getInputMoney() << endl;
 }
 else if (money1.getCurrency() == c_USD && money2.getCurrency() == c_GBP)
 {
  //return dollars
  cout << fixed << setprecision(2) << "$" << (money2.getInputMoney() * gbp2usd) + money1.getInputMoney() << endl;
 }
}

//print out money
ostream& operator<<(ostream& os, Money& money)
{
 switch (money.getCurrency())
 {
 case c_GBP:
  return os << fixed << setprecision(2) << "\n£" << money.getInputMoney() << endl;
  break;
 case c_USD:
  return os << fixed << setprecision(2) << "\n$" << money.getInputMoney() << endl;
  break;
 default:
  return os << "Bad output";
  break;
 }
}

//read money into a Money variable
istream& operator>>(istream& is, Money& money)
{
 cout << "Please enter currency, followed by amount. For example GBP3.45" << endl;
 cout << "Currencies available: GBP || USD" << endl;

 string getMoney;
 cin >> getMoney;

 string denomination, amount;
 double mon;

 for (int i = 0; i < getMoney.size(); ++i)
 {
  if (i < 3)
   denomination += getMoney[i];
  else
   amount += getMoney[i];
 }

 //convert string to double
 mon = stod(amount);

 //update money variable
 if (denomination == "GBP")
 {
  money = Money(c_GBP, mon);
  money.changeCurrency(c_GBP);
 }
 else if (denomination == "USD")
 {
  money = Money(c_USD, mon);
  money.changeCurrency(c_USD);
 }
 else
 {
  cout << "bad input.";
 }

 return is;
}

My example is omitting some error checking due to time constraints so don't put in any illegal values otherwise it'll break however it does what he has asked for. When using cin >> with a Money variable it allows the user to input a new monetary value as well as change the currency. The << was already implemented in the last exercise. I also learnt in this exercise that there is a whole load of functions in the standard library for converting strings to almost any type of decimal. Bless the standard library.