Tic-Tac-Toe MiniMax Algorithm

Hello I am attempting to create an unbeatable Tic-Tac-Toe game using the MiniMax Algorithm. I keep running it to issues with my code. My MiniMax algorithm appears to work but it does not terminate once it finds the optimal play. In line 7-18 I established parameters for it to terminate but it continues to execute without stopping. My code is too long to submit in one post so I'll piece it together into multiple replies.

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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <iostream>
#include <string>
using namespace std;

// Structure
struct Computer
{
    int Row;
    int Column;
};

// Constants
const int Human_Player = 1;         // To hold the integer value of Player 1
const int AI_Player = 2;            // To hold the integer value of Player 2
const int GRID_SIZE = 3;            // To hold the grid size of the array
const char Human_Move = 'X';        // To hold the
const char AI_Move = 'O';

// Global variable
int index = 0;          // Variable to keep track of the number of moves

// Function prototypes
Computer Best_Computer_Move(char Board[][GRID_SIZE], int Player);
void Play_Game();
void Initial_Board(char Array[][GRID_SIZE]);
void Display_Board(char Array[][GRID_SIZE]);
void Turn(char Game_Board[][GRID_SIZE], int Whose_Turn);
int Check_For_Winner(char Game_Board[][GRID_SIZE]);
int Min_Max(char Board[][GRID_SIZE], int Depth, bool isMax);

int main()
{
    Play_Game();
    return 0;
}
//*******************************************
// Definition of Play_Game function.        *
//*******************************************
void Play_Game()
{
    char Board[GRID_SIZE][GRID_SIZE];           // Declare a char array
    Initial_Board(Board);                       // Call the Initial_Board function 
    Turn(Board, Human_Player);                  // The Turn function to Play
}
//*******************************************
// Definition of Initial_Board function.    *
//*******************************************
void Initial_Board(char Array[][GRID_SIZE])
{
    int number = 1;
    for (int i = 0; i < GRID_SIZE; i++)
    {
        for (int j = 0; j < GRID_SIZE; j++)
        {
            Array[i][j] = to_string(number).c_str()[0]; 
            number += 1;
        }
    }
    // Display the contents of the array
    cout << "\t-------\n";
    for (int i = 0; i < GRID_SIZE; i++)
    {
        cout << "\t|";
        for (int j = 0; j < GRID_SIZE; j++)
        {
            cout << Array[i][j] << "|";
        }
        cout << "\n\t-------\n";
    }
}
//*******************************************
// Definition of Display_Board function.    *
//*******************************************
void Display_Board(char Array[][GRID_SIZE])
{
    cout << "\t-------\n";
    for (int i = 0; i < GRID_SIZE; i++)         // Loop through the array and display it contents
    {
        cout << "\t|";
        for (int j = 0; j < GRID_SIZE; j++)
        {
            cout << (Array[i][j]) << "|";
        }
        cout << "\n\t-------\n";
    }

}
//***********************************
// Definition of Turn function.     *
//***********************************
void Turn(char Game_Board[][GRID_SIZE], int Whose_Turn)
{
    int input;          // To hold user input

    while((Check_For_Winner(Game_Board) == 0) && (index != GRID_SIZE * GRID_SIZE))
    {
        if (Whose_Turn == Human_Player)
        {
            cout << "Player 1(Human) select a cell(1 - 9) to place your move." << endl;
            while(!(cin >> input) || ((input <= 0 ) || (input > 9 )))              
                       {
                            cout << "ERROR!!! The number cannot be less than 0 or greater  than 9.";
                            cin.clear();    
                            cout << "\nPlease enter a number between 0 and 9: " << endl;
                            cin.ignore(123, '\n');
                       }
            int row = (input - 1) / 3;
            int column = (input - 1) % 3;
            char Grid_Position = Game_Board[row][column];
            if ((Grid_Position == 'X') || (Grid_Position == 'O'))
            {
                cout << "ERROR!!! A move has already been made there." << endl;
            }
            else
            {
                Game_Board[row][column] = Human_Move;
                index++;
                Display_Board(Game_Board);
                Whose_Turn = AI_Player;
            }
        }
        else if (Whose_Turn == AI_Player)
        {
            cout << "AI Player's turn" << endl;
            Computer Computer_Move;
            Computer_Move = Best_Computer_Move(Game_Board, AI_Player);
            Game_Board[Computer_Move.Row][Computer_Move.Column] = AI_Move;
            cout << "The value of AI is "; 
            cout << Game_Board[Computer_Move.Row][Computer_Move.Column] << endl;
            index++;
            cout << "Row is " << Computer_Move.Row << endl;
            cout << "Column is " << Computer_Move.Column << endl;            
            cout << "AI Player has moved" << endl;
            Display_Board(Game_Board);
            Whose_Turn = Human_Player;

           
        }
    }
    if (Check_For_Winner(Game_Board) != 0)          // Declare a winner
    {
        if (Check_For_Winner(Game_Board) == -10)    // If the score is -10
            cout << "Congratulations!!! Player 1 has won!!!" << endl;
        else if (Check_For_Winner(Game_Board) == 10)
            cout << "Congratulations!!! Player 2 has won!!!" << endl;
    }
    else if ((Check_For_Winner(Game_Board) == 0) && (index == GRID_SIZE * GRID_SIZE))
        cout << "It's a draw! Neither player has won." << endl;

}
//***********************************************
// Definition of Check_For_Winner function.     *
//***********************************************
int Check_For_Winner(char Game_Board[][GRID_SIZE])
{
    // Check horizontal for winning conditions
    for (int i = 0; i < GRID_SIZE; i++)
    {
        if (((Game_Board[i][0]) == (Game_Board[i][1])) &&
            ((Game_Board[i][1]) == (Game_Board[i][2])) &&
            ((Game_Board[i][2]) == (Game_Board[i][0])))
        {
            if ((Game_Board[i][0]) == AI_Move)
                return 10;
            else if ((Game_Board[i][0]) == Human_Move)
                return -10;
        }
    }
    // Check vertical for winning conditions
    for (int j = 0; j < GRID_SIZE; j++)
    {
        if (((Game_Board[0][j]) == ((Game_Board[1][j]))) &&
            ((Game_Board[1][j]) == ((Game_Board[2][j]))) &&
            ((Game_Board[2][j]) == ((Game_Board[0][j]))))
        {
            if ((Game_Board[0][j]) == AI_Move)
                return 10;
            else if ((Game_Board[0][j]) == Human_Move)
                return -10;
        }
    }
    // Check diagonal for winning conditions
    if (((Game_Board[0][0]) == (Game_Board[1][1])) &&
        ((Game_Board[1][1]) == (Game_Board[2][2])) &&
        ((Game_Board[2][2]) == (Game_Board[0][0])))
    {
        if ((Game_Board[0][0]) == AI_Move)
            return 10;
        else if ((Game_Board[0][0]) == Human_Move)
            return -10;
    }
    // Check diagonal for winning conditions
    else if (((Game_Board[0][2]) == (Game_Board[1][1])) &&
             ((Game_Board[1][1]) == (Game_Board[2][0])) &&
             ((Game_Board[2][0]) == (Game_Board[0][2])))
    {
        if ((Game_Board[0][2]) == AI_Move)
            return 10;
        else if ((Game_Board[0][2]) == Human_Move)
            return -10;
    }
    return 0;
}
Last edited on
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

