Tic-Tac-Toe AI in C# Unity

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
6
down vote

favorite












So I have a working game of Tic-Tac-Toe with an AI that plays random moves. Is anyway to maybe shorten the endturn() function so it's not so long? Also is this set up well enough to add a mode where the computer plays optimal or sub-optimal moves and a mode impossible to beat?



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[System.Serializable]
public class Player

public Image panel;
public Text text;
public Button button;

[System.Serializable]
public class PlayerColor

public Color panelColor;
public Color textColor;


public class GameController : MonoBehaviour

public Text buttonList;
public GameObject gameOverPanel;
public Text gameOverText;
private string playerSide;
private string computerSide;
private int moveCount;
public GameObject restartButton;
public GameObject startInfo;

public Player playerX;
public Player playerO;
public PlayerColor activePlayerColor;
public PlayerColor inactivePlayerColor;

public bool playerMove;
public float delay;
private int value;

public enum State Null, X, O ;

void Awake()

SetGameControllerReferenceOnButtons();
gameOverPanel.SetActive(false);
moveCount = 0;
restartButton.SetActive(false);
playerMove = true;


public void Update()

if (playerMove == false)

delay += delay * Time.deltaTime;
if (delay >= 100)

value = Random.Range(0, 8);
if (buttonList[value].GetComponentInParent<Button>().interactable == true)

buttonList[value].text = GetComputerSide();
buttonList[value].GetComponentInParent<Button>().interactable = false;
EndTurn();





void SetGameControllerReferenceOnButtons()

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<GridSpace>().SetGameControllerReference(this);



public void SetStartingSide(string startingSide)

playerSide = startingSide;
if(playerSide == "X")

computerSide = "O";
SetPlayerColors(playerX, playerO);

else

computerSide = "X";
SetPlayerColors(playerO, playerX);


StartGame();


void StartGame()

SetBoardInteractable(true);
SetPlayerButtons(false);
startInfo.SetActive(false);


public string GetPlayerSide()

return playerSide;


public string GetComputerSide()

return computerSide;


public void EndTurn()

moveCount++;

for (int i = 0; i < buttonList.Length; i++)

if (buttonList[0].text == playerSide && buttonList[1].text == playerSide && buttonList[2].text == playerSide)

GameOver(playerSide);


else if (buttonList[3].text == playerSide && buttonList[4].text == playerSide && buttonList[5].text == playerSide)

GameOver(playerSide);


else if (buttonList[6].text == playerSide && buttonList[7].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[4].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[4].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[3].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[1].text == playerSide && buttonList[4].text == playerSide && buttonList[7].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[5].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == computerSide && buttonList[1].text == computerSide && buttonList[2].text == computerSide)

GameOver(computerSide);


else if (buttonList[3].text == computerSide && buttonList[4].text == computerSide && buttonList[5].text == computerSide)

GameOver(computerSide);


else if (buttonList[6].text == computerSide && buttonList[7].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[4].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[4].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[3].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[1].text == computerSide && buttonList[4].text == computerSide && buttonList[7].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[5].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;





void ChangeSides()

//playerSide = (playerSide == "X") ? "O" : "X";
playerMove = (playerMove == true) ? false : true;
//if(playerSide == "X")
if(playerMove == true)

SetPlayerColors(playerX, playerO);

else

SetPlayerColors(playerO, playerX);



void SetPlayerColors(Player newPlayer, Player oldPlayer)

newPlayer.panel.color = activePlayerColor.panelColor;
newPlayer.text.color = activePlayerColor.textColor;

oldPlayer.panel.color = inactivePlayerColor.panelColor;
oldPlayer.text.color = inactivePlayerColor.textColor;


void GameOver(string winningPlayer)

SetBoardInteractable(false);
if (winningPlayer == "draw")

SetGameOverText("Draw");
SetPlayerColorsInactive();

else

SetGameOverText(winningPlayer + " wins");

restartButton.SetActive(true);


void SetGameOverText(string value)

gameOverPanel.SetActive(true);
gameOverText.text = value;


public void RestartGame()

moveCount = 0;
gameOverPanel.SetActive(false);
restartButton.SetActive(false);
SetPlayerButtons(true);
startInfo.SetActive(true);
SetPlayerColorsInactive();
playerMove = true;
delay = 10;

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].text = "";



void SetBoardInteractable(bool toggle)

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<Button>().interactable = toggle;



void SetPlayerButtons(bool toggle)

playerX.button.interactable = toggle;
playerO.button.interactable = toggle;


void SetPlayerColorsInactive()

playerX.panel.color = inactivePlayerColor.panelColor;
playerX.text.color = inactivePlayerColor.textColor;
playerO.panel.color = inactivePlayerColor.panelColor;
playerO.panel.color = inactivePlayerColor.textColor;








share|improve this question















  • 1




    Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
    – Hosch250
    Apr 17 at 18:48











  • Is there an example I could go find?
    – Koli
    Apr 17 at 18:54
















up vote
6
down vote

favorite












So I have a working game of Tic-Tac-Toe with an AI that plays random moves. Is anyway to maybe shorten the endturn() function so it's not so long? Also is this set up well enough to add a mode where the computer plays optimal or sub-optimal moves and a mode impossible to beat?



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[System.Serializable]
public class Player

