Tic tac toe with AI

Jul 28, 2009 at 4:08am
Hi guys, my assignment is to create a simple tic-tac-toe game with an AI as a C++ console application. I have my code done, but my teacher says he wants everything in C++, without C applications (like printf) but when I change them (eg. printf to cout), the console can't seem to output properly with a few funny symbols. Below is my code, can anyone help?

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
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

char matrix[3][3];  //intitial matrix declaration

char check(void); // declaration of functions
void init_matrix(void);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(void);

int main(void)
{
  char done;

  cout<<"Human vs. AI Tic Tac Toe."<<endl;
  cout<<"You will be playing against the computer as 'X'"<<endl;

  done =  ' ';
  init_matrix();

  do {
    disp_matrix();
    get_player_move();
    done = check(); /* check winner */
    if(done!= ' ') break; /* if winner found...*/
    get_computer_move();
    done = check(); /* check for winner again */
  } while(done== ' ');

  if(done=='X')
  cout<<"Human won! (but AI very dumb anyway)\n";
  else
  cout<<"AI so stupid still can win against you..."<<endl;
  disp_matrix(); /* show final positions */

  return 0;
}

/*Functions and function prototypes below
==============================================================================*/

void init_matrix(void) //matrix intitialisation
{
  int i, j;

  for(i=0; i<3; i++)
    for(j=0; j<3; j++) matrix[i][j] =  ' ';
}


void get_player_move(void) //call function for player input
{
  int x, y;

  cout<<"Enter X,Y coordinates for your move: ";
  scanf("%d%*c%d", &x, &y);

  x--; y--;

  if(matrix[x][y]!= ' '){
    cout<<"Invalid move, try again.\n";
    get_player_move();
  }
  else matrix[x][y] = 'X';
}

void get_computer_move(void) //AI move input
{
  int i, j;
  for(i=0; i<3; i++){
    for(j=0; j<3; j++)
      if(matrix[i][j]==' ') break;
    if(matrix[i][j]==' ') break;
  }

  if(i*j==9)  {
    cout<<"draw\n";
    exit(0);
  }
  else
    matrix[i][j] = 'O';
}

void disp_matrix(void) //matrix display
{
  int t;

  for(t=0; t<3; t++)
{
    printf(" %c | %c | %c ",matrix[t][0],
            matrix[t][1], matrix [t][2]);
    if(t!=2)
    printf("\n---|---|---\n");
  }
  printf("\n");
}


char check(void) //used for identifying winner
{
  int i;

  for(i=0; i<3; i++)  /* check rows */
    if(matrix[i][0]==matrix[i][1] &&
       matrix[i][0]==matrix[i][2]) return matrix[i][0];

  for(i=0; i<3; i++)  /* check columns */
    if(matrix[0][i]==matrix[1][i] &&
       matrix[0][i]==matrix[2][i]) return matrix[0][i];

  /* test diagonals */
  if(matrix[0][0]==matrix[1][1] &&
     matrix[1][1]==matrix[2][2])
       return matrix[0][0];

  if(matrix[0][2]==matrix[1][1] &&
     matrix[1][1]==matrix[2][0])
       return matrix[0][2];

  return ' ';
}
Last edited on Jul 28, 2009 at 9:27am
Jul 28, 2009 at 4:56am
what is it actually doing, also I don't see any AI in there.
Jul 28, 2009 at 6:05am
It is actually not so much an AI. It just needs to randomly throw in a "O" at any place that does not have a mark yet. It does not need to be that complex. It is under "get_computer_move" function. Sorry for being unclear.
Jul 29, 2009 at 10:53pm
this worked for me: (i just commented out your printf/scanf calls)
#note the x/y inputs need to be seperated my white space (ie "3 1" as opposed to "3,1")
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
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

char matrix[3][3];  //intitial matrix declaration

char check(void); // declaration of functions
void init_matrix(void);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(void);

