Making PlayGame simpler / more abstract- help with logic (and style?)

Hi all

I would appreciate help with this issue, which I think is logical but perhaps also style related…

I am trying to make PlayGame cleaner / more abstract i.e. just contain function calls rather than text (I want to encapsulate that elsewhere).

So instead of having

void PlayGame() {
constexpr int TURNS_NUMBER{ 5 };
for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
string Guess = GetGuess();
cout << "Your guess was: " << Guess << endl;
cout << endl;
}
return;
}

I have

void PlayGame() {
constexpr int TURNS_NUMBER{ 5 };
for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
ReturnGuess();
}
return;
}

string GetGuess() {
cout << "Enter your guess: ";
string Guess{ “” };
getline(cin, Guess);
return Guess;
}

void ReturnGuess() {
string Guess = GetGuess();
cout << "Your guess was: " << Guess << endl;
cout << endl;
return;
}

My code variation in full is at the bottom of the post

My logical interpretation of the above code is:

PlayGame calls ReturnGuess.
ReturnGuess reads Guess from GetGuess and outputs it.
GetGuess gets the guess from the player.

I am somehow satisfied with the above since it works, however I feel it is not so explicit by just looking at PlayGame, because by reading its content the above logical steps are hidden.

I would like PlayGame to call both GetGuess and ReturnGuess, like so

void PlayGame() { // plays game
constexpr int TURNS_NUMBER{ 5 };
for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
GetGuess();
ReturnGuess();
}
return;
}

As to me this immediately tells me that PlayGame gets the guess, and then returns it, making the two actions explicit.

However if I write the code like that at runtime I get asked to input the guess twice. Why is it so, and is there a way to avoid this issue while making the two actionfs of PlayGame explicit?

my code in full

#include
#include
using namespace std;

void PrintIntro();
void PlayGame();
void ReturnGuess();
string GetGuess();

int main() {
PrintIntro(); // this is a function (method or routine) call
PlayGame();
return 0;
}

void PrintIntro() {
constexpr int WORLD_LENGHT{ 5 };
cout << “Welcome to Bulls & Cows\n”;
cout << “Can you guess the " << WORLD_LENGHT;
cout<<” letter word I am thinking of? It has no repeating letters…\n";
cout << endl;
return;
}

void PlayGame() {
constexpr int TURNS_NUMBER{ 5 };
for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
ReturnGuess();
}
return;
}

string GetGuess() {
cout << "Enter your guess: ";
string Guess{ “” };
getline(cin, Guess);
return Guess;
}

void ReturnGuess() {
string Guess = GetGuess();
cout << "Your guess was: " << Guess << endl;
cout << endl;
return;
}

You get asked to input the guess twice because:

  • First, PlayGame() calls GetGuess()
  • Then, PlayGame() calls ReturnGuess(), which in turn calls GetGuess() again

So, you need to remove the first line of code from ReturnGuess(), and instead pass the guess on to that function as a parameter. Try to do that yourself first, but if you need it, here is a possible solution:

void PlayGame() { // plays game
  constexpr int TURNS_NUMBER{ 5 };
  for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
    string Guess = GetGuess();
    ReturnGuess(Guess);
  }
  return;
}

string GetGuess() {
  cout << "Enter your guess: ";
  string Guess{ "" };
  getline(cin, Guess);
  return Guess;
}

void ReturnGuess(string Guess) {
  cout << "Your guess was: " << Guess << endl;
  cout << endl;
  return;
}

It is interesting how you you formatted the the string-variable “Guess” initialization… And after a little research, it turned out that three initialization formats are actually valid:

I - string Guess = "";
II - string Guess("");
III - string Guess{""};

Could I ask for the reason for putting (string guess) after specifying the ReturnGuess function in the section below:

void ReturnGuess(string Guess) {
cout << "Your guess was: " << Guess << endl;
cout << endl;
return;
}

Are we specifying that we’re pulling the value from the return line in the GetGuess function?

When I first got to the challenge of this section, I attempted to separate our earlier GetGuessAndPrintBack function into separate GetGuess and PrintBack functions, but simply moving the “PrintBack” section of code to its own function didn’t work. The error told me it didn’t have a value for Guess.

Is the resolution adding the (string Guess) as in your suggestion above?

I hope that all makes sense, thank you!

EDIT: Grammar

void ReturnGuess(string Guess) {
  cout << "Your guess was: " << Guess << endl;
  cout << endl;
  return;
}

The first line in the function definition above states that the ReturnGuess() function receives a string parameter, and that we are going to access that string inside the function using the name “Guess”. The function does not know about or influence anything that exists or happens outside it (except in global scope). We could very well write:

void ReturnGuess(string Blah) {
  cout << "Your guess was: " << Blah << endl;
  cout << endl;
  return;
}

The result would be the same. Note that, to call the function, we must supply the argument, so in PlayGame():

string Guess = GetGuess();
ReturnGuess(Guess);

The fact that we store the result of GetGuess() in a variable and pass that variable on to the ReturnGuess() function is what makes it work with the two separate functions. Again, the name of that variable can be anything, and does not need to match the name used inside ReturnGuess(), because each scope is independent of the other. So, we could very well write:

string HeyHo = GetGuess();
ReturnGuess(HeyHo);

