An efficient approach to TicTacToe AI?

• 01-10-2011
xofvc4rqb
An efficient approach to TicTacToe AI?
Some time ago I made a little Tic Tac Toe game with my beginner knowledge just to practice my current skills. However, recently I decided to improve it and go for another approach on the AI part because the first version analyzed EVERY possible move with lots of if conditions (and that resulted in, like, a ~200 lines function)... Of course now I understand that was very inefficient and I searched for some ways on the site to remake it but only found raw data with no examples on stuff like the Minimax Tree, where all the possible moves were linked to each other. Can someone instruct me with examples or at least some info from where I can start reading and experimenting?
• 01-10-2011
GReaper
Just follow the usual steps when you play tictactoe.
• 01-10-2011
xofvc4rqb
I know that, I just don't know how to link my steps with each other in a code...
I was thinking of making a counter-defense way of thinking for the AI - analyze horizontally, diagonally and vertically if there are two of the player's marks ('x'/'o') and put a counter-move to that ('o'/'x') but if there are none - play offensively. But I think that would also require lots of ifs and loops (the defensive part). I would also have to take into account the tricky moves where you put the opponent in a "fork" where I have two places to put my mark that are a winning situation. Something like this:

(ugh, spaces seem to be ignored so I put _ instead

-------------
| x | _ | x |
| _ | o | _ |
| x | _ | o |
-------------
• 01-10-2011
laserlight
Quote:

Originally Posted by xofvc4rqb
I searched for some ways on the site to remake it but only found raw data with no examples on stuff like the Minimax Tree, where all the possible moves were linked to each other. Can someone instruct me with examples or at least some info from where I can start reading and experimenting?

A quick search brings up this article on Game Trees.

Quote:

Originally Posted by xofvc4rqb
I was thinking of making a counter-defense way of thinking for the AI - analyze horizontally, diagonally and vertically if there are two of the player's marks ('x'/'o') and put a counter-move to that ('o'/'x') but if there are none - play offensively. But I think that would also require lots of ifs and loops (the defensive part). I would also have to take into account the tricky moves where you put the opponent in a "fork" where I have two places to put my mark that are a winning situation.

If you want to go this route instead then making use of some simple opening rules can help a great deal, e.g., "if the opponent starts at the centre, respond at a corner", "if the opponent starts at a corner, respond at the centre", "if the opponent starts at a side, respond anywhere except the tiles diagonal to the start and the far corners from the start".

Quote:

Originally Posted by xofvc4rqb
spaces seem to be ignored so I put _ instead

Besides code, you can post such examples in bbcode tags.
• 01-10-2011
anon
If I remember correctly, the simplest Tic-Tac-Toe AI that never loses needn't do more than
1) check for instant victory;
2) else check if opponent needs to be blocked (you could use the same function as for the previous);
3) else choose the location that belongs to the greatest number of lines which would still lead to your win (except when player marked a corner at the first move, in which case marking the centre square would lead to loss). The first move might be random to give more variety (otherwise marking the centre would always give best chances on first move).
• 01-10-2011
laserlight
Quote:

Originally Posted by anon
3) else choose the location that belongs to the greatest number of lines which would still lead to your win (except when player marked a corner at the first move, in which case marking the centre square would lead to loss). The first move might be random to give more variety (otherwise marking the centre would always give best chances on first move).

I suspect that you did not remember this rule correctly. For one thing, the exception obviously wrong: if the first player starts in the corner, the second player must respond in the centre, or a forced win ensues for the first player with best play.

The rule itself sounds like it can allow a loss. For example, supposing that tiles are numbered as such:
0 1 2
3 4 5
6 7 8
A game starting with 462 leaves the possibilities of 0, 3, 7 and 8, all of which "belongs to the greatest number of lines which would still lead to your win", assuming "you" are the second player. However, playing 3 or 7 is suicide, e.g., 46230 and the second player cannot block both 1 and 8 with just one move.