int main(void)
{
  char done;

  cout<<"Human vs. AI Tic Tac Toe."<<endl;
  cout<<"You will be playing against the computer as 'X'"<<endl;

  done =  ' ';
  init_matrix();

  do {
    disp_matrix();
    get_player_move();
    done = check(); /* check winner */
    if(done!= ' ') break; /* if winner found...*/
    get_computer_move();
    done = check(); /* check for winner again */
  } while(done== ' ');

  if(done=='X')
  cout<<"Human won! (but AI very dumb anyway)\n";
  else
  cout<<"AI so stupid still can win against you..."<<endl;
  disp_matrix(); /* show final positions */

  return 0;
}

/*Functions and function prototypes below
==============================================================================*/

void init_matrix(void) //matrix intitialisation
{
  int i, j;

  for(i=0; i<3; i++)
    for(j=0; j<3; j++) matrix[i][j] =  ' ';
}


void get_player_move(void) //call function for player input
{
  int x, y;

  cout<<"Enter X,Y coordinates for your move: ";
//  scanf("%d%*c%d", &x, &y);
  cin >> x >> y;

  x--; y--;

  if(matrix[x][y]!= ' '){
    cout<<"Invalid move, try again.\n";
    get_player_move();
  }
  else matrix[x][y] = 'X';
}

void get_computer_move(void) //AI move input
{
  int i, j;
  for(i=0; i<3; i++){
    for(j=0; j<3; j++)
      if(matrix[i][j]==' ') break;
    if(matrix[i][j]==' ') break;
  }

  if(i*j==9)  {
    cout<<"draw\n";
    exit(0);
  }
  else
    matrix[i][j] = 'O';
}

void disp_matrix(void) //matrix display
{
  int t;

  for(t=0; t<3; t++)
{
//    printf(" %c | %c | %c ",matrix[t][0],
//            matrix[t][1], matrix [t][2]);
    cout << " " << matrix[t][0] << " | " << matrix[t][1] << " | " << matrix[t][2] << " ";
    if(t!=2)
//    printf("\n---|---|---\n");
    cout << "\n---|---|---\n";
  }
//  printf("\n");
  cout << "\n";
}


char check(void) //used for identifying winner
{
  int i;

  for(i=0; i<3; i++)  /* check rows */
    if(matrix[i][0]==matrix[i][1] &&
       matrix[i][0]==matrix[i][2]) return matrix[i][0];

  for(i=0; i<3; i++)  /* check columns */
    if(matrix[0][i]==matrix[1][i] &&
       matrix[0][i]==matrix[2][i]) return matrix[0][i];

  /* test diagonals */
  if(matrix[0][0]==matrix[1][1] &&
     matrix[1][1]==matrix[2][2])
       return matrix[0][0];

  if(matrix[0][2]==matrix[1][1] &&
     matrix[1][1]==matrix[2][0])
       return matrix[0][2];

  return ' ';
}
Jul 29, 2009 at 11:23pm
Well kid, its your lucky day today. I took the liberty of not only changing your printf and scanfs to couts and cins, but I also added some AI functions so the computer can respond to when an opponent is about to win and when a win is possible (for the computer) when it already has 2 O's in any one row, column or diagonal with 1 space free. It does not however change the overall flow of choosing squares from left to right, top to bottom. The computer will only deviate from that pattern if like I said the opponent is about to win, or a sure win is possible for the computer (with a single move). Also it still only plans for 1 move at a time, but nonetheless it still should impress your instructor.

I also changed your char matrix[][] to int matrix[][] because i just like ints better i guess. I'm not saying its perfect, in fact i spent quite a bit of time debugging (the improvements I made mostly), but after a couple of dozen runs now it seems pretty robust. However you should still check it yourself as you don't want the computer to erase all the X's on the board and replace them with O's... (Yes that is what had happened to me at one point.... no it was nothing wrong with your program, just me fiddling with it created some bugs that had to be worked out. ) I think everything is good for now though but i just wanted to warn you.

Oh i also made it loop for ya.

Oh about the only other thing I changed was added a second done = check(); before your second call to if(done!= ' ').

Also please let me know how it works for you.


Jul 29, 2009 at 11:30pm
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
#include <iostream>


using namespace std;

int matrix[3][3]; //initial matrix declaration

int row, column, diagonal;

int empty_r(int c);
int empty_c(int r);

bool vulnerable(int mat[3][3]);
bool winnable(int mat[3][3]);
bool finished(int mat[3][3]);

