Beginner Tic Tac Toe Efficiency

I started learning C++ two days ago by watching beginner video tutorials on YouTube. Since the best way to learn in programming is to just practice, I decided to make a game of Tic Tac Toe to test my new skills. This is what I have so far (The endgame has not been fully implemented yet):
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <iostream>
#include <cstdlib>
using namespace std;

//Globals
string theboard[9] = {"-", "-", "-", "-", "-", "-", "-", "-", "-"};
int showboard();
int movecheck();
int move;
int turn = 0;
bool gameover();
bool over = false;

//Main
int main()
{

	cout << "Two player Tic Tac Toe!" << endl;
	
	showboard();
	cout << endl << "First Player (x), where would you like to move (number on grid below corresponds to board spot)?" << endl;
	cout << "0 1 2" << endl << "3 4 5" << endl << "6 7 8" << endl << endl << "Choice: ";
	cin >> move;
	movecheck();
	showboard();
	cout << "Second Player (o), where would you like to move?" << endl << "Choice: ";
	cin >> move;
	movecheck();
	showboard();
	while(over == false)
	{
		cout << "First player: ";
		cin >> move;
		movecheck();
		showboard();
		gameover();
		

		cout << "Second player: ";
		cin >> move;
		movecheck();
		showboard();
		gameover();

	}
	

	system("PAUSE");
	return 0;
}

//Functions

//Show the Board
int showboard()
{
cout << endl << theboard[0] << " " << theboard[1] << " " << theboard[2] << endl << theboard[3] << " " << theboard[4] << " " << theboard[5] << endl << theboard[6] << " " << theboard[7] << " " << theboard[8] << endl;
return 0;
}

//Check if move is valid
int movecheck()
{
	turn = turn + 1;
	if(theboard[move] != "-")
	{
		cout << "Someone already went there, try again!" << endl;
		
	}
	else
	{
		if(turn % 2 == 0)
		{
			theboard[move] = "o";
		}
		else
		{
			theboard[move] = "x";
		}
		
	}
	return 0;
}

//Check whether game is over
bool gameover()
{
	if(turn % 2 == 0)
	{
		if((theboard[0]=="x" && theboard[1]=="x" && theboard[2]=="x"))
		{
			cout << endl << endl << "Player 1 (x) wins!" << endl;
			over = true;
		}
		else 
		{
			over = false;
		}
		
	}
	else
	{
		if((theboard[0]=="o" && theboard[1]=="o" && theboard[2]=="o"))
		{
			cout << endl << endl << "Player 2 (o) wins!" << endl;
			over = true;
		}
		else 
		{
			over = false;
		}
	}
	 
}


First of all, I've heard that strings are not defaultly in the language, and need to be included with another #include. However, everything seems to work just fine without that, so I let it be. Second of all, I only made one case of winning the game (the top three spaces occupied by either "x" or "o"). Upon player 1 (x) meeting this case, the while loop still runs through and lets player 2 take his turn. How can I make the while loop stop as soon as the condition (over == true) is met? Also, what is the most efficient way (with what I have so far) to implement the other 7 (or 14 if you say x and o as different cases) cases of winning, plus the draw case? My only other code background is about 7 months of vb.net classes in high school, and basic knowledge. Thank you in advance, and feel free to teach me new concepts in your answers that will help me later!
First of all, I've heard that strings are not defaultly in the language, and need to be included with another #include. However, everything seems to work just fine without that, so I let it be.


You heard correct. You need to #include <string> . You should be doing that. It's kind of a fluke that your program is working (the <iostream> header is probably including <string> for you), but you should not rely on that as it is not always the case.

If you are using strings, then #include <string>. It doesn't hurt to do it, and may help.

Second of all, I only made one case of winning the game (the top three spaces occupied by either "x" or "o"). Upon player 1 (x) meeting this case, the while loop still runs through and lets player 2 take his turn. How can I make the while loop stop as soon as the condition (over == true) is met?


As a [very] general rule... if you find yourself copy pasting code (or typing the same code twice), you're probably doing something wrong. That of course is not always true, but it's a good idea to keep that in mind. If you find yourself doing that... stop and think about a better way to approach the problem.

For example... take a look at this section of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	while(over == false)
	{
		cout << "First player: ";
		cin >> move;
		movecheck();
		showboard();
		gameover();
		
		cout << "Second player: ";
		cin >> move;
		movecheck();
		showboard();
		gameover();
	}


You are doing the same thing twice. Once for player 1, then you have the code copy/pasted to do player 2. The only difference is the text you print.

It'd be better to condense all of this:

1
2
3
4
5
6
7
8
9
10
	while(over == false)
	{
		if( /* it's player 1's turn */)   cout << "First player: ";
		else                              cout << "Second player: ";

		cin >> move;
		movecheck();
		showboard();
		gameover();
	}


Notice that not only does this remove the duplicate code... but it also solves your problem because the loop condition is checked after EVERY turn... not just after player 2's turn.


Also.. the code above that while loop is the same. You can get rid of that and move it all into the loop. Keep it all in the same place!

Also, what is the most efficient way (with what I have so far) to implement the other 7 (or 14 if you say x and o as different cases) cases of winning, plus the draw case?


Loops.

There are 3 rows, so do a loop 3 times, checking each row.
Then do another loop for each of the 3 columns.
And the 2 diagonals will probably just have to be checked normally.

After all of those checks, do a loop to check every space on the board. If all spaces are occupied, you know you have a draw.




Other advice:

- Your 'gameover' function is declared as a bool, but you don't return anything from it. Either change it to a void, or (better yet), get rid of the 'over' variable and return the result.

- Ditto for movecheck and showboard. If you are not returning anything meaningful from those functions, they don't need a return value. Change them to be voids.

- Break the habit of global variables. They're messy and make things difficult when you get into larger projects. In general you want to keep variables in as small of a scope as possible. If another function needs information, pass it as a parameter.

- Loops loops loops. Your showboard() function is a copy/paste fest. copy/paste is bad. Turn that into a loop.

- Rather than doing a mod (%) to figure out if it's player 1 or player 2's turn... just keep the turn variable between 0 and 1. IE, instead of adding one each time, just invert it (you can use the ! operator for that: turn = !turn;

EDIT:

- You don't need to check for player 1 and player 2 victory separately. Rather than checking if each square is "o" or "x"... instead, check to see if the squares match. If all 3 match, then you know someone won... and you can check any one of the squares to see who it was.
Last edited on
Ok, thank you very much! I will definitely be changing this up and using this advice in the future!
Topic archived. No new replies allowed.