Tic-Tac-Toe AI in C# Unity
Clash 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;
c# tic-tac-toe unity3d
add a comment |Â
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;
c# tic-tac-toe unity3d
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
add a comment |Â
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;
c# tic-tac-toe unity3d
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;
c# tic-tac-toe unity3d
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
add a comment |Â
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
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
add a comment |Â
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.
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.
edited May 1 at 22:19
answered May 1 at 22:04
sonny
1819
1819
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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