char check(void); // declaration of functions
void init_matrix(void);
void get_player_move(void);
void get_computer_move(void);
void disp_matrix(void);

void reset();


int main(void)
{
    char done; char c;
    bool CONTINUE = true;
    while (CONTINUE)
        {

            cout<<"Human vs. AI Tic Tac Toe."<<endl;
            cout<<"You will be playing against the computer as 'X'"<<endl;

            done =  ' ';
            init_matrix();

            do {
                    disp_matrix();
                    get_player_move();
                    done = check(); /* check winner */
                    if(done!= ' ') break; /* if winner found...*/
                    get_computer_move();
                    done = check(); /* check for winner again */
                    if(done!= ' ') break; /* if winner found...*/
                    if (finished(matrix)) //we don't have a winner and there are no open spaces.
                        {
                            disp_matrix();
                            cout << endl;
                            cout<<"draw\n";
                            break;
                        }
                    reset();

            } while(done== ' ');


            if(done=='X')
                cout<<"Human won! (but AI very dumb anyway)\n";
            else
                cout<<"AI so stupid still can win against you..."<<endl;
            disp_matrix(); /* show final positions */
            cout << "Play again? Y/N" << endl; cin >> c;
            if ( c=='N' || c=='n')
                CONTINUE = false;
            reset();
        }
    return 0;
}
Jul 29, 2009 at 11:32pm
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
void init_matrix(void) //matrix intitialisation
{
    int i, j;

    for(i=0; i<3; i++)
        for(j=0; j<3; j++) matrix[i][j] =  ' ';
}


void get_player_move(void) //call function for player input
{

    int x, y;

    cout<<"Enter X,Y coordinates for your move: ";
    cin >> x >> y;

    x--; y--;

    if(matrix[x][y]!= ' '){
        cout<<"Invalid move, try again.\n";
        get_player_move();
       }
    else matrix[x][y] = 'X';
}

void get_computer_move(void) //AI move input
{
    char temp;
    int test[3][3], temporary[3][3];
    for (int i = 0; i < 3; ++i)
        for (int j = 0; j < 3; ++j)
            {   test[i][j] = matrix[i][j]; temporary[i][j] = matrix[i][j];      }
    int i, j;
    for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
                if (matrix[i][j] == ' ')
                    {
                        temp = matrix[i][j];  
                        if (winnable(test))
                            {
                                if (row > 0)
                                    {
                                        if (matrix[row-1][empty_c(row-1)] != 'X')
                                            matrix[row-1][empty_c(row-1)] = 'O';                                         
                                        return;
                                    }
                                if (column > 0)
                                    {
                                        if (matrix[empty_r(column-1)][column-1] != 'X')
                                            matrix[empty_r(column-1)][column-1] = 'O'; 
                                        return;
                                    }
                                if (diagonal == 1)
                                    {
                                        if ( matrix[0][0] !='X' && matrix[1][1] != 'X' && matrix[2][2] != 'X')
                                            {matrix[0][0] = 'O'; matrix[1][1] = 'O'; matrix[2][2] = 'O';}
                                        return;
                                    }
                                else
                                    {
                                        if (matrix[0][2] != 'X' && matrix[1][1] != 'X' && matrix[2][0] != 'X')
                                            {matrix[0][2] = 'O'; matrix[1][1] = 'O'; matrix[2][0] ='O';}   
                                        return;
                                    }
                                return;
                                //break;
                            }
                        test[i][j] = temp;
                    }
            if (matrix[i][j]==' ')
                {
                    temp = matrix[i][j];
                    if (winnable(test))
                        {
                                if (row > 0)
                                    {
                                        if (matrix[row-1][empty_c(row-1)] != 'X')
                                            matrix[row-1][empty_c(row-1)] = 'O'; 
                                        return;
                                    }
                                if (column > 0)
                                    {
                                        if (matrix[empty_r(column-1)][column-1] != 'X')
                                            matrix[empty_r(column-1)][column-1] = 'O'; 
                                        return;
                                    }
                                if (diagonal == 1)
                                    {
                                        if ( matrix[0][0] !='X' && matrix[1][1] != 'X' && matrix[2][2] != 'X')
                                            {matrix[0][0] = 'O'; matrix[1][1] = 'O'; matrix[2][2] = 'O';} 
                                        return;
                                    }
                                else
                                    {
                                        if (matrix[0][2] != 'X' && matrix[1][1] != 'X' && matrix[2][0] != 'X')
                                            {matrix[0][2] = 'O'; matrix[1][1] = 'O'; matrix[2][0] = 'O';} 
                                        return;
                                    }
                            return;
                        }
                    test[i][j] = temp;
                }
        }
    for (i = 0; i < 3; i++)
        {
            for (j = 0; j < 3; j++)
                if (matrix[i][j]==' ')
                    {
                        temp = matrix[i][j];
                        test[i][j] = 'O';
                        if (!vulnerable(test))
                            break;
                        test[i][j] = temp;
                    }
            if (matrix[i][j]==' ')
                {
                    temp = matrix[i][j];
                    test[i][j] = 'O';
                    if (!vulnerable(test))
                        break;
                    test[i][j] = temp;
                }
        }
    if (column > 0)
        {
            if (matrix[empty_r(column-1)][column-1] !='X')
                matrix[empty_r(column-1)][column-1] = 'O';
            return;
        }
    if (row > 0)
        {
            if (matrix[row-1][empty_c(row-1)] !='X')
                matrix[row-1][empty_c(row-1)] = 'O';
            return;
        } 
    if (diagonal == 1 )
        {
            if (matrix[0][0] != 'X')
                matrix[0][0] = 'O';
            if (matrix[1][1] != 'X')
                matrix[1][1] = 'O';
            if (matrix[2][2] != 'X')
                matrix[2][2] = 'O';
            return;
        }
    if (diagonal == 2 )
        {
            if (matrix[0][2] != 'X')
                matrix[0][2] = 'O';
            if (matrix[1][1] != 'X')
                matrix[1][1] = 'O';
            if (matrix[2][0] != 'X')
                matrix[2][0] = 'O';
            return;
        }
    if (matrix[i][j] != 'X')
        matrix[i][j] = 'O';
}