Note that by "lines" I am assuming that you are talking about 3 consecutive tiles arranged horizontally, vertically or diagonally, not "move variations".
• 01-10-2011
MattJ812
If you have sorted out the strategy and are working on simplfying your code, then ignore this, I'm a newb to coding and especially C++ but I have done this in gamemaker so I thought Id try to help.

To win in tic tac toe you have to create the most possible chances that you can fork your opponent (create two chances of winning). This is actually harder (or was for me) than it sounds.

With any play there are resulting squares that are "safe" and those that are not.

I found an image before that illustrated this but I can't find it now, the closest I have come is...

How to Win at Tic Tac Toe: 4 steps (with video) - wikiHow

I had the AI check its moves square by square and resulting moves and squares to see if there was any chance to be forked, is so then do not play on that square. More aggresively, to check how many resulting squares leave the opponent less chances to play safe.

For instance, if the computer has the first move, playing a corner is the best choice, every other square besides the center is unsafe, you can force a fork.
If the first move is in the center, only the corners are safe, and if the first move is on the edge only the 2 adjacent corners and the middle and opposite square is safe.

This gets complicated so the visual aid was great, but you can work through the moves to see which squares can result in a fork.

What I did was compute the moves, checking each time how many chances to win the opponent had, if after any number of moves the player could fork then the original tested square wasn't safe.

I think I did this by temporarily placing the computer on a square, then test every other available sqaure by putting the player there, and so on and so forth. Each time testing how many chances the player had to win.

Rudamently speaking...

Code:

```if (Square1 == Player && Square2 == Player && Square3 == noone) then chances_to_win += 1; if (Square1 == Player && Square4 == Player && Square7 == noone) then chances_to_win +=1;```
However you get to chances_to_win > 1 the original tested square is unsafe.

This may not be the most economic way to do this, but I feel the computer had to test resulting moves, rather than checking combination upon combination of moves.
• 01-11-2011
laserlight
Quote:

Originally Posted by MattJ812
What I did was compute the moves, checking each time how many chances to win the opponent had, if after any number of moves the player could fork then the original tested square wasn't safe.

I think I did this by temporarily placing the computer on a square, then test every other available sqaure by putting the player there, and so on and so forth. Each time testing how many chances the player had to win.

Essentially, it sounds like you stumbled upon a version of minimax, where you use "how many chances to win the opponent had" as the evaluation function.
• 01-11-2011
xofvc4rqb
Thanks for the replies!
I haven't had free time so I just quickly ran through the posts but I considered most of the things mentioned.

Here's a little code I was able to write, which checks the board's columns, rows and the two diagonals if there are places where it can put a block for the opposing player. The only thing I haven't added is checking whether the two squares are owned by the opponent but I was debugging it. I've also been thinking of making a way to prevent checks on fully filled rows/cols but no effect for now.

Code:

