Tic Tac Toe Level 4 Stars

Hi everyone, I'm doing Tic Tac Toe exercise and I have a bad ass problem in some section of my code,(but may be it's a very simple problem for you), here's the code, (PLEASE if you feel to help but cancel your intention because my large code and want to leave this page, then skip reading my code, instead read my comment below).

and here's my code :
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
// Exercise 6 - Tic Tac Toe level 4 stars
// **** Modify the program so the user will play versus AI Defensive system
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <conio.h> // okay now,.. I know this header is a dumb but right now I really don't want to talk about this thing.
using namespace std;

int ValidMove();

int main()
// Initializing and declaration of board
{cout << "Tic Tac Toe.\n\nYou will play with AI" << endl;
    char cSquare1 = '1';
    char cSquare2 = '2';
    char cSquare3 = '3';
    char cSquare4 = '4';
    char cSquare5 = '5';
    char cSquare6 = '6';
    char cSquare7 = '7';
    char cSquare8 = '8';
    char cSquare9 = '9';
	char Turn = 1;
	bool bGameOver  = true; 

	// Main game loop
     do { // Print Board every turn

        cout << cSquare1 << "|" << cSquare2 << "|" << cSquare3 << endl;
        cout << "-+-+-"  << endl;
        cout << cSquare4 << "|" << cSquare5 << "|" << cSquare6 << endl;
        cout << "-+-+-"  << endl;
        cout << cSquare7 << "|" << cSquare8 << "|" << cSquare9 << endl << endl;

        // Set Player and AI marker
          char Mark;
            if(Turn == 1){Mark = 'X';} // Player's Mark
            else         {Mark = 'O';} // AI's Mark

        // Prompt the respective turn
        char cNextMove;int AiMove; // declaration of player's move and AI's move
    if (Turn == 1) { // Turn 1 = Player's Turn
        // Loop until the player and AI give valid move
         bool bValidMove = true;
       do {
           cout << "\nYour move now: ";
           cin >> cNextMove;  // Player enter their move
           bValidMove = true; // Pretend player enter valid move

           // Check for player's valid move and store the data player has input to the Mark
           if ( cNextMove == '1' && cSquare1 == '1') {
              cSquare1 = Mark;
           } else if ( cNextMove == '2' && cSquare2 == '2') {
              cSquare2 = Mark;
           } else if ( cNextMove == '3' && cSquare3 == '3') {
              cSquare3 = Mark;
           } else if ( cNextMove == '4' && cSquare4 == '4') {
              cSquare4 = Mark;
           } else if ( cNextMove == '5' && cSquare5 == '5') {
              cSquare5 = Mark;
           } else if ( cNextMove == '6' && cSquare6 == '6') {
              cSquare6 = Mark;
           } else if ( cNextMove == '7' && cSquare7 == '7') {
              cSquare7 = Mark;
           } else if ( cNextMove == '8' && cSquare8 == '8') {
              cSquare8 = Mark;
           } else if ( cNextMove == '9' && cSquare9 == '9') {
              cSquare9 = Mark;
           } else {
		cout << "Invalid Move. Try again." << endl;
				bValidMove = false;   } // The player is a dumb and entered invalid move(no 1-9 or maybe non numeric)
           } while (!bValidMove); // Loop the process (back at line 46th)

    } else { // Else = Turn != 1, AI's Turn
         cout << "AI's move now.\n";
         bool bValidMove = true; // Check AI valid move
        do{  srand(time(NULL)); // Generate random input for AI
             bValidMove = true; // Pretend AI valid move

             // AI Hard Mode code
           // DEFENSIVE Mode
            if (cSquare4 == 'X' && cSquare7 == 'X') {
                 AiMove = 1;
           } else if (cSquare5 == 'X' && cSquare9 == 'X') {
                 AiMove = 1;
           } else if (cSquare2 == 'X' && cSquare3 == 'X') {
                 AiMove = 1;
           } else if (cSquare5 == 'X' && cSquare8 == 'X') {
                 AiMove = 2;
           } else if (cSquare1 == 'X' && cSquare3 == 'X') {
                 AiMove = 2;
           } else if (cSquare1 == 'X' && cSquare2 == 'X') {
                 AiMove = 3;
           } else if (cSquare5 == 'X' && cSquare7 == 'X') {
                 AiMove = 3;
           } else if (cSquare6 == 'X' && cSquare9 == 'X') {
                 AiMove = 3;
           } else if (cSquare5 == 'X' && cSquare6 == 'X') {
                 AiMove = 4;
           } else if (cSquare1 == 'X' && cSquare7 == 'X') {
                 AiMove = 4;
           } else if (cSquare1 == 'X' && cSquare9 == 'X') {
                 AiMove = 5;
           } else if (cSquare2 == 'X' && cSquare8 == 'X') {
                 AiMove = 5;
           } else if (cSquare3 == 'X' && cSquare7 == 'X') {
                 AiMove = 5;
           } else if (cSquare4 == 'X' && cSquare6 == 'X') {
                 AiMove = 5;
           } else if (cSquare3 == 'X' && cSquare9 == 'X') {
                 AiMove = 6;
           } else if (cSquare4 == 'X' && cSquare5 == 'X') {
                 AiMove = 6;
           } else if (cSquare3 == 'X' && cSquare5 == 'X') {
                 AiMove = 7;
           } else if (cSquare1 == 'X' && cSquare4 == 'X') {
                 AiMove = 7;
           } else if (cSquare8 == 'X' && cSquare9 == 'X') {
                 AiMove = 7;
           } else if (cSquare7 == 'X' && cSquare9 == 'X') {
                 AiMove = 8;
           } else if (cSquare2 == 'X' && cSquare5 == 'X') {
                 AiMove = 8;
           } else if (cSquare3 == 'X' && cSquare6 == 'X') {
                 AiMove = 9;
           } else if (cSquare7 == 'X' && cSquare8 == 'X') {
                 AiMove = 9;
           } else if (cSquare1 == 'X' && cSquare5 == 'X') {
                 AiMove = 9;
           }
          else // WHY THIS THING DID NOT WORK(this else) ? I know that the computer will never reach this section, because the loop
              AiMove = rand() % 9 + 1;                     // start at line 77th and will execute the invalid move again
                                                           // but how can I solve this matter ? 

            // After the AI input her command, store it in Mark, also check for it's validation below 
            if ( AiMove == 1 && cSquare1 == '1') {
              cSquare1 = Mark;
           } else if ( AiMove == 2 && cSquare2 == '2') {
              cSquare2 = Mark;
           } else if ( AiMove == 3 && cSquare3 == '3') {
              cSquare3 = Mark;
           } else if ( AiMove == 4 && cSquare4 == '4') {
              cSquare4 = Mark;
           } else if ( AiMove == 5 && cSquare5 == '5') {
              cSquare5 = Mark;
           } else if ( AiMove == 6 && cSquare6 == '6') {
              cSquare6 = Mark;
           } else if ( AiMove == 7 && cSquare7 == '7') {
              cSquare7 = Mark;
           } else if ( AiMove == 8 && cSquare8 == '8') {
              cSquare8 = Mark;
           } else if ( AiMove == 9 && cSquare9 == '9') {
              cSquare9 = Mark;
           } else {
				bValidMove = false; }
                    cout << "                     This is AI choice >> " <<  AiMove << endl; getch(); // This is for checking purpose
           } while (!bValidMove); // Loop until AI input valid                                        // to see what move AI chose
         }                                                                                            // sometimes repeating, indicated that 
                                                                                                      // first move is invalid.
		bGameOver		= false; // Pretend the game is not over yet                                  // just press enter
		bool bWinGame	= true;

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
		// Check for end of game conditions
		if (cSquare1 != '1') {
			if (cSquare2 == cSquare1 && cSquare3 == cSquare1) {
				bGameOver = true;
			}
			if (cSquare4 == cSquare1 && cSquare7 == cSquare1) {
				bGameOver = true;
			}
		}
		if (cSquare5 != '5') {
			if (cSquare1 == cSquare5 && cSquare9 == cSquare5) {
				bGameOver = true;
			}
			if (cSquare2 == cSquare5 && cSquare8 == cSquare5) {
				bGameOver = true;
			}
			if (cSquare4 == cSquare5 && cSquare6 == cSquare5) {
				bGameOver = true;
			}
			if (cSquare3 == cSquare5 && cSquare7 == cSquare5) {
				bGameOver = true;
			}
		}
		if (cSquare9 != '9') {
			if (cSquare3 == cSquare9 && cSquare6 == cSquare9) {
				bGameOver = true;
			}
			if (cSquare7 == cSquare9 && cSquare8 == cSquare9) {
				bGameOver = true;
			}
		}
		// Need to check the board full (no-win condition)
		if (cSquare1 != '1' && cSquare2 != '2' && cSquare3 != '3' &&
			cSquare4 != '4' && cSquare5 != '5' && cSquare6 != '6' &&
			cSquare7 != '7' && cSquare8 != '8' && cSquare9 != '9' && !bGameOver) // If board full then this executed
		{
			bGameOver = true; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  // Game Over with no one win
			bWinGame = false; // >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Game OVER !!
		}

        if (bGameOver) { // Game is over and tell who wins.
			if (bWinGame == 1 && Turn == 1) { // if the game is over in turn 1, then player wins.
				cout << "\nYou" << " wins!" << endl << endl;
			}   else if (bWinGame == 1&& Turn == 2) { // if the game is over in turn != 1 or Turn 2, AI wins.
                cout << "\nAI wins! " << endl << endl;
			}
			// Print ending board
			cout << cSquare1 << "|" << cSquare2 << "|" << cSquare3 << endl;
			cout << "-+-+-"<< endl;
			cout << cSquare4 << "|" << cSquare5 << "|" << cSquare6 << endl;
			cout << "-+-+-"<< endl;
			cout << cSquare7 << "|" << cSquare8 << "|" << cSquare9 << endl;

			cout << "Game Over!" << endl;
			cout << "Play again (y/n)?: "; // Ask player to play again or not.
			char cPlayAgain;
            cin >> cPlayAgain;

			if (cPlayAgain == 'y') {
				bGameOver = false;
				// Clear the board
				cSquare1 = '1';
				cSquare2 = '2';
				cSquare3 = '3';
				cSquare4 = '4';
				cSquare5 = '5';
				cSquare6 = '6';
				cSquare7 = '7';
				cSquare8 = '8';
				cSquare9 = '9';
			}
			Turn = 1;
		} else {
			// Alternate player turns also inform that if Turn != 1 so it means Turn = 2 which is responsible in tell the player who wins
			if (Turn == 1) {                               
				Turn = 2;
			} else {
				Turn = 1;
			}
		}
	} while (!bGameOver);
    cout << "\nThank you for playing with stupid AI."; getch(); // I believe the stupid here is me.
return 0;
}