void disp_matrix(void) //matrix display
{
    int t;

    for(t=0; t<3; t++)
        {

            cout << " " << char(matrix[t][0]) << " | " << char(matrix[t][1]) << " | " << char(matrix[t][2]);

            if(t!=2)
            cout << "\n---|---|---\n";
        }
    cout << endl;
}
Last edited on Jul 29, 2009 at 11:53pm
Jul 29, 2009 at 11:32pm
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
137
138
char check(void) //used for identifying winner
{
    int i;

    for(i=0; i<3; i++)  /* check rows */
        if(matrix[i][0]==matrix[i][1] &&
            matrix[i][0]==matrix[i][2]) return matrix[i][0];

    for(i=0; i<3; i++)  /* check columns */
        if(matrix[0][i]==matrix[1][i] &&
            matrix[0][i]==matrix[2][i]) return matrix[0][i];

  /* test diagonals */
    if(matrix[0][0]==matrix[1][1] &&
        matrix[1][1]==matrix[2][2])
            return matrix[0][0];

    if(matrix[0][2]==matrix[1][1] &&
        matrix[1][1]==matrix[2][0])
            return matrix[0][2];

    return ' ';
}

bool vulnerable(int mat[3][3])
{
    char a, b, c, d, e, f, g, h, i;
    a = mat[0][0], b = mat[0][1], c = mat[0][2];
    d = mat[1][0], e = mat[1][1], f = mat[1][2];
    g = mat[2][0], h = mat[2][1], i = mat[2][2];
    if ( (a=='X' && b=='X' && c!='O') || (b=='X' && c=='X' && a!='O') || (a=='X' && c=='X' && b!='O') )
        { row = 1; return true;}
    if ( (d=='X' && e=='X' && f!='O') || (e=='X' && f=='X' && d!='O') || (d=='X' && f=='X' && e!='O') )
        { row = 2; return true;}
    if ( (g=='X' && h=='X' && i!='O') || (h=='X' && i=='X' && g!='O') || (g=='X' && i=='X' && h!='O') )
        { row = 3; return true;}
    if ( (a=='X' && d=='X' && g!='O') || (d=='X' && g=='X' && a!='O') || (a=='X' && g=='X' && d!='O') )
        { column = 1; return true;}
    if ( (b=='X' && e=='X' && h!='O') || (e=='X' && h=='X' && b!='O') || (b=='X' && h=='X' && e!='O') )
        {  column = 2; return true;}
    if ( (c=='X' && f=='X' && i!='O') || (f=='X' && i=='X' && c!='O') || (c=='X' && i=='X' && f!='O') )
        { column = 3; return true;}
    if ( (a=='X' && e=='X' && i!='O') || (e=='X' && i=='X' && a!='O') || (a=='X' && i=='X' && e!='O') )
        { diagonal = 1; return true; }
    if ( (g=='X' && e=='X' && c!='O') || (e=='X' && c=='X' && g!='O') || (g=='X' && c=='X' && e!='O') )
        { diagonal = 2; return true; }
    return false;
}

