Thursday, 29 September 2016

Chapter 6 // Exercise 8 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


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


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 8

Redo the "Bulls & Cows" game from exercise 12 in Chapter 5 to use four letters rather than four digits.



#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

void getSeed();
void printRules();
void startGame();
void getLetters();
void compareLetters();
char assignLoop();
vector<char> fourLetters{ 0,0,0,0 };
vector<char> guess{ 0,0,0,0 };

int main()
try
{
char loop = 'y';

while (loop == 'y')
{
//get number for seed  & assign letters to fourLetters
getSeed();

//print rules of game
printRules();

//begin the game and keep going till user decides to quit
startGame();

//ask if you want to play again
loop = assignLoop();
}

keep_window_open();

return 0;
}


catch (exception& e)
{
cerr << "Error: " << e.what() << '\n';
keep_window_open();
return 1;
}

//produces random number which corralates to ASCII lower case alphabet
char getRandLetter()
{
char randNum = (rand()%(122 - 97 + 1)) + 97; // produces random number between 97 and 122
return randNum;
}

//get seed for rand num and assign letters to comp's four letters
void getSeed()
{
cout << "Please enter a number(any number):\n";
int n;
cin >> n;

srand(n);
for (int i = 0; i < fourLetters.size(); ++i)
{
fourLetters[i] = getRandLetter();
}

sort(fourLetters); //to compare if any are the same

for (int i = 1; i < fourLetters.size(); ++i)
{
while (fourLetters[i] == fourLetters[i - 1])
{
fourLetters[i] = getRandLetter();
}
}

}



void printRules()
{
cout << "//RULES//";
cout << "\nLets Play Bulls & Cows.\n";
cout << "Guess the 4 letters.\n";
cout << "If a letter is right in the right position you will get a bull.\n";
cout << "If the letter is right in the wrong position you will get a cow.\n";
cout << "\nGuess a letter a-z. Each letter must be different and lower case. \n\n";
}

void startGame()
{
while (guess != fourLetters)
{
//get user letters
getLetters();
//compare user and random letters for bulls & cows
compareLetters();
}
}

void getLetters()
{

vector<string>n = { "1st Letter: ", "2nd Letter: ", "3rd Letter: ", "4th Letter: " };

for (int i = 0; i < 4; ++i)
{
cout << n[i];
char letter;
cin >> letter;

if (letter < 'a' || letter > 'z')
error("You can only use lower case.\n");

guess[i] = letter;
}

cout << "Your guess: ";

for (int i = 0; i < 4; ++i)
{
cout << guess[i] << " ";
}

cout << '\n';
}

void compareLetters()
{
for (int i = 0; i < 4; ++i)
{
for (int n = 0; n < 4; ++n)
{
if (guess[i] == fourLetters[n])
{
if (i == n)
cout << "1 Bull(" << guess[i] << ")";
else
cout << "1 Cow(" << guess[i] << ")";
}
}
}
}

char assignLoop()
{
cout << "\n\nCongratz! You did it!\n";
cout << "Would you like to play again? y / n:\n";
char l;
cin >> l;
while (l != 'y' && l != 'n')
{
cout << "Invalid answer, try again. y / n:\n";
cin >> l;
}

return l;
}



This one took a while as I figured out how to perfect a few things. The original exercise had you guess a number 1 - 9, this one a letter a -z. Since int and char are interchangeable I simply changed most of the code to char however when it came to randomizing what letters you would get I had to find a new function.


The one I've got accepts a max and a min value, for us we want between 97 and 122 as these are the numbers for the characters a - z. I then just assigned one of the generated numbers to the guess vector. When looking to see if any of them were the same I realised my prior function wasn't exactly perfect and would sometimes allow the same numbers. I've corrected it on this one by sorting them first. This does give the letters some predictability by putting them in order however not all the time as if some are the same they will be changed to another generated number.



Tuesday, 27 September 2016

Chapter 6 // Exercise 7 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


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


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 7

Write a grammar for bitwise logical expressions.  A bitwise logical expression is much like an arithmetic expression except that the operators are ! (not), ~ (complement), & (and), | (or) and ^ (exclusive or).

Each operator does its operation to each bit of its integer operands. ! and ~ are prefix unary operators.