```// CHARS[] is the board itself (it starts from 1-9 not 0-8 because the game // will be played with NumPad and it's easier to represent it like that) // iCount keeps track of the filled squares // iEmpty is there to point which square is empty and to be filled as a counter-move int VerticalCheck() {     int iStart, iLoop = 1, iCount = 0, iEmpty = 0, iFinal = 0, iStep = 3, iTimesLoop = 3;     while (iLoop <= iTimesLoop)     {         iStart = iLoop;         iFinal = iStart + 2 * iStep;         while (iStart <= iFinal)         {             if (CHARS[iStart] != NULL)                 iCount++;             else                 iEmpty = iStart;             iStart += iStep;         }         if (iCount == 2)             return (iEmpty);         iLoop++;         iCount = 0;     }     return 0; } int HorizontalCheck() {     int iStart = 1, iLoop = 1, iCount = 0, iEmpty = 0, iFinal = 0, iStep = 1, iTimesLoop = 3;     while (iLoop <= iTimesLoop)     {         iFinal = iStart + 2 * iStep;         while (iStart <= iFinal)         {             if (CHARS[iStart] != NULL)                 iCount++;             else                 iEmpty = iStart;             iStart += iStep;         }         if (iCount == 2)             return (iEmpty);         iLoop++;         if (iLoop == 2)             iStart = 4;         else             iStart = 7;         iCount = 0;     }     return 0; } int DiagonalCheck(int iStart, int iStep, int iFinal) {     int iCount = 0, iEmpty = 0;     while (iStart <= iFinal)     {         if (CHARS[iStart] != NULL)             iCount++;         else             iEmpty = iStart;         iStart += iStep;     }     if (iCount == 2)         return (iEmpty);     return 0; } int main() {     int result = 0;     DrawBox();     result = VerticalCheck();     cout<<result <<endl;     result = HorizontalCheck();     cout<<result <<endl;     result = DiagonalCheck(1, 4, 9);     cout<<result<<endl;     result = DiagonalCheck(3, 2, 7);     cout<<result<<endl;     cin.get();     return 0; }```
Actually, all the functions return the square which is empty and should be filled to block the opponent.
I also thought that this should be called right on the 4th turn if the AI is the first player since before that you can't have a threat of 2 squares and the 3rd one being empty.
So all the other counter-moves/starting moves should be considered in the beginning (the ones you mentioned as "if you start at the center, answer at corners, etc").
The problem is, I can't understand how to make the AI think moves ahead - what it's doing right now is computing AT the moment and thus having no real tactical approach to the problem.. :|
• 01-14-2011
MattJ812
I don't know if I can help you much seeing as I am only learning programming and although I have done this game in Gamemaker it is very badly coded. I won't waste time with examples of my code you'll probably get lost but I'll try and help with the process.

In a nut shell...

My main AI script creates an array, and starts a for loop checking every square.
If the square is occupied then it will ignore it, if not it will temporarily put the computer on that square.

I created a temporary array, that held the new information as to leave the original array unchanged. I link to a script to check if the computer wins by playing that square (if square 1(temp) and 2 and 3 == computer then he wins) if so, create another array (i know) to hold the number of the square in question and to also keep count of the number of possible squares the computer can win on..... I did this after to eliminate monotony, if the computer can win on 2 or more squares hopefully it won't always be the same one.

After that I check to see if the square will block an opponent(winning is better than blocking right). I do this by checking combinations in one script with 1 argument. The argument passed in is the square I am checking for the computer so for instance if I am checking the computer for square 1 (the 1st iteration of the for loop) I will ask 3 questions....