First I know this code is very big, But I have give very detailed comment so a very beginner will easy to understand this code, secondly you will notice that I don't use any array. So please read it first slowly(if you still don not want to read it, then don't and jump to my last comment in this topic). Or you can just go to line 131st I believe that's the main problem(or not).
Now the problem is if AI input invalid command and do the loop, the computer will start at line 75th, thus input that invalid command again, and then loop again and do the same thing forever, for example, I input 3 and then the AI input 6, now I input 5, The AI block me and input 7, next I input 2 so I have a 2 X row which is 3 and 2(If I input 1 in the my next turn I will win), but for the AI, instead defending and block square 1, she insist to input 7 although she have already block it before, this make her input invalid, hence the program will loop and order the AI to input her move again, but she do the bad ass input which is 7 again, this become an infinite loop of invalid(For the easy understand, just copy paste this code into your IDE and run it, you will understand very quick).
One thing that makes me very confused is, take a look at line 77th, there is srand(time(NULL)), If I move this thing to the line 131th, exactly just before rand() % 9+1; the whole AI defensive system code will be skipped(or not recognized) by the program, thus the AI will input perfectly random number, it just become the stupid AI like the level 2 stars modified.

I have search everywhere for this problem but cannot find the answer, of course there are many guide in making Tic Tac Toe versus AI, but they all using array at least one, in my case I want to fix this without any array,
The question is, is there any one willing to help me solve/fix my algorithm ?
you can try to play with it for a while, maybe you know something that I missed(perhaps very basic like I must add another if else i.e if the AI have blocked square 7 she should not pick number 7 again ? But I believe this is not efficient).
Anyway, I appreciate it very much, thank you.

