Issue with input in Tic Tac toe

Write your question here.
Whenever i'm trying to input a row or col number for player 1 or player 2,it always assign the value to row =2 and col=2 and after 3 iteration to another random row and col.

#include <iostream>
#include <string>
using namespace std;
string grid[3][3];
void generates(){
for(int i=0;i<3;i++){
for(int j =0;j<3;j++){
grid[i][j]=".";
}
}
}
void output(){
for(int i=0;i<3;i++){
for (int j=0;j<3;j++){
cout << grid[i][j] << " ";
}
cout << endl;
}
}
bool havewinner(){
for(int i=0;i<3;i++){
if(grid[i][1]=="X" && grid[i][2]=="X" && grid[i][3]=="X"){
cout <<"Winner is player 1";
return true;
}else if(grid[i][1]=="0"&& grid[i][2]=="0"&& grid[i][3]=="0"){
cout <<"Winner is player 2";
return true;
}else {return false;
}
}
for(int j=0;j<3;j++){
if (grid[1][j]=="X" && grid[2][j]=="X"&& grid[3][j]=="X"){
cout<<"Winner is player 1";
return true;
}else if(grid[1][j]=="0" && grid[2][j]=="0" && grid[3][j]=="0"){
cout<<"Winner is player 2";
return true;
}else {return false;
}
}
if(grid[1][1]=="X" && grid[2][2]=="X" && grid[3][3]=="X"){
cout << "Winner is player 1";
return true;
}else if(grid[1][1]=="0" && grid[2][2]=="0" && grid[3][3]=="0"){
cout << "Winner is player 2";
return true;
}else {return false;
}
}
void play(){
int row1=0,col1=0,row2=0,col2=0;
int total=0;
while(total !=9 || havewinner==false){
cout<< "Player 1 turn"<< endl;
cout << "Input row:";
cin>> row1;
cout <<"Input col:";
cin >> col1;
grid[row1][col1]="X";
total++;
output();
havewinner();
cout << "Player 2 turn"<< endl;
cout << "Input row:";
cin >>row2;
cout <<"Input col:";
cin>>col2;
grid[row2][col2]="0";
total++;
output();
havewinner();
}
}
int main(){
generates();
output();
play();
return 0;
}
if(grid[i][1]=="X" && grid[i][2]=="X" && grid[i][3]=="X")
Array indices start at 0, not 1.

havewinner==false
havewinner is a function, not a bool.
Last edited on
"Array indices start at 0, not 1."
Thank you so much i always forget this.


havewinner==false
"havewinner is a function, not a bool."
Don't the function havewinner gets assign to a boolean value during the code excution?
The function, when called, returns a bool.

The name of a function also acts as a pointer to that function. You don't need to know the details of this, just know that you need to use parenthesis to call a function.

e.g. like
1
2
3
while (total != 9 && !havewinner()) {
    ...
}

This is equivalent to:
1
2
3
while (total != 9 && havewinner() == false) {
    ...
}
Last edited on
I see so in other words I just have to put those parenthesis in order for it to become a function and return a boolean value?
Hello hayabusaruler,


PLEASE ALWAYS USE CODE TAGS (the <> formatting button), to the right of this box, when posting code.

Along with the proper indenting it makes it easier to read your code and also easier to respond to your post.

http://www.cplusplus.com/articles/jEywvCM9/
http://www.cplusplus.com/articles/z13hAqkS/

Hint: You can edit your post, highlight your code and press the <> formatting button, but you may still to indent your code.

You can use the preview button at the bottom to see how it looks.

I found the second link to be the most help.



As pointed out C++ is a zero based language. Maybe you could find a place to put a sticky note on the screen to remind you of this.

In your "play" function you have:
1
2
3
4
5
6
7
8
cout << "Player 1 turn" << endl;
cout << "Input row:";
cin >> row1;

cout << "Input col:";
cin >> col1;

grid[row1][col1] = "X";

Given the entry of 1 and 2 you are expecting:

. X .
. . .
. . .


But what you end up with is:

. . .
. . X
. . .



This is because you array is:

  0  1  2
0 .  .  .
1 .  .  .
2 .  .  .



To compensate for this what you need is grid[row1 - 1][col1 - 1] = "X";. Otherwise "row1" and "col1" could end up being outside the boundary of the array.

The same would be needed for player 2.

You also need some blank line in your code. As an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
void play()
{
	int row1 = 0, col1 = 0, row2 = 0, col2 = 0;
	int total = 0;

	while (total != 9 || havewinner == false)
	{
		cout << "Player 1 turn" << endl;
		cout << "Input row:";
		cin >> row1;

		cout << "Input col:";
		cin >> col1;

		grid[row1 - 1][col1 - 1] = "X";

		total++;

		output();

		havewinner();

		cout << "Player 2 turn" << endl;
		cout << "Input row:";
		cin >> row2;

		cout << "Input col:";
		cin >> col2;

		grid[row2][col2] = "0";

		total++;

		output();

		havewinner();  // <--- Returns a "bool", but you do not collect this or do anything with it.
                               // Also I do not see any need for it here because it is in the while condition.
	}
}