binds tighter than a | (just as * binds tighter than +) so that x|y^z means x|(y^z) rather than (x|y)^z. The & operator binds tighter than ^ so that x^y&z means x^(y&z).

Expression:
    Third Term
    Expression "|" Third Term

Third Term:
    Second Term
    Third Term "^" Second Term

Second Term:
    First Term
    Second Term "&" First Term

First Term:
    Primary
    First Term "!" Primary
    First Term "~" Primary

Primary:
    Object   //int, char, string etc
    "(" Expression ")"


Following the example earlier in chapter 6 I think this is how it would be done although I'm not entirely sure. English was always my best subject but grammar in programming is throwing my brain for a loop.

EDIT 07/10/2019 - This was almost correct the first time I did it. However, now I understand his thought process a little better on grammars I've realised that the First Term section is incorrect. "!" and "~" are always pre-fix operators and as such it will be sufficient for First term to look like this:
Primary
"!" Primary
"~" Primary
This way, they will always affect the Primary instead of the left value. Here is an updated version on GitHub.

Friday, 23 September 2016

Chapter 6 // Exercises 5, 6 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


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


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 5

Add the article the to the "English" grammar in 6.4.1, so that it can describe sentences such as "The birds fly but the fish swim."

I'm not sure quite what he wants us to do in this one. Make a program or just change the psuedocode? Either way the word 'the' is extremely complicated and has many different uses. It's doesn't always come before or after a verb, same with a noun and it's not a conjunction (something that joins sentences together). 

