How do I shorten this tic tac toe program? (Program works perfect)

How do I shorten this program?
This is a double player tic tac toe. Though it works perfect, Im afraid its too long
What am I doing wrong?
I am going to add single player (vs computer) which will make the program even longer! :(

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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//tic tac toe
#include "iostream"
#include "vector"
#include "math.h"
#include "stdio.h"
#include "string.h"
using namespace std;
//#include "std_lib_facilities.h"
	int board[3][3];

void display_table(){
	for (int i = 0; i < 3; ++i){
		for (int j = 0; j < 3; ++j){
			switch(board[i][j]){
				case 0 : cout << '.'; break;
				case 1 : cout << 'X'; break;
				case 2 : cout << 'O'; break;
			}
			cout << ' ';
		}
         cout << '\n';
	}
}


void mark(int x, int y, bool Xchance){
		x--;
		y = 3 - y;
		if(Xchance)
		board[y][x] = 1;
		else
		board[y][x] = 2;
}
bool overwrite(int x, int y){
	x--;
	y = 3 - y;
	if(board[y][x] == 0)
		return 0;
	return 1;
}
bool check_winner(){
	for (int i = 0; i < 3; ++i) // horizontal checks
			if(board[i][0] == 1)
				if(board[i][1] == 1)
					if(board[i][2] == 1)
						return 1;

	for (int i = 0; i < 3; ++i) // horizontal checks
			if(board[i][0] == 2)
				if(board[i][1] == 2)
					if(board[i][2] == 2)
						return 1;
	for (int i = 0; i < 3; ++i) // vertical checks
			if(board[0][i] == 1)
				if(board[1][i] == 1)
					if(board[2][i] == 1)
						return 1;
	for (int i = 0; i < 3; ++i) // vertical checks
			if(board[i][0] == 2)
				if(board[i][1] == 2)
					if(board[i][2] == 2)
						return 1;
	//major diagonal
if(board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1 )
	return 1;
if(board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1 )
    return 1;

   // minor diagonal
if(board[0][2] == 1 && board[1][1] == 1 && board[2][0] == 1 )
	return 1;
if(board[0][2] == 2 && board[1][1] == 2 && board[2][0] == 2 )
    return 1;
	return 0;
}

int main(){
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j)
		 	board[i][j] = 0; // 0 means empty, 1 means X, 2 means O

	cout << "\nTic Tac toe\n\n";
		display_table();
		cout << '\n';
	bool too_large = false;
	bool tie = true;
	int x, y;
	for (int i = 0; i < 9; ++i) // even for X, odd for O

	{

		if(i % 2 == 0)
			cout << "X its your turn, enter co-ordinates : ";
		else
			cout << "O its your turn, enter co-ordinates : ";

		cin >> x >> y;

		if(x > 3 || y > 3)
			too_large = true;
			
		while( too_large || (overwrite(x , y))  ){ 

			if(x > 3 || y > 3)
			too_large = true;

			if(too_large){
			cout << "Coordinates can only be an int in [1,3]!\nEnter correct value : ";
			cin >> x >> y;
			if(x <= 3 && y <= 3){
				too_large = false; 
			}
			continue;
			}
			if(overwrite(x,y)){
			cout << "Filled box! Enter different values : ";
			cin >> x >> y;}
			
	    }
			too_large = false;

		mark(x , y , i % 2 == 0); // marks x or o in table
		cout << '\n';
		display_table(); // display the table
		cout << '\n';
		if(check_winner()){ tie = false;
			cout << "We have a winner!";
				if(i % 2 == 0)
					cout << "\nX the victor!\n";
				else
					cout << "\nO the victor!\n";
			 break;}
		}
		if( tie)cout << "Tie!\n";
		return 0;
	}
Last edited on
I finally got mine to work for tic tac toe, but mines just as long. I tried to have it check vertical and horizontal at once, but failed miserably... i've posted mine below:


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
#include <iostream>
using namespace std;

int playagain();