Think about it and decide which code is easier to read and work with.

Andy
Hello hayabusaruler,

I see so in other words I just have to put those parenthesis in order for it to become a function and return a boolean value?

To answer your question. Yes, but you do not want to use it there.

When you get the "havewinner" function fixed you will end up printing "Winner is player 1Winner is player 1" instead of just the once that you need.

The function "havewinner" is mostly correct other than you are accessing the array outside the boundary of the array. That is anytime you use a "3" in either row or col.

Andy
Hi Handy Andy,

Thanks for the small tips that you have given me.Do you advise me to fix the havewinner function?Or instead do an If statement that will check for a winner and will return a boolean to stop the loop,each time a player have input a row and col.Because I don't know how to fix the "Winner is player 1Winner is player 1" issue.
Last edited on
Hello Handy Andy,

Thank you so much for the tips you gave me.I just wanted to know one more thing,do you advise me to use an if statement that will check for a winner after a player has input a row and col and then set a bool variable to true to terminate the while loop or should I fix the havewinner function's issue "Winner is player 1Winner is player 1?"
Personally, I would suggest that your havewinner function be refactored a bit to not have any print statements within it.
It should only do the calculations to determine who, if anyone, has won.

e.g.
1
2
3
4
5
6
7
8
9
int havewinner()
{
    // ... iteration through board
    if ( /* player 1 conditions to win */ )
        return 1;
    if ( /* player 2 conditions to win */ )
        return 2;
    return 0;
}


Then in the calling side, you could have something like:
1
2
3
4
5
int winner = havewinner();
if (winner != 0)
{
    cout << "Player " << winner << " is the winner!\n";
}
Last edited on
Yeah that's what I ended up doing, apologies for the hassles I started learning this language by myself one week ago and I'm still learning its syntax.
Don't be sorry, it's a beginner forum.
Last edited on
Hello hayabusaruler,

There is no reason to rewrite the "havewinner" function just use it correctly.

As an example and using Ganado's suggestion:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int havewinner()
{
	for (int i = 0; i < 3; i++)
	{
		if (grid[i][0] == "X" && grid[i][1] == "X" && grid[i][2] == "X")
		{
			return 1;
		}

		else if (grid[i][0] == "0" && grid[i][1] == "0" && grid[i][2] == "0")
		{
			return 2;
		}
	}

        return 0;  // <--- At the end of the function when there is no winner. 

Remove the else statements. This way if nothing returns a 1 or 2 the last thing the function will so is return (0) zero to show there is no winner.

You have a 2D array of strings. Unusual, but it works. Here the for loop has the correct value for "i" to access the rows of the array, but accessing the individual elements of the string are off by one. The string elements are numbered 0, 1, 2 and when you get to the last check of "[i][3]" the (3) is ouside of or past the end of the string.

Then in "play" you would use:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
void play()
{
	bool winner{}, cont{ true };
	int row1 = 0, col1 = 0, row2 = 0, col2 = 0;
	//int total = 0;  // <--- No longer needed.

	while (cont)  // <--- Can not use "continue" because it is a key word.
	{
		cout << "Player 1 turn" << endl;
		cout << "Input row:";
		cin >> row1;  // <--- User types 1, 2 or 3.

		//row1--;  // <--- An alternative to subtracting (1) later.

		cout << "Input col:";
		cin >> col1;  // <--- User types 1, 2 or 3.

		grid[row1 - 1][col1 - 1] = "X";  // <--- Subtracts 1 from user input to access the correct element of the array.
	        //grid[row1][col1] = "X";  // <--- If you use line 13

		//total++;  // <--- No longer needed.

		output();

		//std::cout << "  " << total << '\n'; // <--- Used for testing. Comment or remove when finished.

		winner = havewinner();

		if (winner)  // <--- (0) means false and any number greater than (0) is considered true.
		{
			cout << "Winner is player " << winner << ".\n";

			cont = false;

			continue;  // <--- Jumps to the while condition. Bypasses every down to the closing } of the while loop.
		}

The same concept would have to be repeated for player 2.

The last if/else if in "havewinner" checks for a win from top left to bottom right. That is 1 of 2 diagonals. You need to copy that and reverse the check from top right to bottom left.

That should get you a working program. After that there are ways to improve and shorten the code, but first I would get it working the way that you want.

Before you have to ask in the bool winner{}, cont{ true };. The {}s are called the uniform initializer and are available from the 2011 standards on. Empty they set "char"s to "\0", the int types to (0) zero and "double"s to "0.0". As the "cont" shows you can put something inside the {}s to give it a value other than (0) zero.

Andy
Hello Andy Handy,
Woah thank you for this.
Topic archived. No new replies allowed.