P.S : If you suggest me to use array then go for it, so I know that it's actually impossible to make Tic Tac Toe AI defensive version without array(But I finished making Tic Tac Toe with stupid AI that input random number without any array, and work perfect)


Last edited on
Still need help here, any one ??
Okay I simplify this problem to a question,
how can I make the AI to put random number after she input invalid number ?
i.e The AI put number 7 and it is an invalid, and then the loop is working and the AI must input a number again, however the problem is she won't put any number beside 7(which is the invalid number she was chose)
of course I had used the rand() and srand, but it's more like it didn't work,
and the worst is I encounter this silly problem in my dungeon crawl to, when the AI move to a space where it is invalid, the loop is working and make her to pick a move again and she do her work good(which is put that invalid move again) despite I have used that srand and rand()..
It's because you are calling srand() in a loop.
Place the call to srand() somewhere before the loop - maybe the very first line.
Yeah I figure it already, but the problem is when I move the srand() to another place, let's say outside of the loop, it's working and the AI will not stuck with her invalid move, but the new problem is coming, the AI is becoming stupid again, and just make a random movement(ignore the defensive system code that I made). I had messing about with this all day, but I can't get the nice result..
Maybe if you have some spare time can you try to play with my code for a while ?
But regardless anything I thank you for your reply..
closed account (iAk3T05o)
You're using char Turn = 1 instead of int Turn = 1.
Thanks Nathan for mentioning me about that, however after I changed it to int it does not make any difference at all with the AI thing..
wew.. I think I have a headache now.. hahaha..
Wew, still no progress in here, anyone can help me ? to be honest you, if you want to help but then cancel your intentions because some reason(maybe annoyed by my large code) just copy paste my code and run it, you will know the problem and I have pointed out where's and what is the problem.. so you don't really need to read it one by one and study it, it's not about syntax error, it's about the algortyhm, Many thanks for those who have replied me..
But really I'm still stuck..
The main problem is the AI won't change move after block my 2 X pattern, i.e I have X in square 1 and square 2, then the AI block the square 3, then I put X in square 4, instead defending the square 7, the AI input her move to block square 3 again, which is an invalid command, thus the loop is working and ordering her to input another move, but she is insisting to input 3, and of course it's invalid command, and the loop working again, and same thing happened, again and again, hence it becomes infinite loop of invalid command by the AI.