public Image panel;
public Text text;
public Button button;

[System.Serializable]
public class PlayerColor

public Color panelColor;
public Color textColor;


public class GameController : MonoBehaviour

public Text buttonList;
public GameObject gameOverPanel;
public Text gameOverText;
private string playerSide;
private string computerSide;
private int moveCount;
public GameObject restartButton;
public GameObject startInfo;

public Player playerX;
public Player playerO;
public PlayerColor activePlayerColor;
public PlayerColor inactivePlayerColor;

public bool playerMove;
public float delay;
private int value;

public enum State Null, X, O ;

void Awake()

SetGameControllerReferenceOnButtons();
gameOverPanel.SetActive(false);
moveCount = 0;
restartButton.SetActive(false);
playerMove = true;


public void Update()

if (playerMove == false)

delay += delay * Time.deltaTime;
if (delay >= 100)

value = Random.Range(0, 8);
if (buttonList[value].GetComponentInParent<Button>().interactable == true)

buttonList[value].text = GetComputerSide();
buttonList[value].GetComponentInParent<Button>().interactable = false;
EndTurn();





void SetGameControllerReferenceOnButtons()

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<GridSpace>().SetGameControllerReference(this);



public void SetStartingSide(string startingSide)

playerSide = startingSide;
if(playerSide == "X")

computerSide = "O";
SetPlayerColors(playerX, playerO);

else

computerSide = "X";
SetPlayerColors(playerO, playerX);


StartGame();


void StartGame()

SetBoardInteractable(true);
SetPlayerButtons(false);
startInfo.SetActive(false);


public string GetPlayerSide()

return playerSide;


public string GetComputerSide()

return computerSide;


public void EndTurn()

moveCount++;

for (int i = 0; i < buttonList.Length; i++)

if (buttonList[0].text == playerSide && buttonList[1].text == playerSide && buttonList[2].text == playerSide)

GameOver(playerSide);


else if (buttonList[3].text == playerSide && buttonList[4].text == playerSide && buttonList[5].text == playerSide)

GameOver(playerSide);


else if (buttonList[6].text == playerSide && buttonList[7].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[4].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[4].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[3].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[1].text == playerSide && buttonList[4].text == playerSide && buttonList[7].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[5].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == computerSide && buttonList[1].text == computerSide && buttonList[2].text == computerSide)

GameOver(computerSide);


else if (buttonList[3].text == computerSide && buttonList[4].text == computerSide && buttonList[5].text == computerSide)

GameOver(computerSide);


else if (buttonList[6].text == computerSide && buttonList[7].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[4].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[4].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[3].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[1].text == computerSide && buttonList[4].text == computerSide && buttonList[7].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[5].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;





void ChangeSides()

//playerSide = (playerSide == "X") ? "O" : "X";
playerMove = (playerMove == true) ? false : true;
//if(playerSide == "X")
if(playerMove == true)

SetPlayerColors(playerX, playerO);

else

SetPlayerColors(playerO, playerX);



void SetPlayerColors(Player newPlayer, Player oldPlayer)

newPlayer.panel.color = activePlayerColor.panelColor;
newPlayer.text.color = activePlayerColor.textColor;

oldPlayer.panel.color = inactivePlayerColor.panelColor;
oldPlayer.text.color = inactivePlayerColor.textColor;


void GameOver(string winningPlayer)

SetBoardInteractable(false);
if (winningPlayer == "draw")

SetGameOverText("Draw");
SetPlayerColorsInactive();

else

SetGameOverText(winningPlayer + " wins");

restartButton.SetActive(true);


void SetGameOverText(string value)

gameOverPanel.SetActive(true);
gameOverText.text = value;


public void RestartGame()

moveCount = 0;
gameOverPanel.SetActive(false);
restartButton.SetActive(false);
SetPlayerButtons(true);
startInfo.SetActive(true);
SetPlayerColorsInactive();
playerMove = true;
delay = 10;

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].text = "";



void SetBoardInteractable(bool toggle)

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<Button>().interactable = toggle;



void SetPlayerButtons(bool toggle)

playerX.button.interactable = toggle;
playerO.button.interactable = toggle;


void SetPlayerColorsInactive()

playerX.panel.color = inactivePlayerColor.panelColor;
playerX.text.color = inactivePlayerColor.textColor;
playerO.panel.color = inactivePlayerColor.panelColor;
playerO.panel.color = inactivePlayerColor.textColor;








share|improve this question















  • 1




    Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
    – Hosch250
    Apr 17 at 18:48











  • Is there an example I could go find?
    – Koli
    Apr 17 at 18:54












up vote
6
down vote

favorite









up vote
6
down vote

favorite











So I have a working game of Tic-Tac-Toe with an AI that plays random moves. Is anyway to maybe shorten the endturn() function so it's not so long? Also is this set up well enough to add a mode where the computer plays optimal or sub-optimal moves and a mode impossible to beat?



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[System.Serializable]
public class Player

public Image panel;
public Text text;
public Button button;

[System.Serializable]
public class PlayerColor

public Color panelColor;
public Color textColor;


public class GameController : MonoBehaviour

public Text buttonList;
public GameObject gameOverPanel;
public Text gameOverText;
private string playerSide;
private string computerSide;
private int moveCount;
public GameObject restartButton;
public GameObject startInfo;

