develop free website


Phoenix Dynasty Studio
凤皇朝工作室

Tic Tac Toe
Intelligent Computer Player logic

"There is nothing difficult for us to do in the world. If we do it, the difficult thing will be easy; if we don't, the easy thing will be difficult."
天下事有难易乎,
为之,则难者亦易矣;
不为,则易者亦难矣。

- Peng Duan Shu 彭端叔 -


Project Overview & Design

This topic will guild you through how to build a Tic Tac Toe Intelligent Computer Play logic that will auto assign relevant computer move. In previous Tic Tac Toe tutorial, the final outcome will be 2 players Tic Tac Toe game. So, you might want to add on an additional feature to let player play the game with computer.

The Intelligent Computer Play logic is the continuous development of Tic Tac Toe tutorial. If you had not completed the Tic Tac Toe game development tutorial, please visit below link:

Game Development with Unity:

Tic Tac Toe

Mobirise

Game Development Platform

All of our games are made with Unity.

Unity is a multi-platform comprehensive game development tool developed by Unity Technologies that allows players to easily create interactive content such as video games, real-time animations, etc. It is a fully integrated professional game engine. Unity editor runs under Windows and Mac OS X, and can publish applications to more than 20 platforms such as Windows, Mac, Iphone, Web, Andriod.

To get started, you may download the free version of Unity with below link.

Below are development chapters list



Chapter 1.
Determine Player Turn

When the game start, by default Player will be X and Computer will be O. We need to make the O Panel Text as Button so that when the Player click on it, Player will change side to O and Computer as X.

Click on PlayerO GameObject. Click on Add Component, search for Button component and add to game object. 


Next, open GameControl Scripts, create below public variables. 

SetPlayerToO GameObject variable is to hold PlayerO GameObject. ComputerXFontColor and ComputerOFontColor is to hold and change color for X and O while switch side. 

Now, drag PlayerO GameObject to SetPlayerToO, then set ComputerXFontColor color to blue (43,77,200,225) and ComputerOFontColor to pink (217,3,114,225).


Then in GameControl Scripts, create below private variables. This is for later stage use. 

PlayerValue and ComputerValue variable will hold Player and Computer side through out the whole game. After Player change to O side cannot switch back to X side as the game score count is still counting. Player had to back to main menu then come back to game board again to reset everything. 

While for FirstLevelStep variable, is to hold integer from 0 to 8, this is use to random assign computer step. 

Now, create a ChangeComputerSideToX () public function. This function will switch Computer side to X and Player side to O. 

Assign ChangeComputerSideToX () function to PlayerO GameObject. 

Now, you can save your work and play game. When you check on PlayerO GameObject, you should see the orange box is switch to O but nothing happen after this. As Computer Intelligent Logic still not created. 



Chapter 2.
Check Computer or Player Win Step

Next, let's create a new private function call CheckWinStep () to check win step for Player or Computer. In This function, you will check the Verticle line 1, 2, 3 and Horizontal line 1, 2, 3 and cross line for both / and \. First, you need to check if Computer next step can win the game, else check on player current step and block Player from win on next step. 

Pass in the Player side or Computer Side as parameter. To check Computer win step, then pass in ComputerValue. To block Player win step, then pass in PlayerValue. The return value would be the next step Computer should assign in game board. 

In CheckWinStep () function, there is one additional check to make sure if the Computer is O and it was the O first turn and if the middle Grid box is null, assign the Computer next step to middle Grid box (Grid 4). 