On the other hand, it is important to give our variables nice descriptive names.

Yes, I am reading Stroustroup’s Programming Principles and Practices 2014 as accompaniment to this course and it introduces such things

1 Like

Thank you

I tried myself and arrived to passing Guess as argument, like so

void ReturnGuess(string Guess) {
cout << "Your guess was " << Guess << endl;
cout << endl;
return;
}

I then got an error as at the top I still had

void ReturnGuess();

Then I changed that to

void ReturnGuess(string Guess);

But then I got an error “too few arguments in function call” in my PlayGame function, which I left unchanged

void PlayGame() { // plays game
constexpr int TURNS_NUMBER{ 5 };
for (int i{ 1 }; i <= TURNS_NUMBER; i++) {
GetGuess();
ReturnGuess();
}
return;
}

I then tried a couple of things without success

If I modify ReturnGuess() to ReturnGuess(string Guess) I get other errors - “type name is not allowed”, "expected a ‘)’.

In my reasoning it should be possible for ReturnGuess to take the parameter Guess in the above, rather than having to define the string within the function. But probably I dont understand how this works exactly…

If I understand correctly PlayGame function simply states to call GetGuess and ReturnGuess while not defining any variable within the function.

Am I correct to assume that your change to

string Guess = GetGuess();
ReturnGuess(Guess);

is to define the parameter within PlayGame function, so that ReturnGuess is called using the returned Guess value from GetGuess?

But then again I don’t understand why I then have to have

void ReturnGuess(string Guess)

instead of just

void ReturnGuess()

if I already passed Guess as a parameter to ReturnGuess in my Playgame function?

Could you explain a bit more about the logic on how you arrive to that, because I could not think of it until I saw it…

I think you are having trouble understanding the concept of “scope”. I’ll try presenting some examples below. If it is not enough, or if it confuses you more than it helps, I suggest you try researching “c++ scope” a little bit.

When trying to follow the execution of the examples below, remember to start in main() and only examine func() when it is called. The comments are predicting the output of the programs with that in mind.

Ok. Imagine a program like this:

#include <iostream>

using namespace std;

void func()
{
  //a = 1;      // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  int a = 2;    // Declares a variable named 'a' in this scope and initializes it to 2
  cout << a;    // Prints '2'
  a = 3;        // Sets the value of the local variable 'a' to 3
  cout << a;    // Prints '3'
}

int main()
{
  //a = 4;      // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  //b = 5;      // Compilation error: the variable 'b' is not yet declared in this scope
  //cout << b;  // Compilation error: the variable 'b' is not yet declared in this scope
  int b = 6;    // Declares a variable named 'b' in this scope and initializes it to 6
  cout << b;    // Prints '6'
  func();       // Calls func1(), which will print '2' and '3'
  cout << b;    // Prints '6'
  cout << endl;
  return 0;
}

// Final output: '6236'

Note the variable ‘a’ exists only inside func(), from the point where it is declared, until the end of the scope in which the declaration was made, which is the function itself (the scope is delimited by curly braces). Similarly, the variable ‘b’ exists only inside main(), from the declaration until the end of the function.

Now suppose we rename our ‘b’ variable in main() to ‘a’:

#include <iostream>

using namespace std;

void func()
{
  //a = 1;      // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  int a = 2;    // Declares a variable named 'a' in this scope and initializes it to 2
  cout << a;    // Prints '2'
  a = 3;        // Sets the value of the local variable 'a' to 3
  cout << a;    // Prints '3'
}

int main()
{
  //a = 4;      // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  int a = 6;    // Declares a variable named 'a' in this scope and initializes it to 6
  cout << a;    // Prints '6'
  func();       // Calls func1(), which will print '2' and '3'
  cout << a;    // Prints '6'
  cout << endl;
  return 0;
}

// Final output: '6236'

Note that absolutely nothing changed. Each function is completely unaffected by variables that are declared in the scope of the other function, even if they have the same name. Their variables are in different scopes.

Ok, now let’s pass a parameter to func():

#include <iostream>

using namespace std;

void func(int c)
{
  //a = 1;      // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  cout << c;    // Prints '6' (c received the value that was passed as an argument)
  c = 2;
  cout << c;    // Prints '2'
  int a = 3;    // Declares a local variable named 'a' in this scope and initializes it to 3
  cout << a;    // Prints '3'
  a = 4;        // Sets the value of the local variable 'a' to 4
  cout << a;    // Prints '4'
}

int main()
{
  //cout << a;  // Compilation error: the variable 'a' is not yet declared in this scope
  //cout << c;  // Compilation error: the variable 'c' is not yet declared in this scope
  int a = 6;    // Declares a local variable named 'a' in this scope and initializes it to 6
  cout << a;    // Prints '6'
  func(a);      // Calls func() passing the value of 'a' as an argument
  cout << a;    // Prints '6'
  //cout << c;  // Compilation error: the variable 'c' is not yet declared in this scope
  cout << endl;
  return 0;
}

// Final output: '662346'

Again, note that the variable ‘a’ inside func() is not the same as the variable ‘a’ inside main() just because they have the same name. They are in different scopes. On the other hand, the value of ‘a’ is passed as an argument to func(). And func() puts that value into ‘c’, as per its declaration.

Hope this helps a bit.

Privacy & Terms