int main()
{
int board[3][3],x,y,loopcount=0;
int PlayerA=1, PlayerB=5;
int i=0;
int winchecker=0, checkx=0, checky=0, leftdiag=0, rightdiag=0;
bool win=0;
cout<<"[X,Y]"<<endl;
cout<<"[0,0]\t[1,0]\t[2,0]\n";
cout<<"[0,1]\t[1,1]\t[2,1]\n";
cout<<"[0,2]\t[1,2]\t[2,2]\n\n";


	while(loopcount<9 & win!=1)
	{
	i++;
	//to set board
	cout<<"**********************";
	for (y=0;y<3; y++)
		{
			cout<<endl;
			for (x=0;x<3; x++)
			{
			if (loopcount==0) {board[x][y]=0;}
			cout<<board[x][y]<<"\t";
		}
		}
	cout<<endl<<"**********************"<<endl;

	//game play
	{
	do{
	if ((i % 2)!=0) {cout<<"Player A\n";loopcount++;}
	else {cout<<"Player B\n";loopcount++;}
	cin>>x; cin>>y;
	cout<<endl;
	if ((x>2 or x<0) or (y>2 or y<0) or (board[x][y]!=0)){cout<<"Error\n"; loopcount--;}
	if (board[x][y]==0)
	{
		if ((i % 2)!=0) {board[x][y]=PlayerA;}
		else {board[x][y]=PlayerB;}
	}
	else {x=5;}
	
	// to determine winner-vertical
	for (checkx=0;checkx<3;checkx++)
	{
	for (checky=0;checky<3;checky++)
	{
	winchecker+=board[checkx][checky];
	if (winchecker==(3*PlayerA)){cout<<"winner-player A"; winchecker=0; win=1; break;}
	if (winchecker==(3*PlayerB)){cout<<"winner-player B"; winchecker=0; win=1; break;}
	}
	winchecker=0;
	}
	
	// to determine winner-horizontal
	for (checky=0;checky<3;checky++)
	{
	for (checkx=0;checkx<3;checkx++)
	{
	winchecker+=board[checkx][checky];
	if (winchecker==(3*PlayerA)){cout<<"winner-player A"; winchecker=0; win=1; break;}
	if (winchecker==(3*PlayerB)){cout<<"winner-player B"; winchecker=0; win=1; break;}
	}
	winchecker=0;
	}
	
	//to determine winner-left diagnal (left top start) & right diagnal
	{
	leftdiag=board[0][0]+board[1][1]+board[2][2];
	rightdiag=board[2][0]+board[1][1]+board[0][2];
	
	if (((leftdiag==(3*PlayerA))) or ((rightdiag==(3*PlayerA)))){cout<<"winner-player A"; winchecker=0; win=1; break;}
	if (((leftdiag==(3*PlayerB))) or ((rightdiag==(3*PlayerB)))){cout<<"winner-player B"; winchecker=0; win=1; break;} 
	}
			
	if ((win!=1) && loopcount==9){cout<<"No Winners Idiots";}
	}while((x>2 or x<0) or (y>2 or y<0));
	}
	}	
	cout<<endl;
	playagain();
	return 0;
}


int playagain()
{
	int playagain;
	cout<<"Press 1 to play again, anything else to exit\n";
	cin>>playagain;
	while(playagain==1)
	{
	main();
	}
	return 0;
}
Last edited on
Hey! Can you edit your comment to put it into code tags? Makes it easier to read :)
Sure, mines a little shorter i guess :P. It'll prob be similar in length, once i add in more titles, ect. Seems to be a tic tac toe kinda day. Everyone's doing it.
Haha yeah :D Good job! :)
@ratfus

You have a serious error in your program.

The C++ standard states that a program must not call its own main() function. A given compiler implementation might let you get away with it, but it's not actually legal C++.

Andy
Last edited on
It would be easier to represent the board with the actual characters that it displays:
1
2
3
4
5
6
7
8
9
10
char board[3][3];               // each cell is ' ', 'X' or 'O'

void display_table(){
    for (int i = 0; i < 3; ++i){
        for (int j = 0; j < 3; ++j){
            cout << board[i][j] << ' ';
        }
        cout << '\n';
    }
}


You don't need the mark() and overwrite() functions at all. The key to making this work is to convert the user's 1-3 input to C++ friendly 0-2 values. To keep things straight, Always represent the data internally as 0-2, even though you might display it with 1-3:
1
2
cin >> x >> y;
--x; --y;  // immediately convert to internal representation (0-2) 


check_winner can be simplified a lot. By the way you have a bug in your code there. It won't catch the case where player 2 wins on the major diagonal because these checks are identical:
1
2
3
4
    if(board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1 )
        return 1;
    if(board[0][0] == 1 && board[1][1] == 1 && board[2][2] == 1 )
        return 1;


Here is a shorter version
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
// See if we have a winner. Return ' ' (no winner),
// 'X' (X wins) or 'O' (O wins)
int check_winner(){
    for (int i = 0; i < 3; ++i) { // horizontal checks
        if(board[i][0] == board[i][1] &&
           board[i][0] == board[i][2]) {
            return board[i][0];
        }
    }

    for (int i = 0; i < 3; ++i) { // vertical checks
        if(board[0][i] == board[1][i] &&
           board[0][i] == board[2][i]) {
            return board[0][i];
        }
    }
    //major diagonal
    if(board[0][0] == board[1][1] && board[0][1] == board[2][2]) {
        return board[0][0];
    }

    // minor diagonal
    if(board[0][2] == board[1][1]  && board[0][2] == board[2][0]) {
        return board[0][2];
    }
    return ' ';                 // no winner
}


In main() you call overwrite() twice and check if the numbers are too large in 3 different places. This can be simplified a lot. When validating user input, I like to use this pattern:
1
2
3
4
5
while (true) {
   get input
   if (input is valid) break
   else print error message
}