public Player playerX;
public Player playerO;
public PlayerColor activePlayerColor;
public PlayerColor inactivePlayerColor;

public bool playerMove;
public float delay;
private int value;

public enum State Null, X, O ;

void Awake()

SetGameControllerReferenceOnButtons();
gameOverPanel.SetActive(false);
moveCount = 0;
restartButton.SetActive(false);
playerMove = true;


public void Update()

if (playerMove == false)

delay += delay * Time.deltaTime;
if (delay >= 100)

value = Random.Range(0, 8);
if (buttonList[value].GetComponentInParent<Button>().interactable == true)

buttonList[value].text = GetComputerSide();
buttonList[value].GetComponentInParent<Button>().interactable = false;
EndTurn();





void SetGameControllerReferenceOnButtons()

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<GridSpace>().SetGameControllerReference(this);



public void SetStartingSide(string startingSide)

playerSide = startingSide;
if(playerSide == "X")

computerSide = "O";
SetPlayerColors(playerX, playerO);

else

computerSide = "X";
SetPlayerColors(playerO, playerX);


StartGame();


void StartGame()

SetBoardInteractable(true);
SetPlayerButtons(false);
startInfo.SetActive(false);


public string GetPlayerSide()

return playerSide;


public string GetComputerSide()

return computerSide;


public void EndTurn()

moveCount++;

for (int i = 0; i < buttonList.Length; i++)

if (buttonList[0].text == playerSide && buttonList[1].text == playerSide && buttonList[2].text == playerSide)

GameOver(playerSide);


else if (buttonList[3].text == playerSide && buttonList[4].text == playerSide && buttonList[5].text == playerSide)

GameOver(playerSide);


else if (buttonList[6].text == playerSide && buttonList[7].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[4].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[4].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[3].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[1].text == playerSide && buttonList[4].text == playerSide && buttonList[7].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[5].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == computerSide && buttonList[1].text == computerSide && buttonList[2].text == computerSide)

GameOver(computerSide);


else if (buttonList[3].text == computerSide && buttonList[4].text == computerSide && buttonList[5].text == computerSide)

GameOver(computerSide);


else if (buttonList[6].text == computerSide && buttonList[7].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[4].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[4].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[3].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[1].text == computerSide && buttonList[4].text == computerSide && buttonList[7].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[5].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;





void ChangeSides()

//playerSide = (playerSide == "X") ? "O" : "X";
playerMove = (playerMove == true) ? false : true;
//if(playerSide == "X")
if(playerMove == true)

SetPlayerColors(playerX, playerO);

else

SetPlayerColors(playerO, playerX);



void SetPlayerColors(Player newPlayer, Player oldPlayer)

newPlayer.panel.color = activePlayerColor.panelColor;
newPlayer.text.color = activePlayerColor.textColor;

oldPlayer.panel.color = inactivePlayerColor.panelColor;
oldPlayer.text.color = inactivePlayerColor.textColor;


void GameOver(string winningPlayer)

SetBoardInteractable(false);
if (winningPlayer == "draw")

SetGameOverText("Draw");
SetPlayerColorsInactive();

else

SetGameOverText(winningPlayer + " wins");

restartButton.SetActive(true);


void SetGameOverText(string value)

gameOverPanel.SetActive(true);
gameOverText.text = value;


public void RestartGame()

moveCount = 0;
gameOverPanel.SetActive(false);
restartButton.SetActive(false);
SetPlayerButtons(true);
startInfo.SetActive(true);
SetPlayerColorsInactive();
playerMove = true;
delay = 10;

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].text = "";



void SetBoardInteractable(bool toggle)

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<Button>().interactable = toggle;



void SetPlayerButtons(bool toggle)

playerX.button.interactable = toggle;
playerO.button.interactable = toggle;


void SetPlayerColorsInactive()

playerX.panel.color = inactivePlayerColor.panelColor;
playerX.text.color = inactivePlayerColor.textColor;
playerO.panel.color = inactivePlayerColor.panelColor;
playerO.panel.color = inactivePlayerColor.textColor;








share|improve this question











So I have a working game of Tic-Tac-Toe with an AI that plays random moves. Is anyway to maybe shorten the endturn() function so it's not so long? Also is this set up well enough to add a mode where the computer plays optimal or sub-optimal moves and a mode impossible to beat?



using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

[System.Serializable]
public class Player

public Image panel;
public Text text;
public Button button;

[System.Serializable]
public class PlayerColor

public Color panelColor;
public Color textColor;


public class GameController : MonoBehaviour

public Text buttonList;
public GameObject gameOverPanel;
public Text gameOverText;
private string playerSide;
private string computerSide;
private int moveCount;
public GameObject restartButton;
public GameObject startInfo;

public Player playerX;
public Player playerO;
public PlayerColor activePlayerColor;
public PlayerColor inactivePlayerColor;

public bool playerMove;
public float delay;
private int value;

public enum State Null, X, O ;

void Awake()

SetGameControllerReferenceOnButtons();
gameOverPanel.SetActive(false);
moveCount = 0;
restartButton.SetActive(false);
playerMove = true;


public void Update()

if (playerMove == false)

delay += delay * Time.deltaTime;
if (delay >= 100)

value = Random.Range(0, 8);
if (buttonList[value].GetComponentInParent<Button>().interactable == true)