//*******************************************
// Definition of Min_Max function.          *
//*******************************************
int Min_Max(char Board[][GRID_SIZE], int Depth, bool isMax)
{
    int Max_Move = -1000;
    int Score = Check_For_Winner(Board);        // Set the value of Score
    cout << "The value of Score is " << Score << endl;
    
    if (Score == 10)                            // Return the value of Score if the computer has won
        return Score;

    if (Score == -10)                           // Return the value of Score if the human player has won
        return Score;

    if ((Check_For_Winner(Board) == 0) && (index == GRID_SIZE * GRID_SIZE))
        return 0;
    if (isMax == false)                // Computer Player's turn
    {
        for (int i = 0; i < GRID_SIZE; i++)
        {
            for (int j = 0; j < GRID_SIZE; j++)
            {
                // Check to see if a player has made a move there
                while (!((Board[i][j] == 'X') || (Board[i][j] == 'O')))
                {
                    // Store the current value of the element in the array
                    char Temporary = Board[i][j];
                    cout << "The contents of temporary for Max is " << Temporary << endl;

                    // Make the move for the computer
                    Board[i][j] = AI_Move;
                    cout << "The value for the element Max is " << Board[i][j] << endl;

                    Display_Board(Board);
                    cout << "The value of Max_Move " << Max_Move << endl;

                    Max_Move = max(Max_Move,
                                   Min_Max(Board, Depth++, !isMax));

                    // Undo the move made by the computer
                    Board[i][j] = Temporary;
                    cout << "The contents of temporary for Max is " << Temporary << endl;
                }
            }
        }
        return Max_Move;
    }
    else if (isMax == true)                               // Human Player's turn
    {
        int Min_Move = 1000;
        for (int i = 0; i < GRID_SIZE; i++)
        {
            for (int j = 0; j < GRID_SIZE; j++)
            {
                // Check to see if a player has made a move there
                while (!((Board[i][j] == 'X') || (Board[i][j] == 'O')))
                {
                    // Store the current value of the element in the array
                    char Temporary_2 = Board[i][j];
                    cout << "The contents of temporary for Min is " << Temporary_2 << endl;

                    // Make the move for the Human player
                    Board[i][j] = Human_Move;
                    cout << "The value for the element Min is " << Board[i][j] << endl;
                    Display_Board(Board);

                    Min_Move = min(Min_Move,
                                   Min_Max(Board, Depth++, !isMax));

                    // Undo the move made for the Human player
                    Board[i][j] = Temporary_2;
                    cout << "The contents of temporary for Min is " << Temporary_2 << endl;
                }
            }
        }
        return Min_Move;
    }
}
//***********************************************************
// Definition of structure function Best_Computer_Move.     *
//***********************************************************
Computer Best_Computer_Move(char Board[][GRID_SIZE], int Player)
{
    cout << "You are in the structure" << endl;
    int Best_Value = -1000;
    Computer Best_Move;         // Create a structure variable
    Best_Move.Row = -1;
    Best_Move.Column = -1;

    for (int i = 0; i < GRID_SIZE; i++)
    {
        for (int j = 0; j < GRID_SIZE; j++)
        {
            // Check to see if a player has made a move there
            while (!((Board[i][j] == 'X') || (Board[i][j] == 'O')))
            {
                cout << "i = " << i << " j = " << j << endl;
                // Store the current value of the element in the array
                char Temporary = Board[i][j];
                cout << "The contents of temporary int the structure is " << Temporary << endl;

                // Make the move for the computer
                Board[i][j] = AI_Move;

                cout << Board[i][j] << endl;

                // Calculate the Maximizing move
                int Value = Min_Max(Board, 0, false);

                // Undo the move made by the computer
                Board[i][j] = Temporary;

                if (Value > Best_Value)
                {
                    Best_Move.Row = i;
                    Best_Move.Column = j;
                    Best_Value = Value;
                }
            }

        }
    }
    return Best_Move;
}
Last edited on
Topic archived. No new replies allowed.