If he just wants us to change the psuedocode so it always comes before a noun (like he's put in his example) then it would be like this:


Sentence:
The Noun Verb
Sentence Conjuction Sentence

Conjuction:
and
or
but

Noun:
birds
fish
C++

The:
the

Verb:
rules
fly 
swim

I think this would also give you "The c++ rules", which is bad grammar because c++ doesn't denote something plural or a direct object (as opposed to saying 'the rules' where rules denotes the plural of rule) But I don't think we're creating Microsoft Word just yet, so I'm going to leave this one where it is.

Chapter 6 // Exercise 6


Write a program that checks if a sentence is correct according to the "English" grammar in 6.4.1. Assume that every sentence is terminated by a full stop (.) surrounded by white space. For example, birds fly but the fish swim .  is a sentence, but birds fly but the fish swim (terminating dot missing) and birds fly but the fish swim. (no space before dot) are not. For each sentence entered, the program should simply respond "OK" or "not OK". Hint: Don't bother with tokens; just read in a string using >>.

 I honestly didn't know what to make of this so here is his answer:

Chapter 6 exercise 6

Reading through it, it uses bools and I just can't wrap my head around them. It's just like minecraft with the not gates, I understand it flips it but I just don't get the whole 'true' 'false' thing.

Overall these two exercises were just



to me.

EDIT 07/10/2019 - I have now completed these two exercises found on GitHub here. This took me a while as I started getting pedantic about how to parse the sentence. I eventually went with a very hacky way of doing things as I was starting to run out of time. Eventually, I'll go back and refactor the code again to make it a little more …elegant shall we say. I started doing it how he has done it without realising it, but it doesn't allow for all the sentence types I don't think. I do like the idea of parsing the sentence into a wordtype vector as you can create verb/noun vectors and add more words to them and when deciding what they are, use a for loop to loop through each vector. Then creating a function which checks sentence structure shouldn't be too much hassle. I say shouldn't...

Wednesday, 21 September 2016

Chapter 6 // Exercise 4 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


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


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 4

Define a class Name_value that holds a string and a value. Rework exercise 19 in Chapter 4 to use a vector<Name_value> instead of two vectors.

#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

class Name_value
{
public:
string name;
int score;
};

vector<Name_value> n_s;

void getData()
{
cout << "Please enter a name, press enter, then input the score. To stop input enter 'NoName' in name and 0 in scores.\n";

Name_value data;  //variable that holds a string and int pair
char loop = 'y';

//get names and scores
while (loop == 'y')
{
cout << "Name: ";
cin >> data.name;
cout << "Score: ";
cin >> data.score;
for (int i = 0; i < n_s.size(); ++i)
{
while (n_s[i].name == data.name)
{
cout << "Sorry, that name has already been entered. Please Re-Name it: \n" << endl;
cin >> data.name;
}
}

if (data.name == "NoName" && data.score == 0)
{
loop = 'n';
}

n_s.push_back(data);  //pushes the string and int pair into the vector together
}

}

void printData()
{
cout << '\n';

//print them out
for (int x = 0; x < n_s.size() - 1; ++x)
{
cout << n_s[x].name << '\t' << n_s[x].score << '\n';
}

}

int main()
{

getData();

printData();

keep_window_open();

return 0;

}


This took some thought but didn't take me too long. The bit I tripped up on was pushing back the data into the class vector. Originally I had separate variables and was trying to push them in like this:
     n_s.name.push_back(inputname);
but obviously that wouldn't work because the compiler thought name was a function. Instead I realised I could just create a variable that held both and then push the entire variable into it's respective slots in the vector.

Monday, 19 September 2016

Chapter 6 // Exercise 3 - Principles & Practice Using C++

In all these exercises I am using Visual Studio Community 2015 and the header file "std_lib_facilities.h" which can be found here:


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


My version is spelt differently so adjust the code accordingly if copying and pasting.


Chapter 6 // Exercise 3

Add a factorial operator: use suffix ! operator to represent "factorial." For example, the expression 7! means 7*6*5*4*3*2*1. Make ! bind tighter than * and /; that is 7*8! means 7*(8!) rather than (7*8)!. begin by modifying the grammar to account for a higher-level operator. To agree with the standard mathematical definition of factorial, let 0! evaluate to 1.
Hint: The calculator functions deals with doubles, but factorial is defined only for ints, so just for x!, assign the x to an int and calculate the factorial of that int.

Sweet baby Jesus and the orphans. I read this and thought "what the hell is a factorial? Is he just making shit up now?". After some researching on factorials it's basically represented like this n(n-1). To start off I wrote a program that works out a factorial and got it working just so I understood what I was working with. Below is the program for documentation purposes:

#include "stdafx.h"
#include "std_lib_facilities_new_version.h"
using namespace std;

int getFactorial(int n)
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

int main()
{
cout << "Please enter a number to find the factorial:\n";
cout << "Press x to quit.\n";

while (cin)
{
int n;
cin >> n;

int f = getFactorial(n);

cout << n << "!" << " = " << f << endl;

cout << "Please enter a number to find the factorial:\n";
}

keep_window_open();

return 0;

}

The for loop in getFactorial() starts with i assigned -1 of whatever the number you input. So if n was 5, i will equal 4. Factorial is then assigned itself; multiplied by i. So for each iteration, i minuses 1 until it reaches 1 and multiplies with the previous answer.

So now we know how do do a factorial, it's just a matter of implementing it within the calculator program. First I added '!' to the case list in get():

Token Token_stream::get()
{
if (full)
{       // do we already have a Token ready?
// remove token from buffer
Token_stream::full = false;
return buffer;
}


char ch;
cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

switch (ch)
{
case '=':    // for "print"
case 'x':    // for "quit"


case '(': case ')': case '+': case '-': case '*': case '/':
case '{': case '}': case '!':
return Token(ch);        // let each character represent itself 
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':

{
cin.putback(ch);         // put digit back into the input stream
cin >> val;              // read a floating-point number
return Token('#', val);   // let '#' represent "a number"
}

default:
error("Bad token");
}

}

Then, I created a new function called int higherTerm() which is obviously higher than term. This is meant to illustrate to the computer that '!' binds tighter than '*' or '/'. This code is placed directly after primary().

int getFactorial(int n) //function that deals with factorials
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

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

//deal with !
int higherTerm()
{
double left = primary();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '!':
{
int ileft = left; //changing the double to an int, this will round down
left = getFactorial(ileft);
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}


}

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

// deal with *, /
double term()
{
double left = higherTerm();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '*':
{
left *= higherTerm();
t = ts.get();
break;
}

case '/':
{
double d = higherTerm();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}



So higherTerm() now gets the primary, the function checks to see if there is a '!' after the primary, if not, passes the number on down the food chain. term() now calls to higherTerm() so it gets whatever has been left over from there.

Here is the full program:


#include "stdafx.h"

#include "std_lib_facilities_new_version.h"
using namespace std;

double val; //global variable
//------------------------------------------------------------------------------

class Token {
public:
char kind;        // what kind of token
double value;     // for numbers: a value 
Token(char ch)    // make a Token from a char
:kind(ch), value(0) { }
Token(char ch, double val)     // make a Token from a char and a double
:kind(ch), value(val) { }
};

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

class Token_stream {
public:
Token_stream();   // make a Token_stream that reads from cin
Token get();      // get a Token (get() is defined elsewhere)
void putback(Token t);    // put a Token back
private:
bool full;        // is there a Token in the buffer?
Token buffer;     // here is where we keep a Token put back using putback()
};

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

// The constructor just sets full to indicate that the buffer is empty:
Token_stream::Token_stream()
:full(false), buffer(0)    // no Token in buffer
{
}

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

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
if (full) error("putback() into a full buffer");
buffer = t;       // copy t to buffer
full = true;      // buffer is now full
}

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

Token Token_stream::get()
{
if (full)
{       // do we already have a Token ready?
// remove token from buffer
Token_stream::full = false;
return buffer;
}


char ch;
cin >> ch;    // note that >> skips whitespace (space, newline, tab, etc.)

switch (ch)
{
case '=':    // for "print"
case 'x':    // for "quit"


case '(': case ')': case '+': case '-': case '*': case '/':
case '{': case '}': case '!':
return Token(ch);        // let each character represent itself 
case '.':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':

{
cin.putback(ch);         // put digit back into the input stream
cin >> val;              // read a floating-point number
return Token('#', val);   // let '#' represent "a number"
}

default:
error("Bad token");
}
}

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

Token_stream ts;        // provides get() and putback() 

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

double expression();    // declaration so that primary() can call expression()

int getFactorial(int n);

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

// deal with numbers and parentheses
double primary()
{
Token t = ts.get();

switch (t.kind)
{

case '{':     // handle '{' expression '}'
{
double d = expression();
t = ts.get();
if (t.kind != '}')
error("'}' expected");
return d;
break;
}

case '(':    // handle '(' expression ')'
{
double d = expression();
t = ts.get();
if (t.kind != ')') error("')' expected)");
return d;
break;
}

case '#':            // we use '#' to represent a number
{
return t.value;  // return the number's value
break;
}

default:
error("primary expected");
}
}

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

int getFactorial(int n) //function that deals with factorials
{
if (n == 0)
n = 1;

int factorial = n;

for (int i = n - 1; i > 1; --i)
{
factorial = factorial*i;
}

return factorial;
}

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

//deal with !
int higherTerm()
{
double left = primary();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '!':
{
int ileft = left; //changing the double to an int, this will round down
left = getFactorial(ileft);
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}



// deal with *, /
double term()
{
double left = higherTerm();
Token t = ts.get();        // get the next token from token stream

while (true)
{
switch (t.kind)
{
case '*':
{
left *= higherTerm();
t = ts.get();
break;
}

case '/':
{
double d = higherTerm();
if (d == 0) error("divide by zero");
left /= d;
t = ts.get();
break;
}

default:
ts.putback(t);     // put t back into the token stream

return left;
}
}
}

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

// deal with + and -
double expression()
{
double left = term();      // read and evaluate a Term
Token t = ts.get();        // get the next token from token stream

while (true) {
switch (t.kind) {
case '+':
left += term();    // evaluate Term and add
t = ts.get();
break;
case '-':
left -= term();    // evaluate Term and subtract
t = ts.get();
break;
default:
ts.putback(t);     // put t back into the token stream
return left;       // finally: no more + or -: return the answer
}
}
}

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

void printInstructions()
{
cout << "Welcome to our simple calculator!\n";
cout << "You can use + - / * and ! for factorial \n";
cout << "Press = to print the answer and x to exit.\n";
cout << "Please enter expressions using floating-point numbers:\n" << endl;
}

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

int main()
try
{
printInstructions();

val = 0;
while (cin)
{
Token t = ts.get();

while (t.kind == '=')
t = ts.get();

if (t.kind == 'x')
{
return 0;
}

ts.putback(t);
cout << expression() << '\n';
}
return 0;
}
catch (exception& e) {
cerr << "error: " << e.what() << '\n';
keep_window_open();
return 1;
}
catch (...) {
cerr << "Oops: unknown exception!\n";
keep_window_open();
return 2;
}

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