Below the code for CheckWinStep() function. 


   private int CheckWinStep (String WhichSide)
    {
        // Computer Inteligent
        int BlockGrid = -1;
        if (ComputerValue != "X" && PlayCount != 0 && buttonControlList[4].text == "")
        {
            // Computer Inteligent - Check if middle Grid button index 4 and assign
            BlockGrid = 4;
        }
        else
        {
            // Computer Inteligent - Check and assign win step / block win step from win
            // Verticle line 1
            if (buttonControlList[1].text == WhichSide && buttonControlList[2].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[2].text == WhichSide && buttonControlList[1].text == "")
            {
                BlockGrid = 1;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[1].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            // Verticle line 2
            if (buttonControlList[4].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[3].text == "")
            {
                BlockGrid = 3;
            }
            if (buttonControlList[3].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[3].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[5].text == "")
            {
                BlockGrid = 5;
            }
            // Verticle line 3
            if (buttonControlList[7].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
            if (buttonControlList[6].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[7].text == "")
            {
                BlockGrid = 7;
            }
            if (buttonControlList[6].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Horizontal line 1
            if (buttonControlList[3].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[3].text == "")
            {
                BlockGrid = 3;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[3].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
            // Horizontal line 2
            if (buttonControlList[4].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[1].text == "")
            {
                BlockGrid = 1;
            }
            if (buttonControlList[1].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[1].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[7].text == "")
            {
                BlockGrid = 7;
            }
            // Horizontal line 3
            if (buttonControlList[5].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[5].text == "")
            {
                BlockGrid = 5;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Cross line \
            if (buttonControlList[4].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Cross line /
            if (buttonControlList[4].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
        }
        return BlockGrid;
    }

“Time Is Precious And Priceless.”
一寸光阴一寸金,寸金难买寸光阴

– 增广贤文 -



Chapter 3.
Assign Computer Random Step

Lastly is to add in a Update() function. This Update function is called every frame. It will continuous checking your game for any update. Then we will call CheckWinStep () from this function. 

In the Update() function, first it will check if the game end. If EndGame not true, we only proceed the rest of the function. Then check if it is Computer turns. If yes, then call CheckWinStep() function to check on any Computer win step. If no, then call CheckWinStep() function again to check on any Player win step. If no, then we need to proceed to random assign step for Computer move. 

On random number assign, because not every time it will return the grid number which had not assigned. So, we need to have while loop to check if the return grid number is empty grid, then only we quit the loop. Else it will continous loop to get new grid number. 


After we get the grid number, then we will assign it to the grid with correct color. If Computer is X then blue and if Computer is O then pink.


Make the grid interactable to false after assign the grid. Then check on end game, check if there is any winner or game draw. 

Below the final code for GameControl Script. Save the game and play. You should have a computer that will play with you and assign grid automatically now.

Enjoy the game.


using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Linq;
public class GameControl : MonoBehaviour
{
    public Text[] buttonControlList;
    private string playerSide;
    private int PlayCount;
    private Boolean EndGame;
    public GameObject GameStatusPanel;
    public Text GameStatusText;
    public GameObject PlayerXTurnPanel;
    public GameObject PlayerOTurnPanel;
    private int PlayerXScoreCount = 0;
    private int PlayerOScoreCount = 0;
    public Text PlayerXScoreText;
    public Text PlayerOScoreText;
    // Computer Inteligent
    public GameObject SetPlayerToO;
    public Color ComputerXFontColor;
    public Color ComputerOFontColor;
    private string PlayerValue;
    private string ComputerValue;
    private readonly int[] FirstLevelStep = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
    void Awake()
    {
        for (int i = 0; i < buttonControlList.Length; i++)
        {
            // Build the buttonControlList item and reference it to each ButtonControl
            // This will call to ButtonControl Class SetGameControllerReference function to create reference there
            buttonControlList[i].GetComponentInParent<ButtonControl>().SetGameControllerReference(this);
        }
        // Preset the playerSide to X while game Awake
        playerSide = "X";
        // Computer Inteligent - Preset the ComputerValue to O while game Awake
        ComputerValue = "O";
        PlayerValue = "X";
        // Set PlayCount = 0
        PlayCount = 0;
        // Set GameStatusText to blank and inactive GameStatusPanel GameObject
        GameStatusText.text = "";
        GameStatusPanel.SetActive(false);
        // Activate PlayerXTurnPanel & Inactive PlayerOTurnPanel GameObject
        PlayerXTurnPanel.SetActive(true);
        PlayerOTurnPanel.SetActive(false);
    }
    void Update()
    {
        // Computer Inteligent - Auto Assign Computer Value
        if (EndGame != true)
        {
            // Computer Inteligent - Check if computer turns
            if (ComputerValue == playerSide)
            {
                Boolean HaveValue = true;
                int x = -1;
                // Computer Inteligent - Check Computer win step
                if (x < 0)
                {
                    x = CheckWinStep(ComputerValue);
                }
                // Computer Inteligent - Check and block Player win step
                if (x < 0)
                {
                    x = CheckWinStep(PlayerValue);
                }
                // Computer Inteligent - Get ramdon step to assign, cannot duplicate with previous
                if (x < 0)
                {
                    while (HaveValue == true)
                    {
                        x = FirstLevelStep[UnityEngine.Random.Range(0, 9)];
                        if (buttonControlList[x].text == "")
                        {
                            HaveValue = false;
                        }
                    }
                }
                // Computer Inteligent - Assign Grid value with correct color
                if (ComputerValue == "X")
                {
                    buttonControlList[x].color = ComputerXFontColor;
                }
                else if(ComputerValue == "O")
                {
                    buttonControlList[x].color = ComputerOFontColor;
                }
                // Computer Inteligent - Assign Grid value with computer value and make interactable to false
                buttonControlList[x].text = ComputerValue;
                buttonControlList[x].GetComponentInParent<Button>().interactable = false;
                // Computer Inteligent - Check if end game
                CheckEndGame();
            }
        }
    }
    public void ChangeComputerSideToX()
    {
        // Computer Inteligent - While Player choose to be O side
        // Computer Inteligent - Computer will become X
        ComputerValue = "X";
        PlayerValue = "O";
        // Reset the playerSide to initial value X
        playerSide = "X";
        // Reset playCount to 0
        PlayCount = 0;
        EndGame = false;
        PlayerXScoreCount = 0;
        PlayerXScoreText.text = "-";
        PlayerOScoreCount = 0;
        PlayerOScoreText.text = "-";
    }
    public int CheckWinStep (String WhichSide)
    {
        // Computer Inteligent
        int BlockGrid = -1;
        if (ComputerValue != "X" && PlayCount != 0 && buttonControlList[4].text == "")
        {
            // Computer Inteligent - Check if middle Grid button index 4 and assign
            BlockGrid = 4;
        }
        else
        {
            // Computer Inteligent - Check and assign win step / block win step from win
            // Verticle line 1
            if (buttonControlList[1].text == WhichSide && buttonControlList[2].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[2].text == WhichSide && buttonControlList[1].text == "")
            {
                BlockGrid = 1;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[1].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            // Verticle line 2
            if (buttonControlList[4].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[3].text == "")
            {
                BlockGrid = 3;
            }
            if (buttonControlList[3].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[3].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[5].text == "")
            {
                BlockGrid = 5;
            }
            // Verticle line 3
            if (buttonControlList[7].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
            if (buttonControlList[6].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[7].text == "")
            {
                BlockGrid = 7;
            }
            if (buttonControlList[6].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Horizontal line 1
            if (buttonControlList[3].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[3].text == "")
            {
                BlockGrid = 3;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[3].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
            // Horizontal line 2
            if (buttonControlList[4].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[1].text == "")
            {
                BlockGrid = 1;
            }
            if (buttonControlList[1].text == WhichSide && buttonControlList[7].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[1].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[7].text == "")
            {
                BlockGrid = 7;
            }
            // Horizontal line 3
            if (buttonControlList[5].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[5].text == "")
            {
                BlockGrid = 5;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[5].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Cross line \
            if (buttonControlList[4].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[0].text == "")
            {
                BlockGrid = 0;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[8].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[0].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[8].text == "")
            {
                BlockGrid = 8;
            }
            // Cross line /
            if (buttonControlList[4].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[2].text == "")
            {
                BlockGrid = 2;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[6].text == WhichSide && buttonControlList[4].text == "")
            {
                BlockGrid = 4;
            }
            if (buttonControlList[2].text == WhichSide && buttonControlList[4].text == WhichSide && buttonControlList[6].text == "")
            {
                BlockGrid = 6;
            }
        }
        return BlockGrid;
    }
    public string GetPlayerSide()
    {
        // This function determine which playerSide and gridButtonText will based on the return value to display text
        return playerSide;
    }
    public void CheckEndGame()
    {
        // Computer Inteligent - If PlayCount > 0 then Player cannot choose to be O
        if (PlayCount > 0)
        {
            if (ComputerValue == "O")
            {
                SetPlayerToO.GetComponent<Button>().interactable = false;
            }
        }
        // Check all logic and determine if playerSide had got 3 straight match, if yes end the game
        if (buttonControlList[0].text == playerSide && buttonControlList[1].text == playerSide && buttonControlList[2].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[3].text == playerSide && buttonControlList[4].text == playerSide && buttonControlList[5].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[6].text == playerSide && buttonControlList[7].text == playerSide && buttonControlList[8].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[0].text == playerSide && buttonControlList[3].text == playerSide && buttonControlList[6].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[1].text == playerSide && buttonControlList[4].text == playerSide && buttonControlList[7].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[2].text == playerSide && buttonControlList[5].text == playerSide && buttonControlList[8].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[0].text == playerSide && buttonControlList[4].text == playerSide && buttonControlList[8].text == playerSide)
        {
            SetEndGame();
        }
        if (buttonControlList[2].text == playerSide && buttonControlList[4].text == playerSide && buttonControlList[6].text == playerSide)
        {
            SetEndGame();
        }
        if (EndGame != true)
        {
            // Call to ChangePlayerSide function
            ChangePlayerSide();
            // Add PlayCount
            PlayCount++;
            //Check if play count is equal or more than 9, then display Draw Game
            if (PlayCount >= 9)
            {
                DisplayGameStatus("DRAW!");
                EndGame = true;
            }
        }
    }
    void ChangePlayerSide()
    {
        // Check if playerSide = X, set playerSide = O
        // Check if playerSide = O, set playerSide = X
        playerSide = (playerSide == "X") ? "O" : "X";
        if (playerSide == "X")
        {
            // Activate PlayerXTurnPanel & Inactive PlayerOTurnPanel GameObject
            PlayerXTurnPanel.SetActive(true);
            PlayerOTurnPanel.SetActive(false);
        }
        else
        {
            // Inactive PlayerXTurnPanel & Activate PlayerOTurnPanel GameObject
            PlayerXTurnPanel.SetActive(false);
            PlayerOTurnPanel.SetActive(true);
        }
    }
    void SetEndGame()
    {
        // End of Game - Set all buttonControlList to disable
        BoardActivation(false);
        EndGame = true;
        if (playerSide == "X")
        {
            PlayerXScoreCount++;
            PlayerXScoreText.text = PlayerXScoreCount.ToString();
        }
        else
        {
            PlayerOScoreCount++;
            PlayerOScoreText.text = PlayerOScoreCount.ToString();
        }
        DisplayGameStatus(playerSide + "\nWINNER!");
    }
    void DisplayGameStatus(string GameStatus)
    {
        // Set GameStatusText with pass in parameter
        // Set GameStatusPanel visibility to true
        GameStatusText.text = GameStatus;
        GameStatusPanel.SetActive(true);
        // Inactive PlayerXTurnPanel & Inactive PlayerOTurnPanel GameObject
        PlayerXTurnPanel.SetActive(false);
        PlayerOTurnPanel.SetActive(false);
    }
    public void RestartGame()
    {
        // Reset the playerSide to initial value X
        playerSide = "X";
        // Reset playCount to 0
        PlayCount = 0;
        EndGame = false;
        // Computer Inteligent - Preset the ComputerValue to O while game restart
        // Computer Inteligent - O button able to choose by Player
        SetPlayerToO.GetComponent<Button>().interactable = true;
        // Set GameStatusText to blank
        // Set GameStatusPanel visibility to false
        GameStatusPanel.SetActive(false);
        // Inactive PlayerXTurnPanel & Inactive PlayerOTurnPanel GameObject
        PlayerXTurnPanel.SetActive(true);
        PlayerOTurnPanel.SetActive(false);
        // Restart Game - Set all buttonControlList to enable
        BoardActivation(true);
        // Restart Game - Set all buttonControlList text to blank
        for (int i = 0; i < buttonControlList.Length; i++)
        {
            buttonControlList[i].text = "";
        }
    }
    void BoardActivation(bool Status)
    {
        // Set all buttonControlList to enable or disable
        for (int i = 0; i < buttonControlList.Length; i++)
        {
            buttonControlList[i].GetComponentInParent<Button>().interactable = Status;
        }
    }
    public void LoadOtherScene()
    {
        // Go to BoardGame Scene
        SceneManager.LoadScene("MainMenu");
    }
}





CONTACT US

Send us your question and comments.
有问题可以飞鸽传书给我们。

SHARE THIS PAGE!

© Copyright 2020 Phoenix Dynasty Studio - All Rights Reserved