Does the player have squares 2 and 3 (remember square 1 has to be empty or it wouldn't be checking it) if so simply return true and set a "block" variable to 1.
The other 2 questions are: does the player have squares 4 and 7, or 5 and 9.

Corner squares have 3 chances to win, sides have 2 and the center has 4 but will never get 4, I think 3 is possible tho.

Now onto the horrible part, I think this is techinally called recursion? or similar to it but I couldn't figure that out and had to create more temporary arrays and more scripts that do the same thing. But in essence all it does is take the original square and link to a position checking script(which i had to create 4).

If I am checking the empty square 1, I will check if either square 2 or 3 is mine, if so we have a winning chance next move, if I also hold either square 4 or 7 I have another chance to win, so square 1 would be a forking square.

The return value of this script (well its actually a variable) is how many chances to win there are from that square on this move. Based on that info I will check that variable, if the variable is greater than 1 then this square is gonna win next move. If there is only one winning chance I have to force the player temporarily into playing the blocking square (again a return variable from the previous script) then check the temporaries again. If there are no winning moves from playing that square(first few moves of the game) I set off a for loop for the player in another script that does the same thing and if at any time during this recursion the player can forceably win more than once then it was orginally a bad move.

This basically checks square by square, move by move which squares can fork the player either by force or freely by forcing the player to block your move. I stored this data in an array as it recursed, a value of 10 being a forking square, either right now or forceably down the line, a value of -1 if the player can fork, again either freely or forceably. I only did this to add to randomization, if I can fork twice I don't want to pick the same everytime.

Ultimately this leads to the computer picking (I think, i had different versions) the square that leads to the most possible chances of winning more than once in a move and will always avoid a square that will lead to losing. I also messed with switching it up to pick any square that wasn't gonna lose but wasn't as impressive.

Ah, in short, check square by square, if its occupied then move on , if not then temporarily place the computer there, check if it wins, check it blocks, check winning chances on that square, if more than 2 great!, if 1 then put the player on the blocked and check players move etc, if 0 check the players moves square by square and so on.

Remember using all moves there are only 9 so there isn't that much to check, I used I think 3 scripts if there were no winning moves, forced moves are easy coz you just put the opponent in the blocking square. I had 4 temporary arrays because I wanted to undo each succesive recursion but not all of them dependant on the outcome. I know that doesn't make sense but say its the first move, I temporarily put the computer in square 1, then I temporarily put the player in sqaure two... say this didn't work out(it will), I now want to put the player's first move in square 3 so I undo everything up to the first temporary computer move and check what happens if the player had played in square 3.

You could, if you want make it much simpler but just picking the first good move you come across but that seemed to boring, I wanted the computer to act as if he was human and to mix it up a little bit.

I hope this helps some, if you want to check my gamemaker scripts you are welcome.
• 01-15-2011
xofvc4rqb
Thanks for the info! Yes, I'd love to check someone else's source code to actually see what has been done because currently it's a little hard for me to imagine the way it looks.
So, the priority of executions should be like this as it follows, I guess: check for winning move, check for a blocking move, plan a fork/just normal move, play a move but consider enemy forks.
Due to lack of time I haven't worked a lot but I'll surely put my finished code when I'm done just for some advice/feedback.
Btw, are there any spoiler tags or something like that?
• 01-15-2011
MattJ812
Code:

```/////////////segment of start up script ////////////// tile[0] = "noone" tile[1] = "noone" tile[2] = "noone" tile[3] = "noone" tile[4] = "noone" tile[5] = "noone" tile[6] = "noone" tile[7] = "noone" tile[8] = "noone" tile[9] = "noone"```
Code:

```//////////////// scr_expert ////////////////// //Create an array to store how many dangerous squares can be created for the player num_dan[1] = 0; num_dan[2] = 0; num_dan[3] = 0; num_dan[4] = 0; num_dan[5] = 0; num_dan[6] = 0; num_dan[7] = 0; num_dan[8] = 0; num_dan[9] = 0; cwt = 0; block = 0; for(i = 1; i < 10; i += 1;) // check every square {     if tile[i] != "noone"  //if occupied then ignore it     {          num_dan[i] = -1;         continue;     }     tile[i] = "computer";             if script_execute(scr_win_check_com) == true // check computer winning here     {         tile[i] = "noone";         com_win_tile[cwt] = i;         cwt += 1;         num_dan[i] = -1;         continue;     }     tile[i] = "noone";             if script_execute(scr_block_check,i) == true //check computer having to block here     {         block = 1;         num_dan[i] = -1;         continue;     }             script_execute(scr_most_dan,i); // check all other moves } if (cwt) // Select random winning move if there is one {     rand = floor(random(cwt));     script_execute(scr_com_take,com_win_tile[rand]);     exit; } if (block) // Select blocking move if there is one {     script_execute(scr_com_take,block);     exit; } most_dangerous = 0; ttt = 0; // Check the num_dan array to see which square choice leads to most dangerous squares for the player for(i = 1; i < 10; i += 1;) {     if (num_dan[i] > most_dangerous)     {         most_dangerous = num_dan[i];     } } // Check if there is more than one square creating the same number of dangerous squares   for(i = 1; i < 10; i += 1;) {     if (num_dan[i] == most_dangerous)     {         tile_choice[ttt] = i;         ttt += 1;     } } // randomly select the square leading to the most dangerous outcome.   rand = floor(random(ttt)); script_execute(scr_com_take,tile_choice[rand]);```
Code:

```///////////////// scr_win_check_com //////////////// if tile[1] == "computer" && tile[2] == "computer" && tile[3] == "computer" {     return true;     exit; } if tile[4] == "computer" && tile[5] == "computer" && tile[6] == "computer" {     return true;     exit; } if tile[7] == "computer" && tile[8] == "computer" && tile[9] == "computer" {     return true;     exit; } if tile[1] == "computer" && tile[4] == "computer" && tile[7] == "computer" {     return true;     exit; } if tile[2] == "computer" && tile[5] == "computer" && tile[8] == "computer" {     return true;     exit; } if tile[3] == "computer" && tile[6] == "computer" && tile[9] == "computer" {     return true;     exit; } if tile[1] == "computer" && tile[5] == "computer" && tile[9] == "computer" {     return true;     exit; } if tile[3] == "computer" && tile[5] == "computer" && tile[7] == "computer" {     return true;     exit; } return false;```
Code:

```//////////////// scr_block_check ///////////////////// // check winning combinations that may involve the square in question... // corners (1,3,7,9) have 3 combinations, sides(2,4,6,8) have 2, and centre(5) has 4. tile_to_check = argument0; if tile_to_check == 1 {     if (tile[2] == "player" && tile[3] == "player")     {         return true;         exit;     }     if (tile[4] == "player" && tile[7] == "player")     {         return true;         exit;     }     if (tile[5] == "player" && tile[9] == "player")     {         return true;         exit;     } } // .... other square checks here... \\ return false;```

Code:

```//////////////// scr_most_dan //////////////////// script_execute(scr_tt1_upd); next_tile = argument0 test_tile_1[next_tile] = "computer"; script_execute(scr_com_wc_1,next_tile); if wincha > 1 {     //return true;     num_dan[next_tile] = 10;     exit; } else if wincha == 1 {     test_tile_1[win_chances[0]] = "player";     script_execute(scr_pl_wc_1,win_chances[0]);     if wincha > 1     {         num_dan[argument0] = -1;         exit;     }     else     if wincha == 1     {         test_tile_1[win_chances[0]] = "computer"         script_execute(scr_com_wc_1,win_chances[0]);         if wincha > 1         {             num_dan[argument0] = 10;             exit;         }         else         if wincha == 1         {             test_tile_1[win_chances[0]] = "player"             script_execute(scr_pl_wc_1,win_chances[0]);             if wincha > 1             {                 num_dan[argument0] = -1;                 exit;             }             else             if wincha == 1             {                 test_tile_1[win_chances[0]] = "computer"                 script_execute(scr_com_wc_1,win_chances[0]);                 if wincha > 1                 {                     num_dan[argument0] = 10;                     exit;                 }             }             else             if wincha == 0             {                 script_execute(scr_com_mo_2,next_tile)             }         }     }     else     if wincha == 0     {         script_execute(scr_com_mo_2,next_tile)     } } else if wincha == 0 {     script_execute(scr_pl_mo_2,next_tile) }```

Code:

```//////// scr_com_wc_1 /////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_1[2] == "computer" && test_tile_1[3] == "noone") || (test_tile_1[3] == "computer" && test_tile_1[2] == "noone")     {         if test_tile_1[3] == "noone" then win_chances[wincha] = 3;         if test_tile_1[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_1[4] == "computer" && test_tile_1[7] == "noone") || (test_tile_1[7] == "computer" && test_tile_1[4] == "noone")     {         if test_tile_1[4] == "noone" then win_chances[wincha] = 4;         if test_tile_1[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_1[5] == "computer" && test_tile_1[9] == "noone") || (test_tile_1[9] == "computer" && test_tile_1[5] == "noone")     {         if test_tile_1[5] == "noone" then win_chances[wincha] = 5;         if test_tile_1[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```//////// scr_com_wc_2 /////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_2[2] == "computer" && test_tile_2[3] == "noone") || (test_tile_2[3] == "computer" && test_tile_2[2] == "noone")     {         if test_tile_2[3] == "noone" then win_chances[wincha] = 3;         if test_tile_2[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_2[4] == "computer" && test_tile_2[7] == "noone") || (test_tile_2[7] == "computer" && test_tile_2[4] == "noone")     {         if test_tile_2[4] == "noone" then win_chances[wincha] = 4;         if test_tile_2[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_2[5] == "computer" && test_tile_2[9] == "noone") || (test_tile_2[9] == "computer" && test_tile_2[5] == "noone")     {         if test_tile_2[5] == "noone" then win_chances[wincha] = 5;         if test_tile_2[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```

Code:

```//////// scr_com_wc_3 /////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_3[2] == "computer" && test_tile_3[3] == "noone") || (test_tile_3[3] == "computer" && test_tile_3[2] == "noone")     {         if test_tile_3[3] == "noone" then win_chances[wincha] = 3;         if test_tile_3[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_3[4] == "computer" && test_tile_3[7] == "noone") || (test_tile_3[7] == "computer" && test_tile_3[4] == "noone")     {         if test_tile_3[4] == "noone" then win_chances[wincha] = 4;         if test_tile_3[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_3[5] == "computer" && test_tile_3[9] == "noone") || (test_tile_3[9] == "computer" && test_tile_3[5] == "noone")     {         if test_tile_3[5] == "noone" then win_chances[wincha] = 5;         if test_tile_3[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```//////// scr_com_wc_4 /////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_4[2] == "computer" && test_tile_4[3] == "noone") || (test_tile_4[3] == "computer" && test_tile_4[2] == "noone")     {         if test_tile_4[3] == "noone" then win_chances[wincha] = 3;         if test_tile_4[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_4[4] == "computer" && test_tile_4[7] == "noone") || (test_tile_4[7] == "computer" && test_tile_4[4] == "noone")     {         if test_tile_4[4] == "noone" then win_chances[wincha] = 4;         if test_tile_4[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_4[5] == "computer" && test_tile_4[9] == "noone") || (test_tile_4[9] == "computer" && test_tile_4[5] == "noone")     {         if test_tile_4[5] == "noone" then win_chances[wincha] = 5;         if test_tile_4[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```//////////////// scr_pl_wc_1 //////////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_1[2] == "player" && test_tile_1[3] == "noone") || (test_tile_1[3] == "player" && test_tile_1[2] == "noone")     {         if test_tile_1[3] == "noone" then win_chances[wincha] = 3;         if test_tile_1[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_1[4] == "player" && test_tile_1[7] == "noone") || (test_tile_1[7] == "player" && test_tile_1[4] == "noone")     {         if test_tile_1[4] == "noone" then win_chances[wincha] = 4;         if test_tile_1[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_1[5] == "player" && test_tile_1[9] == "noone") || (test_tile_1[9] == "player" && test_tile_1[5] == "noone")     {         if test_tile_1[5] == "noone" then win_chances[wincha] = 5;         if test_tile_1[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```///////////// scr_pl_wc_2 //////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_2[2] == "player" && test_tile_2[3] == "noone") || (test_tile_2[3] == "player" && test_tile_2[2] == "noone")     {         if test_tile_2[3] == "noone" then win_chances[wincha] = 3;         if test_tile_2[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_2[4] == "player" && test_tile_2[7] == "noone") || (test_tile_2[7] == "player" && test_tile_2[4] == "noone")     {         if test_tile_2[4] == "noone" then win_chances[wincha] = 4;         if test_tile_2[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_2[5] == "player" && test_tile_2[9] == "noone") || (test_tile_2[9] == "player" && test_tile_2[5] == "noone")     {         if test_tile_2[5] == "noone" then win_chances[wincha] = 5;         if test_tile_2[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```//////////// scr_pl_wc_3 /////////////////// tile_to_check = argument0; wincha = 0; if tile_to_check == 1 {     if (test_tile_3[2] == "player" && test_tile_3[3] == "noone") || (test_tile_3[3] == "player" && test_tile_3[2] == "noone")     {         if test_tile_3[3] == "noone" then win_chances[wincha] = 3;         if test_tile_3[2] == "noone" then win_chances[wincha] = 2;         wincha += 1;     }     if (test_tile_3[4] == "player" && test_tile_3[7] == "noone") || (test_tile_3[7] == "player" && test_tile_3[4] == "noone")     {         if test_tile_3[4] == "noone" then win_chances[wincha] = 4;         if test_tile_3[7] == "noone" then win_chances[wincha] = 7;         wincha += 1;     }     if (test_tile_3[5] == "player" && test_tile_3[9] == "noone") || (test_tile_3[9] == "player" && test_tile_3[5] == "noone")     {         if test_tile_3[5] == "noone" then win_chances[wincha] = 5;         if test_tile_3[9] == "noone" then win_chances[wincha] = 9;         wincha += 1;     } } //.... other squares to check here.....// if wincha > 0 {     return true;     exit; } else {     return false;     exit; }```
Code:

```////////////// scr_pl_mo_2 ////////////////     for(ii = 1; ii < 10; ii += 1;) {     script_execute(scr_tt2_upd);     if test_tile_2[ii] == "noone"     {         test_tile_2[ii] = "player";         script_execute(scr_pl_wc_2,ii);         if wincha > 1         {             num_dan[argument0] = -1;             exit;         }         else         if wincha == 1         {             test_tile_2[win_chances[0]] = "computer"             script_execute(scr_com_wc_2,win_chances[0]);              if wincha > 1             {                 num_dan[argument0] += 1;                 continue;             }             else             if wincha == 1             {                 test_tile_2[win_chances[0]] = "player"                 script_execute(scr_pl_wc_2,win_chances[0]);                 if wincha > 1                 {                     num_dan[argument0] = -1;                     exit;                 }                 else                 if wincha == 1                 {                     test_tile_2[win_chances[0]] = "computer"                     script_execute(scr_com_wc_2,win_chances[0]);                     if wincha == 1                     {                         test_tile_2[win_chances[0]] = "player"                         script_execute(scr_pl_wc_2,win_chances[0]);                         if wincha > 1                         {                             num_dan[argument0] = -1;                             exit;                         }                     }                 }             }             else             if wincha == 0             {                 if script_execute(scr_pl_mo_3) == false                 {                     num_dan[argument0] = -1;                     exit;                 }             }         }         else         if wincha == 0         {             if script_execute(scr_com_mo_3) == true             {                 num_dan[argument0] += 1;                 continue;             }         }     } }```
Code:

```///////////// scr_pl_mo_3 ////////////// for(iii = 1; iii < 10; iii += 1;) {     script_execute(scr_tt3_upd);     if test_tile_3[iii] == "noone"     {         test_tile_3[iii] = "player";         script_execute(scr_pl_wc_3,iii);         if wincha > 1         {             return false;             exit;         }         else         if wincha == 1         {             test_tile_3[win_chances[0]] = "computer"             script_execute(scr_com_wc_3,win_chances[0]);              if wincha == 1             {                 test_tile_3[win_chances[0]] = "player"                 script_execute(scr_pl_wc_3,win_chances[0]);                 if wincha > 1                 {                     return false;                     exit;                 }                 else                 if wincha == 1                 {                     test_tile_3[win_chances[0]] = "computer"                     script_execute(scr_com_wc_3,win_chances[0]);                     if wincha == 1                     {                         test_tile_3[win_chances[0]] = "player"                         script_execute(scr_pl_wc_3,win_chances[0]);                         if wincha > 1                         {                             return false;                             exit;                         }                     }                 }             }             else             if wincha == 0             {                 if script_execute(scr_mo_4) == true                 {                     return true;                     exit;                 }             }         }     } } return true;```
Code:

```//////////////// scr_com_mo_2 ////////////////// for(ii = 1; ii < 10; ii += 1;) {     script_execute(scr_tt2_upd);     if test_tile_2[ii] == "noone"     {         test_tile_2[ii] = "computer";         script_execute(scr_com_wc_2,ii);         if wincha > 1         {             num_dan[argument0] = 10;             exit;         }         else         if wincha == 1         {             test_tile_2[win_chances[0]] = "player"             script_execute(scr_pl_wc_2,win_chances[0]);              if wincha == 1             {                 test_tile_2[win_chances[0]] = "computer"                 script_execute(scr_com_wc_2,win_chances[0]);                 if wincha > 1                 {                     num_dan[argument0] = 10;                     exit;                 }             }             else             if wincha == 0             {                 if script_execute(scr_com_mo_3) == true                 {                     num_dan[argument0] = 10;                     exit;                 }             }         }     } } //nd = 0; //return false;```
Code:

```//////////////// scr_pl_mo_3 /////////////////// for(iii = 1; iii < 10; iii += 1;) {     script_execute(scr_tt3_upd);     if test_tile_3[iii] == "noone"     {         test_tile_3[iii] = "computer";         script_execute(scr_com_wc_3,iii);         if wincha > 1         {             return true;             exit;         }         else         if wincha == 1         {             test_tile_3[win_chances[0]] = "player"             script_execute(scr_pl_wc_3,win_chances[0]);              if wincha == 1             {                 test_tile_3[win_chances[0]] = "computer"                 script_execute(scr_com_wc_3,win_chances[0]);                 if wincha > 1                 {                     return true;                     exit;                 }                 else                 if wincha == 1                 {                     test_tile_3[win_chances[0]] = "player"                     script_execute(scr_pl_wc_3,win_chances[0]);                     //if wincha > 1                   // {                     //    return false;                   //    exit;                   // }                     //else                     if wincha == 1                     {                         test_tile_3[win_chances[0]] = "computer"                         script_execute(scr_com_wc_3,win_chances[0]);                         if wincha > 1                         {                             return true;                             exit;                         }                     }                 }             }             else             if wincha == 0             {                 if script_execute(scr_mo_4) == true                 {                     return true;                     exit;                 }             }         }     } } nd = 0; return false;```
Code:

```//////////// scr_mo_4 //////////////// for(iiii = 1; iiii < 10; iiii += 1;) {     script_execute(scr_tt4_upd);     if test_tile_4[iiii] == "noone"     {         test_tile_4[iiii] = "computer";         script_execute(scr_com_wc_4,iiii);         if wincha > 1         {             return true;             exit;         }     } } return false;```
Code:

```///////// scr_tt1upd ///////////// for(tt_1 = 1; tt_1 < 10; tt_1 += 1;) {     test_tile_1[tt_1] = tile[tt_1] } ////////// scr_tt2upd ///////////// for(tt_2 = 1; tt_2 < 10; tt_2 += 1;) {     test_tile_2[tt_2] = test_tile_1[tt_2] } ////////// scr_tt3upd //////////////// for(tt_3 = 1; tt_3 < 10; tt_3 += 1;) {     test_tile_3[tt_3] = test_tile_2[tt_3] } /////////// scr_tt4upd ////////////// for(tt_4 = 1; tt_4 < 10; tt_4 += 1;) {     test_tile_4[tt_4] = test_tile_3[tt_4] }```