Your problem is this:

Let's say I have two X's - on square1 and square2. Now it's the AI's turn, and it will play on square3.

Now I put another X somewhere else. The reason that the computer will insist on square3 is because you're telling it to. Infact, the same thing should happen if you played your X's in different squares - just then the computer wouldn't want to play on square3 necessarily.

What do I mean? This:

1
2
3
4
5
6
           } else if (cSquare1 == 'X' && cSquare2 == 'X') {
                 AiMove = 3;
           } else if (cSquare5 == 'X' && cSquare7 == 'X') {
                 AiMove = 3;
           } else if (cSquare6 == 'X' && cSquare9 == 'X') {
                 AiMove = 3;

This is a snippet extracted from your code. If squares 1 and 2 have X's on them, the computer will always be forced to play on square 3. Squares 1 and 2 will have X's on them even after you've put them there, or even after the computer makes a move. They are there permanently, and remain unchanged. As soon as the program gets to the point where it checks whether squares 1 and 2 are occupied by X's, it'll set AiMove to 3. Since that move is invalid, and the loop only exits when the move is valid, the program runs indefinitely.

Example:


[ ][ ][ ]
[ ][ ][ ]
[ ][ ][ ]


Do squares 1 and 2 have X's in them?
No


[X][ ][ ]
[ ][ ][ ]
[ ][ ][ ]


Do squares 1 and 2 have X's in them?
No, just 1.


[X][X][ ]
[ ][ ][ ]
[ ][ ][ ]

Do squares 1 and 2 have X's in them?
Yes, play 3.


[X][X][O]
[ ][ ][ ]
[ ][ ][ ]





[X][X][O]
[X][ ][ ]
[ ][ ][ ]

Do squares 1 and 2 have X's in them?
Yes, play 3.
Last edited on
Yeah I've know it already, and that's why I need help from someone to help me fix this thing, I have messing with this code for 3 days and the progress is nothing,

Aside from that I have put this silly question in my comment above :
One thing that makes me very confused is, take a look at line 77th(the first part code), there is srand(time(NULL)), If I move this thing to the line 131st, exactly just before rand() % 9+1; the whole AI defensive system code will be skipped(or not recognized) by the program, thus the AI will input perfectly random number, it just become the stupid AI like the level 2 stars modified. I know that this shouldn't related to the AI move, because
1
2
 else if (cSquare1 == 'X' && cSquare2 == 'X') {
                 AiMove = 3;
is in line 92 exactly line 92(and the whole defensive AI code) comes first than line 131, but why the computer ignore it and put random movement even after I have 2 X in a row which mean defensive mode should be working ?. (I have a big headache)

to be honest right now I have added some code in now the AI work like this :
1. I input 1
2. AI input 6(example from random move)
3 I input 4(two X in a row)
4 AI block and input 7(yes the defensive mode work)
5 I input 2(two X in a row)
6. AI put random movement(The AI defensive mode just work once, and after that the move is perfectly random until the game over either with a draw or I win(or accidentaly the AI win)
7. Yes this code is working fine now, and the AI will not input infinite invalid move, and I think I close this case and make this one a medium difficulty AI because the AI only block the first time player got 2 row of X and then the AI will input perfect random after that.

If there is anyone who still curious about this matter, feel free to try meesing with my code above,
For all who read, comment and give suggestion I appreciate it very much and thank you.

I don't know why you would put srand() to line 131. Can you tell me why?
The reason for the behavior you've described probably has to do with the lack of braces around the else on line 131. If you don't provide braces, the else will only execute the one line of code following it, which means AiMove will always be overwritten.
Haha that's it why I call it a silly question :p LOL.. As I said I was playing mess with this code and put that srand() thing over there(line 131), and suddenly it's get my attention because the behaviour I mentioned earlier (defensive mode is skipped), it's not really that matter, because even if the defensive mode is not skipped, it still do the bad infinite invalid move.. Haha really a silly question from me.. Thanks for mentioning me about the braces, it looks like you're right, I should put brace after else.. Thanks xismn..
Topic archived. No new replies allowed.