It seems awkward because the real test condition is in the middle of the loop, but it really simplifies the code. Note that in the code below I'm actually checking for errors first and valid input second.
1
2
3
4
5
6
7
8
9
10
11
12
13
        while (true) {
            cin >> x >> y;
            --x; --y;           // immediately convert 1-3 into 0-2

            if(x > 2 || y > 2) {
                cout << "Coordinates can only be an int in [1,3]!\nEnter correc\
t value : ";
            } else if (board[x][y] != ' ') {
                cout << "Filled box! Enter different values : ";
            } else {
                break;          // the values are good.
            }
        }

Also in main(), it's handy to create a variable with the character for the current player's mark:
1
2
3
4
5
6
7
8
9
10
    for (int i = 0; i < 9; ++i) { // even for X, odd for O
        char mark = (i%2 ? 'O' : 'X');
        cout << mark << " its your turn, enter co-ordinates : ";
        ...
        if(check_winner() == mark) {
            cout << "We have a winner!\n";
            cout << mark << " the victor!\n";
            tie = false;
            break;
        }

Putting all of this together the program shrinks from 136 lines to 83.
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
//tic tac toe
#include "iostream"
#include "vector"
#include "math.h"
#include "stdio.h"
#include "string.h"
using namespace std;
//#include "std_lib_facilities.h"
char board[3][3];               // each cell is ' ', 'X' or 'O'

void display_table(){
    for (int i = 0; i < 3; ++i){
        for (int j = 0; j < 3; ++j){
            cout << board[i][j] << ' ';
        }
        cout << '\n';
    }
}


// See if we have a winner. Return ' ' (no winner),
// 'X' (X wins) or 'O' (O wins)

int check_winner(){
    for (int i = 0; i < 3; ++i) { // vertical checks
        if(board[0][i] == board[1][i] &&
           board[0][i] == board[2][i]) {
            return board[0][i];
        }
    }
    //major diagonal
    if(board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return board[0][0];
    }

    // minor diagonal
    if(board[0][2] == board[1][1]  && board[0][2] == board[2][0]) {
        return board[0][2];
    }
    return ' ';                 // no winner
}

int main(){
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            board[i][j] = ' ';

    cout << "\nTic Tac toe\n\n";
    display_table();
    cout << '\n';
    bool too_large = false;
    bool tie = true;
    int x, y;
    for (int i = 0; i < 9; ++i) { // even for X, odd for O
        char mark = (i%2 ? 'O' : 'X');
        cout << mark << " its your turn, enter co-ordinates : ";

        while (true) {
            cin >> x >> y;
            --x; --y;           // immediately convert 1-3 into 0-2

            if(x > 2 || y > 2) {
                cout << "Coordinates can only be an int in [1,3]!\nEnter correc\
t value : ";
            } else if (board[x][y] != ' ') {
                cout << "Filled box! Enter different values : ";
            } else {
                break;          // the values are good.
            }
        }

        board[x][y] = mark;
        display_table(); // display the table
        if(check_winner() == mark) {
            cout << "We have a winner!\n";
            cout << mark << " the victor!\n";
            tie = false;
            break;
        }
    }
    if( tie)cout << "Tie!\n";
    return 0;
}







I've always preferred a prettier board.

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
#include <iostream>

using namespace std;

void display(char* board) {
    const char* h_sep = "---+---+---";
    const char* v_sep = " |";

    for (unsigned row = 0; row < 3; ++row)
    {
        for (unsigned col = 0; col < 3; ++col)
        {
            cout << ' ' << board[row * 3 + col];
            if (col < 2) cout << v_sep;
        }
        cout << '\n';
        if (row < 2) cout << h_sep << '\n';
    }

    cout<< '\n';
}

char check_winner(char* board, unsigned* t)
{
    if (board[t[0]] == board[t[1]] && board[t[1]] == board[t[2]])
        return board[t[0]];
    return '\0';
}

int check_winner(char* board) {
    const std::size_t n_triplets = 8;
    static unsigned triplets[n_triplets][3] =
    { 
        { 0,1,2 },{ 3,4,5 },{ 6,7,8 },{ 0,3,6 },
        { 1,4,7 },{ 2,5,8 },{ 0,4,8 },{ 2,4,6 } 
    };

    for (std::size_t i = 0; i < n_triplets; ++i)
        if (char winner = check_winner(board, triplets[i]))
            return winner;
    return '\0';
}

int main() {

    char board[9] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

    cout << "\nTic Tac toe\n\n";
    display(board);

    unsigned turn = 0;
    while ( turn < 9 && !check_winner(board))
    {
        char mark = "XO"[turn % 2];

        unsigned cell;
        cout << mark << " it's your turn, where will you play?\n> ";
        cin >> cell;
        if (!cin || cell < 1 || cell > 9)
        {
            cin.clear();
            cin.ignore(1000, '\n');
            cout << "Invalid input.\n";
        }
        else if (board[cell - 1] == 'X' || board[cell - 1] == 'Y')
            cout << "Cell is occupied.\n";
        else
        {
            board[cell - 1] = mark;
            ++turn;
            display(board);
        }
    }

    if (char winner = check_winner(board))
        cout << winner << " wins!\n";
    else
        cout << "It's a tie!\n";
}
I cant thank you enough, dhayden
Topic archived. No new replies allowed.