buttonList[value].text = GetComputerSide();
buttonList[value].GetComponentInParent<Button>().interactable = false;
EndTurn();





void SetGameControllerReferenceOnButtons()

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<GridSpace>().SetGameControllerReference(this);



public void SetStartingSide(string startingSide)

playerSide = startingSide;
if(playerSide == "X")

computerSide = "O";
SetPlayerColors(playerX, playerO);

else

computerSide = "X";
SetPlayerColors(playerO, playerX);


StartGame();


void StartGame()

SetBoardInteractable(true);
SetPlayerButtons(false);
startInfo.SetActive(false);


public string GetPlayerSide()

return playerSide;


public string GetComputerSide()

return computerSide;


public void EndTurn()

moveCount++;

for (int i = 0; i < buttonList.Length; i++)

if (buttonList[0].text == playerSide && buttonList[1].text == playerSide && buttonList[2].text == playerSide)

GameOver(playerSide);


else if (buttonList[3].text == playerSide && buttonList[4].text == playerSide && buttonList[5].text == playerSide)

GameOver(playerSide);


else if (buttonList[6].text == playerSide && buttonList[7].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[4].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[4].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == playerSide && buttonList[3].text == playerSide && buttonList[6].text == playerSide)

GameOver(playerSide);


else if (buttonList[1].text == playerSide && buttonList[4].text == playerSide && buttonList[7].text == playerSide)

GameOver(playerSide);


else if (buttonList[2].text == playerSide && buttonList[5].text == playerSide && buttonList[8].text == playerSide)

GameOver(playerSide);


else if (buttonList[0].text == computerSide && buttonList[1].text == computerSide && buttonList[2].text == computerSide)

GameOver(computerSide);


else if (buttonList[3].text == computerSide && buttonList[4].text == computerSide && buttonList[5].text == computerSide)

GameOver(computerSide);


else if (buttonList[6].text == computerSide && buttonList[7].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[4].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[4].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[0].text == computerSide && buttonList[3].text == computerSide && buttonList[6].text == computerSide)

GameOver(computerSide);


else if (buttonList[1].text == computerSide && buttonList[4].text == computerSide && buttonList[7].text == computerSide)

GameOver(computerSide);


else if (buttonList[2].text == computerSide && buttonList[5].text == computerSide && buttonList[8].text == computerSide)

GameOver(computerSide);


else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;





void ChangeSides()

//playerSide = (playerSide == "X") ? "O" : "X";
playerMove = (playerMove == true) ? false : true;
//if(playerSide == "X")
if(playerMove == true)

SetPlayerColors(playerX, playerO);

else

SetPlayerColors(playerO, playerX);



void SetPlayerColors(Player newPlayer, Player oldPlayer)

newPlayer.panel.color = activePlayerColor.panelColor;
newPlayer.text.color = activePlayerColor.textColor;

oldPlayer.panel.color = inactivePlayerColor.panelColor;
oldPlayer.text.color = inactivePlayerColor.textColor;


void GameOver(string winningPlayer)

SetBoardInteractable(false);
if (winningPlayer == "draw")

SetGameOverText("Draw");
SetPlayerColorsInactive();

else

SetGameOverText(winningPlayer + " wins");

restartButton.SetActive(true);


void SetGameOverText(string value)

gameOverPanel.SetActive(true);
gameOverText.text = value;


public void RestartGame()

moveCount = 0;
gameOverPanel.SetActive(false);
restartButton.SetActive(false);
SetPlayerButtons(true);
startInfo.SetActive(true);
SetPlayerColorsInactive();
playerMove = true;
delay = 10;

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].text = "";



void SetBoardInteractable(bool toggle)

for (int i = 0; i < buttonList.Length; i++)

buttonList[i].GetComponentInParent<Button>().interactable = toggle;



void SetPlayerButtons(bool toggle)

playerX.button.interactable = toggle;
playerO.button.interactable = toggle;


void SetPlayerColorsInactive()

playerX.panel.color = inactivePlayerColor.panelColor;
playerX.text.color = inactivePlayerColor.textColor;
playerO.panel.color = inactivePlayerColor.panelColor;
playerO.panel.color = inactivePlayerColor.textColor;










share|improve this question










share|improve this question




share|improve this question









asked Apr 17 at 18:35









Koli

333




333







  • 1




    Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
    – Hosch250
    Apr 17 at 18:48











  • Is there an example I could go find?
    – Koli
    Apr 17 at 18:54












  • 1




    Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
    – Hosch250
    Apr 17 at 18:48











  • Is there an example I could go find?
    – Koli
    Apr 17 at 18:54







1




1




Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
– Hosch250
Apr 17 at 18:48





Use a 2d array of buttons, not a 1d list. Then you can loop over the items by row/column.
– Hosch250
Apr 17 at 18:48













Is there an example I could go find?
– Koli
Apr 17 at 18:54




Is there an example I could go find?
– Koli
Apr 17 at 18:54










1 Answer
1






active

oldest

votes

















up vote
3
down vote



accepted










Yes, there are ways you can shorten your EndTurn method.



First, you've duplicated your code in EndTurn to compare to both playerSide and computerSide, but the code is the same otherwise. You can extract a method (named IsGameWonBy below) to eliminate this duplication as follows:



public void EndTurn()

moveCount++;

for (int i = 0; i < buttonList.Length; i++)

if (IsGameWonBy(playerSide))

GameOver(playerSide);

else if (IsGameWonBy(computerSide))

GameOver(computerSide);

else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;




private bool IsGameWonBy(string side)

if (buttonList[0].text == side && buttonList[1].text == side && buttonList[2].text == side)

return true;

else if (buttonList[3].text == side && buttonList[4].text == side && buttonList[5].text == side)

return true;

else if (buttonList[6].text == side && buttonList[7].text == side && buttonList[8].text == side)

return true;

else if (buttonList[0].text == side && buttonList[4].text == side && buttonList[8].text == side)

return true;

else if (buttonList[2].text == side && buttonList[4].text == side && buttonList[6].text == side)

return true;

else if (buttonList[0].text == side && buttonList[3].text == side && buttonList[6].text == side)

return true;

else if (buttonList[1].text == side && buttonList[4].text == side && buttonList[7].text == side)

return true;

else if (buttonList[2].text == side && buttonList[5].text == side && buttonList[8].text == side)

return true;


return false;



Restructuring your code this way, your code is more readable and it is more obvious that your for loop in EndTurn isn't necessary. I think the code just happens to work because ChangeSides is called 9 times, an odd number, and there seem to be no consequences in your code for calling GameOver or ChangeSides multiple times. Let's remove that for loop there.



public void EndTurn()

moveCount++;

if (IsGameWonBy(playerSide))

GameOver(playerSide);

else if (IsGameWonBy(computerSide))

GameOver(computerSide);

else if (moveCount >= 9)

GameOver("draw");

else

ChangeSides();
delay = 10;




As another user commented, ideally you should use a 2D array rather than a 1D array to represent your tic-tac-toe board. This will also make the logic of the code simpler when using for loops to check for the win condition rather than manually checking every possible row/column/diagonal. If you aren't familiar with 2D arrays, you should do some research on "C# multidimensional arrays". After learning about them, you can check out this post with some other algorithms for solving tic-tac-toe, most of which use a 2D array.



However, note that for a 3x3 tic-tac-toe, it's also acceptable to just check the rows, columns, and diagonals manually for the win condition as you have done. As an exercise, you may want to try modifying your game to a 5x5 tic-tac-toe game to see what is difficult to change in your code and Unity project to make that happen. If your code is structured well, it should allow you to quickly switch the game between a 3x3 board and a 5x5 board without having to make significant changes to your code & project.



(As a note, 2D arrays are a bit tricky to set up with the current structure of your code because they don't work nicely with the Unity Editor Inspector window by default. This is a slightly more advanced topic, but you'll need to separate the logic of your game code from the UI code. Currently, all your game state and logic is tied to your buttonList buttons.)



As for adding a mode where the computer has different behavior, yes it should be possible but you should restructure your code a bit. Ideally, the computer's behavior should be separated out into its own class or at least its own method as a first step. For example, see the GetNextComputerMove method below:



public void Update()

if (playerMove == false)

delay += delay * Time.deltaTime;
if (delay >= 100)

value = GetNextComputerMove();

buttonList[value].text = GetComputerSide();
buttonList[value].GetComponentInParent<Button>().interactable = false;

EndTurn();




private int GetNextComputerMove()

// Put computer's logic here
// for example, Random.Range(0, 8)
// but you also need to check which moves are valid
// so you can return a valid move



Note that if you want to add a mode where computer plays optimal or sub-optimal moves, that will take more logic than just Random.Range. Currently, you are relying on the Update method being called multiple times to get a valid move by the computer. As a first step, I'd suggest figuring out how to get the list of all valid moves that the computer can make so that you can select a random move among those moves.