bool winnable(int mat[3][3])
{
    char a, b, c, d, e, f, g, h, i;
    a = mat[0][0], b = mat[0][1], c = mat[0][2];
    d = mat[1][0], e = mat[1][1], f = mat[1][2];
    g = mat[2][0], h = mat[2][1], i = mat[2][2];
    if ( (a=='O' && b=='O' && c!='X') || (b=='O' && c=='O' && a!='X') || (a=='O' && c=='O' && b!='X') )
        {
            row = 1;             
             return true;
        }
    if ( (d=='O' && e=='O' && f!='X') || (e=='O' && f=='O' && d!='X') || (d=='O' && f=='O' && e!='X') )
        {
            row = 2;            
            return true;
        }
    if ( (g=='O' && h=='O' && i!='X') || (h=='O' && i=='O' && g!='X') || (g=='O' && i=='O' && h!='X') )
        {
            row = 3;            
            return true;
        }
    if ( (a=='O' && d=='O' && g!='X') || (d=='O' && g=='O' && a!='X') || (a=='O' && g=='O' && d!='X') )
        {
            column = 1;            
            return true;
        }
    if ( (b=='O' && e=='O' && h!='X') || (e=='O' && h=='O' && b!='X') || (b=='O' && h=='O' && e!='X') )
        {
            column = 2;                        
            return true;
        }
    if ( (c=='O' && f=='O' && i!='X') || (f=='O' && i=='O' && c!='X') || (c=='O' && i=='O' && f!='X') )
        {
            column = 3;            
            return true;
        }
    if ( (a=='O' && e=='O' && i!='X') || (e=='O' && i=='O' && a!='X') || (a=='O' && i=='O' && e!='X') )
        {
            diagonal = 1;           
            return true;
        }
    if ( (g=='O' && e=='O' && c!='X') || (e=='O' && c=='O' && g!='X') || (g=='O' && c=='O' && e!='X') )
        {
            diagonal = 2;            
            return true;
        }
    return false;


}

bool finished(int mat[3][3])
{
    for (int i = 0; i < 3; ++i)
        {
            for (int j = 0; j < 3; ++j)
                {
                    if (mat[i][j] == ' ')
                        return false;
                }
        }
    return true;
}

int empty_c(int r)
{
    for (int i = 0; i < 3; ++i)
        {
            if (matrix[r][i] == ' ')
                return i;
        }
}

int empty_r(int c)
{
    for (int i = 0; i < 3; ++i)
        {
            if (matrix[i][c] == ' ')
                return i;
        }
}

void reset()
{
    row = 0;
    column = 0;
    diagonal = 0;
}
Last edited on Jul 29, 2009 at 11:42pm
Jul 30, 2009 at 1:21am
Hi guys, thanks a lot for your help. As mrHappyPants said, it needs to have <number> <space> <number>, not a comma.

wtf,
Thanks a lot!! I'll try and edit it a little to see if it can accept a comma if I use something like 'getline', etc. I'll see what I can do from here.

Thanks again guys.
Aug 4, 2009 at 3:59am
Hi guys, I saw another problem in the above code that me and my friends can't seem to fix, when the player "draws" with the AI, it outputs 2 lines, both for the "player lost" and the "draw". How do I fix this without interfering with the flow?
Topic archived. No new replies allowed.