3

I am new to coding and I started with C++ in Codeacademy. This is a very basic doubt, so TIA for helping me out.

The point of the program is to build a TIC TAC TOC game. I was looking to understand the solution that is available. That's where I came across one of the functions in the program, called void set_position() which is to determine which position in the board (from 1 to 9) the player wants to play at. I will paste the entire code block below for context and then come to my query.

void set_position() {

  std::cout << "Player " << player << "'s Turn (Enter 1-9): ";
  while (!(std::cin>>position)) {

    std::cout << "Player " << player << ", please enter a valid number between 1 and 9: ";
    std::cin.clear();
    std::cin.ignore();

  }

My question is, how is the while(!(std::cin>>position)) ensuring that the number being entered is between 1 to 9?

Edited to add:

position is a user defined variable initialized to 0 in the beginning of the program. I did not find position being forced to take values between 1 and 9 at any point in the program. It is entirely possible I missed it, I will add the entire code below if that provides more clarity, the reason I did not do so initially was because this is a solution and I wasn't sure if I could paste it in public forums

#include <iostream>
#include "play.hpp"

std::string board[9] = {" ", " ", " ", " ", " ", " ", " ", " ", " "};
int player = 1;
int position = 0;

void introduction() {

  std::cout << "Press [Enter] to begin: ";
  std::cin.ignore();

  std::cout << "\n";

  std::cout << "===========\n";
  std::cout << "Tic-Tac-Toe\n";
  std::cout << "===========\n\n";
  
  std::cout << "Player 1) ✖\n";
  std::cout << "Player 2) ⊙\n\n";

  std::cout << "Here's the 3 x 3 grid:\n\n";

  std::cout << "     |     |      \n";
  std::cout << "  1  |  2  |  3   \n";
  std::cout << "_____|_____|_____ \n";
  std::cout << "     |     |      \n";
  std::cout << "  4  |  5  |  6   \n";
  std::cout << "_____|_____|_____ \n";
  std::cout << "     |     |      \n";
  std::cout << "  7  |  8  |  9   \n";
  std::cout << "     |     |      \n\n";

}

bool is_winner() {

  bool winner = false;
  // rows
  if ((board[0] == board[1]) && (board[1] == board[2]) && board[0] != " ") {
    winner = true;
  } else if ((board[3] == board[4]) && (board[3] == board[5]) && board[3] != " ") {
    winner = true;
  } else if ((board[6] == board[7]) && (board[6] == board[8]) && board[6] != " ") {
    winner = true;
  } 
  // columns
  else if ((board[0] == board[3]) && (board[0] == board[6]) && board[0] != " ") {
    winner = true;
  } else if ((board[1] == board[4]) && (board[1] == board[7]) && board[1] != " ") {
    winner = true;
  } else if ((board[2] == board[5]) && (board[2] == board[8]) && board[2] != " ") {
    winner = true;
  } // diagonals
  else if ((board[0] == board[4]) && (board[0] == board[8]) && board[0] != " ") {
    winner = true;
  }
  else if ((board[2] == board[4]) && (board[2] == board[6]) && board[2] != " ") {
    winner = true;
  }

  return winner;

}

bool filled_up() {

  bool filled = true;

  for (int i = 0; i < 9; i++) {

    if (board[i] == " ") {

      filled = false;

    }

  }

  return filled;

}
void draw() {

  std::cout << "     |     |      \n";

  std::cout << "  " << board[0] << "  |  " << board[1] << "  |  " << board[2] << "\n";

  std::cout << "_____|_____|_____ \n";
  std::cout << "     |     |      \n";

  std::cout << "  " << board[3] << "  |  " << board[4] << "  |  " << board[5] << "\n";

  std::cout << "_____|_____|_____ \n";
  std::cout << "     |     |      \n";

  std::cout << "  " << board[6] << "  |  " << board[7] << "  |  " << board[8] << "\n";
  std::cout << "     |     |      \n";

  std::cout << "\n";
    
}

void set_position() {

  std::cout << "Player " << player << "'s Turn (Enter 1-9): ";
  
  while(!(std::cin>>position)) {

    std::cout << "Player " << player << ", please enter a valid number between 1 and 9: ";
    std::cin.clear();
    std::cin.ignore();

  }
  
  std::cout << "\n";

  while (board[position-1] != " ") {

    std::cout << "Oops, there's already something in that position!\n\n";

    std::cout << "Player " << player << "'s Turn (Enter 1-9): ";
    std::cin >> position;

    std::cout << "\n";
  }

}

void update_board() {

  if (player % 2 == 1) {

    board[position-1] = "✖";

  } else {

    board[position-1] = "⊙";

  }

}

void change_player() {

  if (player == 1) {

    player++;

  } else {
  
    player--;
  
  }

}

void take_turn() {

  while ( !is_winner() && !filled_up() ) {
  
    set_position();

    update_board();

    change_player();

    draw();
  
  }

}

void end_game() {

  if (is_winner()) {
    std::cout << "There's a winner!\n";
  }
  else if (filled_up()) {
    std::cout << "There's a tie!\n";
  }

}

  • 2
    Have you run the program to see if that's actually what it does? Please make a [mre] – cigien Oct 02 '20 at 23:12
  • Yes, I did run the program and this seems to be the function of the code. Also, from a broader context while reading the program - I understood that this is why they are using it. I am just not able to figure out how. – SrirakshaVR Oct 02 '20 at 23:18
  • 2
    Then you'll need to show the relevant code. e.g. the definition of `position`. See the link in the first comment. – cigien Oct 02 '20 at 23:19
  • This is much better, but it would be nice to have the main that calls this code. Also, you could remove a lot of code, and still reproduce the behavior. – cigien Oct 02 '20 at 23:43
  • 1
    @SrirakshaVR Closely related: https://stackoverflow.com/questions/24504582/how-to-test-whether-stringstream-operator-has-parsed-a-bad-type-and-skip-it As it was mentioned you can't restrict `std::cin` inputs beforehand to a specific range of numbers, you'll need to check after the input was entered from the console prompt. – πάντα ῥεῖ Oct 02 '20 at 23:46
  • Based on what you have posted, I don't see how it could limit the input to 1-9. Have you tested other numbers? Not just 10, but other arbitrary numbers? Remember that attempting to access members outside of the arrays bound is undefined behavior, which means it might or might not give you error or do anything. – Ranoiaetep Oct 03 '20 at 03:06

3 Answers3

1

It seems like position only allows numbers from 1 to 9, but this is not clear in your code. If it is this way, std::cin>>position reads the user's input and writes it into position if possible. If it is not possible, this operation evaluates to a false value. As it is negated by ! the loop does repeat the input until there is a valid input given. This pattern is quite common in C++.

andrbrue
  • 721
  • 6
  • 15
  • 1
    What do you mean by "Could it be the case that position uses an enum to force the interval from 1 to 9 being used?"? The only way the code does what the op claims is if `position` is a custom type and there's an istream overload for `>>` that takes that custom type as a param. – George Oct 02 '20 at 23:21
  • Yes, that would be my guess based on the provided snippet. Surprising for an introductory course though. – jtbandes Oct 02 '20 at 23:21
  • I thought as much too, but when I went through the code, I could not find any point where it was established that `position` was to be used in this way. Position is initialized as 0 in the beginning of the game and then the re-initialization only happens at this point. – SrirakshaVR Oct 02 '20 at 23:22
  • Then the program does not check the number is between 0 and 9, it merely checks that it is a number. Otherwise you'll have to edit your question to post more of the code so others can reproduce the problem. – jtbandes Oct 02 '20 at 23:28
  • I posted the solution code in its entirety @jtbandes – SrirakshaVR Oct 02 '20 at 23:45
  • @SrirakshaVR But we need to see play.hpp and the main function as well. – cigien Oct 03 '20 at 03:36
1

My question is, how is the while(!(std::cin>>position)) ensuring that the number being entered is between 1 to 9?

It doesn't. It merely checks if the user entered a valid integer. Any additional checks must be done manually.

Paul Sanders
  • 24,133
  • 4
  • 26
  • 48
  • There are no other manual checks to ensure the number is between one and nine, however when I tried to test the program out by entering values greater than 9, or lesser than 1, I was asked to enter different values [`Player 1 please enter a value between 1 and 9` -- as present in the code] – SrirakshaVR Oct 02 '20 at 23:27
  • The code shown isn't doing that. It must be somewhere else, please include it in your question. – Paul Sanders Oct 02 '20 at 23:34
1

It does not ensure. I made this small program though which will guarantee it to be between 1 and 9

#include <iostream>

int main() {
    int player = 0;                                             //force integer
    while ((std::cin >> player) && (player < 1 || player > 9) || std::cin.fail()) {
        std::cout << "Player " << player << ", please enter a valid number between 1 and 9: ";
        std::cin.clear();
        std::cin.ignore();
    }
    return 0;
}
pesuww
  • 105
  • 11
  • That logic would count `z` as a valid number between 1-9 for example. Also doesn't really answer the op's question (granted their question is incomplete). – George Oct 02 '20 at 23:28
  • Yes, this makes sense. But there is no sure clarification in the program, and it still runs like it is supposed it. `position` was initialized to 0 in the beginning of the code, apart from which it is not set any value until this point in the code. – SrirakshaVR Oct 02 '20 at 23:29
  • It doesn't have to be initialized, since std::cin will initialize the value. – pesuww Oct 02 '20 at 23:33