share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192315%2ftic-tac-toe-ai-in-c-unity%23new-answer', 'question_page');

    );

    Post as a guest






























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    3
    down vote



    accepted










    Yes, there are ways you can shorten your EndTurn method.



    First, you've duplicated your code in EndTurn to compare to both playerSide and computerSide, but the code is the same otherwise. You can extract a method (named IsGameWonBy below) to eliminate this duplication as follows:



    public void EndTurn()

    moveCount++;

    for (int i = 0; i < buttonList.Length; i++)

    if (IsGameWonBy(playerSide))

    GameOver(playerSide);

    else if (IsGameWonBy(computerSide))

    GameOver(computerSide);

    else if (moveCount >= 9)

    GameOver("draw");

    else

    ChangeSides();
    delay = 10;




    private bool IsGameWonBy(string side)

    if (buttonList[0].text == side && buttonList[1].text == side && buttonList[2].text == side)

    return true;

    else if (buttonList[3].text == side && buttonList[4].text == side && buttonList[5].text == side)

    return true;

    else if (buttonList[6].text == side && buttonList[7].text == side && buttonList[8].text == side)

    return true;

    else if (buttonList[0].text == side && buttonList[4].text == side && buttonList[8].text == side)

    return true;

    else if (buttonList[2].text == side && buttonList[4].text == side && buttonList[6].text == side)

    return true;

    else if (buttonList[0].text == side && buttonList[3].text == side && buttonList[6].text == side)

    return true;

    else if (buttonList[1].text == side && buttonList[4].text == side && buttonList[7].text == side)

    return true;

    else if (buttonList[2].text == side && buttonList[5].text == side && buttonList[8].text == side)

    return true;


    return false;



    Restructuring your code this way, your code is more readable and it is more obvious that your for loop in EndTurn isn't necessary. I think the code just happens to work because ChangeSides is called 9 times, an odd number, and there seem to be no consequences in your code for calling GameOver or ChangeSides multiple times. Let's remove that for loop there.



    public void EndTurn()

    moveCount++;

    if (IsGameWonBy(playerSide))

    GameOver(playerSide);

    else if (IsGameWonBy(computerSide))

    GameOver(computerSide);

    else if (moveCount >= 9)

    GameOver("draw");

    else

    ChangeSides();
    delay = 10;




    As another user commented, ideally you should use a 2D array rather than a 1D array to represent your tic-tac-toe board. This will also make the logic of the code simpler when using for loops to check for the win condition rather than manually checking every possible row/column/diagonal. If you aren't familiar with 2D arrays, you should do some research on "C# multidimensional arrays". After learning about them, you can check out this post with some other algorithms for solving tic-tac-toe, most of which use a 2D array.



    However, note that for a 3x3 tic-tac-toe, it's also acceptable to just check the rows, columns, and diagonals manually for the win condition as you have done. As an exercise, you may want to try modifying your game to a 5x5 tic-tac-toe game to see what is difficult to change in your code and Unity project to make that happen. If your code is structured well, it should allow you to quickly switch the game between a 3x3 board and a 5x5 board without having to make significant changes to your code & project.



    (As a note, 2D arrays are a bit tricky to set up with the current structure of your code because they don't work nicely with the Unity Editor Inspector window by default. This is a slightly more advanced topic, but you'll need to separate the logic of your game code from the UI code. Currently, all your game state and logic is tied to your buttonList buttons.)



    As for adding a mode where the computer has different behavior, yes it should be possible but you should restructure your code a bit. Ideally, the computer's behavior should be separated out into its own class or at least its own method as a first step. For example, see the GetNextComputerMove method below:



    public void Update()

    if (playerMove == false)

    delay += delay * Time.deltaTime;
    if (delay >= 100)

    value = GetNextComputerMove();

    buttonList[value].text = GetComputerSide();
    buttonList[value].GetComponentInParent<Button>().interactable = false;

    EndTurn();




    private int GetNextComputerMove()

    // Put computer's logic here
    // for example, Random.Range(0, 8)
    // but you also need to check which moves are valid
    // so you can return a valid move



    Note that if you want to add a mode where computer plays optimal or sub-optimal moves, that will take more logic than just Random.Range. Currently, you are relying on the Update method being called multiple times to get a valid move by the computer. As a first step, I'd suggest figuring out how to get the list of all valid moves that the computer can make so that you can select a random move among those moves.






    share|improve this answer



























      up vote
      3
      down vote



      accepted










      Yes, there are ways you can shorten your EndTurn method.



      First, you've duplicated your code in EndTurn to compare to both playerSide and computerSide, but the code is the same otherwise. You can extract a method (named IsGameWonBy below) to eliminate this duplication as follows:



      public void EndTurn()

      moveCount++;

      for (int i = 0; i < buttonList.Length; i++)

      if (IsGameWonBy(playerSide))

      GameOver(playerSide);

      else if (IsGameWonBy(computerSide))

      GameOver(computerSide);

      else if (moveCount >= 9)

      GameOver("draw");

      else

      ChangeSides();
      delay = 10;




      private bool IsGameWonBy(string side)

      if (buttonList[0].text == side && buttonList[1].text == side && buttonList[2].text == side)

      return true;

      else if (buttonList[3].text == side && buttonList[4].text == side && buttonList[5].text == side)

      return true;

      else if (buttonList[6].text == side && buttonList[7].text == side && buttonList[8].text == side)

      return true;

      else if (buttonList[0].text == side && buttonList[4].text == side && buttonList[8].text == side)

      return true;

      else if (buttonList[2].text == side && buttonList[4].text == side && buttonList[6].text == side)

      return true;

      else if (buttonList[0].text == side && buttonList[3].text == side && buttonList[6].text == side)

      return true;

      else if (buttonList[1].text == side && buttonList[4].text == side && buttonList[7].text == side)

      return true;

      else if (buttonList[2].text == side && buttonList[5].text == side && buttonList[8].text == side)

      return true;


      return false;



      Restructuring your code this way, your code is more readable and it is more obvious that your for loop in EndTurn isn't necessary. I think the code just happens to work because ChangeSides is called 9 times, an odd number, and there seem to be no consequences in your code for calling GameOver or ChangeSides multiple times. Let's remove that for loop there.



      public void EndTurn()

      moveCount++;

      if (IsGameWonBy(playerSide))

      GameOver(playerSide);

      else if (IsGameWonBy(computerSide))

      GameOver(computerSide);

      else if (moveCount >= 9)

      GameOver("draw");

      else

      ChangeSides();
      delay = 10;




      As another user commented, ideally you should use a 2D array rather than a 1D array to represent your tic-tac-toe board. This will also make the logic of the code simpler when using for loops to check for the win condition rather than manually checking every possible row/column/diagonal. If you aren't familiar with 2D arrays, you should do some research on "C# multidimensional arrays". After learning about them, you can check out this post with some other algorithms for solving tic-tac-toe, most of which use a 2D array.



      However, note that for a 3x3 tic-tac-toe, it's also acceptable to just check the rows, columns, and diagonals manually for the win condition as you have done. As an exercise, you may want to try modifying your game to a 5x5 tic-tac-toe game to see what is difficult to change in your code and Unity project to make that happen. If your code is structured well, it should allow you to quickly switch the game between a 3x3 board and a 5x5 board without having to make significant changes to your code & project.



      (As a note, 2D arrays are a bit tricky to set up with the current structure of your code because they don't work nicely with the Unity Editor Inspector window by default. This is a slightly more advanced topic, but you'll need to separate the logic of your game code from the UI code. Currently, all your game state and logic is tied to your buttonList buttons.)



      As for adding a mode where the computer has different behavior, yes it should be possible but you should restructure your code a bit. Ideally, the computer's behavior should be separated out into its own class or at least its own method as a first step. For example, see the GetNextComputerMove method below:



      public void Update()

      if (playerMove == false)

      delay += delay * Time.deltaTime;
      if (delay >= 100)

      value = GetNextComputerMove();

      buttonList[value].text = GetComputerSide();
      buttonList[value].GetComponentInParent<Button>().interactable = false;

      EndTurn();




      private int GetNextComputerMove()

      // Put computer's logic here
      // for example, Random.Range(0, 8)
      // but you also need to check which moves are valid
      // so you can return a valid move



      Note that if you want to add a mode where computer plays optimal or sub-optimal moves, that will take more logic than just Random.Range. Currently, you are relying on the Update method being called multiple times to get a valid move by the computer. As a first step, I'd suggest figuring out how to get the list of all valid moves that the computer can make so that you can select a random move among those moves.






      share|improve this answer

























        up vote
        3
        down vote



        accepted







        up vote
        3
        down vote



        accepted






        Yes, there are ways you can shorten your EndTurn method.



        First, you've duplicated your code in EndTurn to compare to both playerSide and computerSide, but the code is the same otherwise. You can extract a method (named IsGameWonBy below) to eliminate this duplication as follows:



        public void EndTurn()

        moveCount++;

        for (int i = 0; i < buttonList.Length; i++)

        if (IsGameWonBy(playerSide))

        GameOver(playerSide);

        else if (IsGameWonBy(computerSide))

        GameOver(computerSide);

        else if (moveCount >= 9)

        GameOver("draw");

        else

        ChangeSides();
        delay = 10;




        private bool IsGameWonBy(string side)

        if (buttonList[0].text == side && buttonList[1].text == side && buttonList[2].text == side)

        return true;

        else if (buttonList[3].text == side && buttonList[4].text == side && buttonList[5].text == side)

        return true;

        else if (buttonList[6].text == side && buttonList[7].text == side && buttonList[8].text == side)

        return true;

        else if (buttonList[0].text == side && buttonList[4].text == side && buttonList[8].text == side)

        return true;

        else if (buttonList[2].text == side && buttonList[4].text == side && buttonList[6].text == side)

        return true;

        else if (buttonList[0].text == side && buttonList[3].text == side && buttonList[6].text == side)

        return true;

        else if (buttonList[1].text == side && buttonList[4].text == side && buttonList[7].text == side)

        return true;

        else if (buttonList[2].text == side && buttonList[5].text == side && buttonList[8].text == side)

        return true;


        return false;



        Restructuring your code this way, your code is more readable and it is more obvious that your for loop in EndTurn isn't necessary. I think the code just happens to work because ChangeSides is called 9 times, an odd number, and there seem to be no consequences in your code for calling GameOver or ChangeSides multiple times. Let's remove that for loop there.



        public void EndTurn()

        moveCount++;

        if (IsGameWonBy(playerSide))

        GameOver(playerSide);

        else if (IsGameWonBy(computerSide))

        GameOver(computerSide);

        else if (moveCount >= 9)

        GameOver("draw");

        else

        ChangeSides();
        delay = 10;




        As another user commented, ideally you should use a 2D array rather than a 1D array to represent your tic-tac-toe board. This will also make the logic of the code simpler when using for loops to check for the win condition rather than manually checking every possible row/column/diagonal. If you aren't familiar with 2D arrays, you should do some research on "C# multidimensional arrays". After learning about them, you can check out this post with some other algorithms for solving tic-tac-toe, most of which use a 2D array.



        However, note that for a 3x3 tic-tac-toe, it's also acceptable to just check the rows, columns, and diagonals manually for the win condition as you have done. As an exercise, you may want to try modifying your game to a 5x5 tic-tac-toe game to see what is difficult to change in your code and Unity project to make that happen. If your code is structured well, it should allow you to quickly switch the game between a 3x3 board and a 5x5 board without having to make significant changes to your code & project.



        (As a note, 2D arrays are a bit tricky to set up with the current structure of your code because they don't work nicely with the Unity Editor Inspector window by default. This is a slightly more advanced topic, but you'll need to separate the logic of your game code from the UI code. Currently, all your game state and logic is tied to your buttonList buttons.)



        As for adding a mode where the computer has different behavior, yes it should be possible but you should restructure your code a bit. Ideally, the computer's behavior should be separated out into its own class or at least its own method as a first step. For example, see the GetNextComputerMove method below:



        public void Update()

        if (playerMove == false)

        delay += delay * Time.deltaTime;
        if (delay >= 100)

        value = GetNextComputerMove();

        buttonList[value].text = GetComputerSide();
        buttonList[value].GetComponentInParent<Button>().interactable = false;

        EndTurn();




        private int GetNextComputerMove()

        // Put computer's logic here
        // for example, Random.Range(0, 8)
        // but you also need to check which moves are valid
        // so you can return a valid move



        Note that if you want to add a mode where computer plays optimal or sub-optimal moves, that will take more logic than just Random.Range. Currently, you are relying on the Update method being called multiple times to get a valid move by the computer. As a first step, I'd suggest figuring out how to get the list of all valid moves that the computer can make so that you can select a random move among those moves.






        share|improve this answer















        Yes, there are ways you can shorten your EndTurn method.



        First, you've duplicated your code in EndTurn to compare to both playerSide and computerSide, but the code is the same otherwise. You can extract a method (named IsGameWonBy below) to eliminate this duplication as follows:



        public void EndTurn()

        moveCount++;

        for (int i = 0; i < buttonList.Length; i++)

        if (IsGameWonBy(playerSide))

        GameOver(playerSide);

        else if (IsGameWonBy(computerSide))

        GameOver(computerSide);

        else if (moveCount >= 9)

        GameOver("draw");

        else

        ChangeSides();
        delay = 10;




        private bool IsGameWonBy(string side)

        if (buttonList[0].text == side && buttonList[1].text == side && buttonList[2].text == side)

        return true;

        else if (buttonList[3].text == side && buttonList[4].text == side && buttonList[5].text == side)

        return true;

        else if (buttonList[6].text == side && buttonList[7].text == side && buttonList[8].text == side)

        return true;

        else if (buttonList[0].text == side && buttonList[4].text == side && buttonList[8].text == side)

        return true;

        else if (buttonList[2].text == side && buttonList[4].text == side && buttonList[6].text == side)

        return true;

        else if (buttonList[0].text == side && buttonList[3].text == side && buttonList[6].text == side)

        return true;

        else if (buttonList[1].text == side && buttonList[4].text == side && buttonList[7].text == side)

        return true;

        else if (buttonList[2].text == side && buttonList[5].text == side && buttonList[8].text == side)

        return true;


        return false;



        Restructuring your code this way, your code is more readable and it is more obvious that your for loop in EndTurn isn't necessary. I think the code just happens to work because ChangeSides is called 9 times, an odd number, and there seem to be no consequences in your code for calling GameOver or ChangeSides multiple times. Let's remove that for loop there.



        public void EndTurn()

        moveCount++;

        if (IsGameWonBy(playerSide))

        GameOver(playerSide);

        else if (IsGameWonBy(computerSide))

        GameOver(computerSide);

        else if (moveCount >= 9)

        GameOver("draw");

        else

        ChangeSides();
        delay = 10;




        As another user commented, ideally you should use a 2D array rather than a 1D array to represent your tic-tac-toe board. This will also make the logic of the code simpler when using for loops to check for the win condition rather than manually checking every possible row/column/diagonal. If you aren't familiar with 2D arrays, you should do some research on "C# multidimensional arrays". After learning about them, you can check out this post with some other algorithms for solving tic-tac-toe, most of which use a 2D array.



        However, note that for a 3x3 tic-tac-toe, it's also acceptable to just check the rows, columns, and diagonals manually for the win condition as you have done. As an exercise, you may want to try modifying your game to a 5x5 tic-tac-toe game to see what is difficult to change in your code and Unity project to make that happen. If your code is structured well, it should allow you to quickly switch the game between a 3x3 board and a 5x5 board without having to make significant changes to your code & project.



        (As a note, 2D arrays are a bit tricky to set up with the current structure of your code because they don't work nicely with the Unity Editor Inspector window by default. This is a slightly more advanced topic, but you'll need to separate the logic of your game code from the UI code. Currently, all your game state and logic is tied to your buttonList buttons.)



        As for adding a mode where the computer has different behavior, yes it should be possible but you should restructure your code a bit. Ideally, the computer's behavior should be separated out into its own class or at least its own method as a first step. For example, see the GetNextComputerMove method below:



        public void Update()

        if (playerMove == false)

        delay += delay * Time.deltaTime;
        if (delay >= 100)

        value = GetNextComputerMove();

        buttonList[value].text = GetComputerSide();
        buttonList[value].GetComponentInParent<Button>().interactable = false;

        EndTurn();




        private int GetNextComputerMove()

        // Put computer's logic here
        // for example, Random.Range(0, 8)
        // but you also need to check which moves are valid
        // so you can return a valid move



        Note that if you want to add a mode where computer plays optimal or sub-optimal moves, that will take more logic than just Random.Range. Currently, you are relying on the Update method being called multiple times to get a valid move by the computer. As a first step, I'd suggest figuring out how to get the list of all valid moves that the computer can make so that you can select a random move among those moves.







        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited May 1 at 22:19


























        answered May 1 at 22:04









        sonny

        1819




        1819






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f192315%2ftic-tac-toe-ai-in-c-unity%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            Greedy Best First Search implementation in Rust

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            C++11 CLH Lock Implementation