/// <summary> /// Call back when any cell in the Grid is clicked. /// </summary> /// <param name="cellID">Cell ID</param> private void OnCellClick(int cellID) { //is invoking is true when Bot's turn is pending. Check added after intentionally Bot wait time added. if (IsInvoking()) { return; } this.lastUsedCellID = cellID; C.CellState tempState = this.players[this.playerTurnIndex].playerValue; //Update cell with appropriate Image. this.gridHandler.UpdateCellState(cellID, tempState); this.totalTurns += 1; //After every turn check for result EvaluateResult(this.lastUsedCellID, tempState); ChangePlayerTurn(); //if result is not declared tell bot to play. if (!this.resultPopup.activeSelf) { // BotTurn(cellID); // BotTurn(); //Added delay so that user doesn't get confuse with the turns. Invoke("BotTurn", 1f); } }
/// <summary> /// Checks the left top to right bottom diagnol. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysis">Grid analysis.</param> private void CheckLeftTopToRightBottomDiagnol(int cellID, C.CellState playerValue, ref GridAnalysisForDefence gridAnalysis) { int iterationCOunter = 0; int counter = 0; int index; for (int i = 0; iterationCOunter < 3; i++, iterationCOunter++) { index = (i * 3) + i; if (this.cells[index].CellState == playerValue) { counter++; } else if (this.cells[index].CellState == C.CellState.None) { gridAnalysis.proposedCellID = index; } } if (counter > 1) { gridAnalysis.isOpponentWinning = true; return; } gridAnalysis.isOpponentWinning = false; }
/// <summary> /// Checks the row. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysis">Grid analysis.</param> private void CheckRow(int cellID, C.CellState playerValue, ref GridAnalysisForDefence gridAnalysis) { int rowNumber = cellID / 3; int start = rowNumber * 3; int end = start + 3; int counter = 0; for (int i = start; i < end; i++) { if (this.cells[i].CellState == playerValue) { counter++; } else if (this.cells[i].CellState == C.CellState.None) { gridAnalysis.proposedCellID = i; } } if (counter > 1) { gridAnalysis.isOpponentWinning = true; return; } gridAnalysis.isOpponentWinning = false; }
/// <summary> /// Checks the column. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysis">Grid analysis.</param> private void CheckColumn(int cellID, C.CellState playerValue, ref GridAnalysisForDefence gridAnalysis) { int colNumber = cellID % 3; int iterationCOunter = 0; int counter = 0; for (int i = colNumber; iterationCOunter < 3; i += 3, iterationCOunter++) { if (this.cells[i].CellState == playerValue) { counter++; } else if (this.cells[i].CellState == C.CellState.None) { gridAnalysis.proposedCellID = i; } } if (counter > 1) { gridAnalysis.isOpponentWinning = true; return; } gridAnalysis.isOpponentWinning = false; }
/// <summary> /// Gets the column analysis for attack. /// </summary> /// <returns>The column analysis for attack.</returns> /// <param name="lastUsedCellID">Last used cell I.</param> /// <param name="playerValue">Player value.</param> public GridAnalysisForAttack GetColumnAnalysisForAttack(int lastUsedCellID, C.CellState playerValue) { GridAnalysisForAttack gridAnalysis = new GridAnalysisForAttack(); gridAnalysis.proposedCellID = -1; CheckColumnForAttack(lastUsedCellID, playerValue, ref gridAnalysis); return(gridAnalysis); }
/// <summary> /// Checks the column for for attack. /// </summary> /// <returns>The column for for attack.</returns> /// <param name="gridHandler">Grid handler.</param> /// <param name="playerValue">Player value.</param> private int CheckColumnForForAttack(GridHandler gridHandler, C.CellState playerValue) { GridHandler.GridAnalysisForAttack analysis = gridHandler.GetColumnAnalysisForAttack(this.lastUsedCellID, playerValue); if (analysis.isCellHasTwoEmptySpace || analysis.playerValueCounter == 2) { return(analysis.proposedCellID); } return(-1); }
/// <summary> /// Gets the column analysis. /// Information it will return is whether row/col/diagnol has empty space, has 2 cells which have player value and a proposed cell ID /// </summary> /// <returns>The column analysis.</returns> /// <param name="lastUsedCellID">Last used cell I.</param> /// <param name="opponentValue">Opponent value.</param> public GridAnalysisForDefence GetColumnAnalysis(int lastUsedCellID, C.CellState opponentValue) { GridAnalysisForDefence gridAnalysis = new GridAnalysisForDefence(); gridAnalysis.isCellHasEmptySpace = IsColumnHasEmptySpace(lastUsedCellID); CheckColumn(lastUsedCellID, opponentValue, ref gridAnalysis); return(gridAnalysis); }
/// <summary> /// Checks the left top to right bottom diagnol. /// </summary> /// <returns><c>true</c>, if left top to right bottom diagnol was checked, <c>false</c> otherwise.</returns> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> private bool CheckLeftTopToRightBottomDiagnol(int cellID, C.CellState playerValue) { int iterationCOunter = 0; int counter = 0; for (int i = 0; iterationCOunter < 3; i++, iterationCOunter++) { if (this.cells[(i * 3) + i].CellState == playerValue) { counter++; } } return(counter == 3); }
/// <summary> /// Checks the column. /// </summary> /// <returns><c>true</c>, if column was checked, <c>false</c> otherwise.</returns> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> private bool CheckColumn(int cellID, C.CellState playerValue) { int colNumber = cellID % 3; int iterationCOunter = 0; int counter = 0; for (int i = colNumber; iterationCOunter < 3; i += 3, iterationCOunter++) { if (this.cells[i].CellState == playerValue) { counter++; } } return(counter == 3); }
/// <summary> /// Checks the row. /// </summary> /// <returns><c>true</c>, if row was checked, <c>false</c> otherwise.</returns> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> private bool CheckRow(int cellID, C.CellState playerValue) { int rowNumber = cellID / 3; int start = rowNumber * 3; int end = start + 3; int counter = 0; for (int i = start; i < end; i++) { if (this.cells[i].CellState == playerValue) { counter++; } } return(counter == 3); }
/// <summary> /// Evaluates the result. /// </summary> /// <param name="cellID">Cell ID from last turn</param> /// <param name="playerValue">Player value.</param> private void EvaluateResult(int cellID, C.CellState playerValue) { bool isAnyPlayerWon = this.gridHandler.EvaluateResult(cellID, playerValue); //if any player won then decalre result if (isAnyPlayerWon) { //Declare result DeclareResult(true, this.players[this.playerTurnIndex].playerName + " won!"); //Update score this.players[this.playerTurnIndex].score += 1; //Update score text UpdateScoreText(); } else if (this.totalTurns == C.MAX_TURNS_PER_GAME) { //If Max turn is achieved, declare game is draw. DeclareResult(true, "Draw!"); } }
/// <summary> /// Checks the column for attack. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysisForAttack">Grid analysis for attack.</param> private void CheckColumnForAttack(int cellID, C.CellState playerValue, ref GridAnalysisForAttack gridAnalysisForAttack) { int colNumber = cellID % 3; int iterationCOunter = 0; int counter = 0; for (int i = colNumber; iterationCOunter < 3; i += 3, iterationCOunter++) { if (this.cells[i].CellState == C.CellState.None) { counter++; gridAnalysisForAttack.proposedCellID = i; } else if (this.cells[i].CellState == playerValue) { gridAnalysisForAttack.playerValueCounter += 1; } } gridAnalysisForAttack.isCellHasTwoEmptySpace = counter > 1; }
/// <summary> /// Let Bot Play the next turn/=. /// </summary> /// <param name="cellID">Cell I.D which was last used by the user.</param> private void BotTurn() { //CHeck if its actually Bot's turn. if (this.players[this.playerTurnIndex] is Bot) { //Cell ID which is selected by Bot. int turnCellID = ((Bot)this.players[this.playerTurnIndex]).PlayTurn(this.gridHandler, this.totalTurns, this.lastUsedCellID); if (turnCellID != -1) { this.lastUsedCellID = turnCellID; C.CellState tempState = this.players[this.playerTurnIndex].playerValue; //Update cell with appropriate Image. this.gridHandler.UpdateCellState(turnCellID, tempState); this.totalTurns += 1; //Evaluate result EvaluateResult(this.lastUsedCellID, tempState); //change player turn ChangePlayerTurn(); } } }
/// <summary> /// Checks the left top to right bottom diagnol for attack. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysisForAttack">Grid analysis for attack.</param> private void CheckLeftTopToRightBottomDiagnolForAttack(int cellID, C.CellState playerValue, ref GridAnalysisForAttack gridAnalysisForAttack) { int iterationCOunter = 0; int counter = 0; int index; for (int i = 0; iterationCOunter < 3; i++, iterationCOunter++) { index = (i * 3) + i; if (this.cells[index].CellState == C.CellState.None) { counter++; gridAnalysisForAttack.proposedCellID = index; } else if (this.cells[index].CellState == playerValue) { gridAnalysisForAttack.playerValueCounter += 1; } } gridAnalysisForAttack.isCellHasTwoEmptySpace = counter > 1; }
/// <summary> /// Checks the row for attack. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> /// <param name="gridAnalysisForAttack">Grid analysis for attack.</param> private void CheckRowForAttack(int cellID, C.CellState playerValue, ref GridAnalysisForAttack gridAnalysisForAttack) { int rowNumber = cellID / 3; int start = rowNumber * 3; int end = start + 3; int counter = 0; int playerValueCounter = 0; for (int i = start; i < end; i++) { if (this.cells[i].CellState == C.CellState.None) { counter++; gridAnalysisForAttack.proposedCellID = i; } else if (this.cells[i].CellState == playerValue) { gridAnalysisForAttack.playerValueCounter += 1; } } gridAnalysisForAttack.isCellHasTwoEmptySpace = counter > 1; }
/// <summary> /// Initializes a new instance of the <see cref="Players.Human"/> class. /// Init with player name, player value and default score /// </summary> /// <param name="playerName">Player name.</param> /// <param name="playerValue">Player value.</param> /// <param name="score">Score.</param> public Human(string playerName, C.CellState playerValue, int score) : base(playerName, playerValue, score) { }
/// <summary> /// Defend the specified gridHandler, totalTurns and opponentUsedCellID. /// </summary> /// <param name="gridHandler">Grid handler.</param> /// <param name="totalTurns">Total turns.</param> /// <param name="opponentUsedCellID">Opponent used cell ID.</param> private int Defend(GridHandler gridHandler, int totalTurns, int opponentUsedCellID) { C.CellState tempOpponentValue = this.playerValue == C.CellState.Circle ? C.CellState.Cross : C.CellState.Circle; int proposedCellID = -1; //cases will be the cell ID which was last used. //Cell ID will decide which row/column/diagnol to check for defence. switch (opponentUsedCellID) { case 0: case 8: proposedCellID = CheckRowForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckLeftTopToRightBottomDiagnolForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 1: case 3: case 5: case 7: proposedCellID = CheckRowForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 2: case 6: proposedCellID = CheckRowForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckRightTopToLeftBottomDiagnolForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 4: proposedCellID = CheckRowForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckRightTopToLeftBottomDiagnolForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckLeftTopToRightBottomDiagnolForDefence(gridHandler, totalTurns, opponentUsedCellID, tempOpponentValue); if (proposedCellID != -1) { return(proposedCellID); } break; } return(proposedCellID); }
/// <summary> /// Checks the right top to left bottom diagnol for attack. /// </summary> /// <returns>The right top to left bottom diagnol for attack.</returns> /// <param name="gridHandler">Grid handler.</param> /// <param name="playerValue">Player value.</param> private int CheckRightTopToLeftBottomDiagnolForAttack(GridHandler gridHandler, C.CellState playerValue) { GridHandler.GridAnalysisForAttack analysis = gridHandler.GetRightTopToLeftBottomDiagnolAnalysisForAttack(this.lastUsedCellID, playerValue); if (analysis.isCellHasTwoEmptySpace || analysis.playerValueCounter == 2) { return(analysis.proposedCellID); } return(-1); }
/// <summary> /// Gets the right top to left bottom diagnol analysis. /// Information it will return is whether row/col/diagnol has empty space, has 2 cells which have player value and a proposed cell ID /// </summary> /// <returns>The right top to left bottom diagnol analysis.</returns> /// <param name="lastUsedCellID">Last used cell I.</param> /// <param name="opponentValue">Opponent value.</param> public GridAnalysisForDefence GetRightTopToLeftBottomDiagnolAnalysis(int lastUsedCellID, C.CellState opponentValue) { GridAnalysisForDefence gridAnalysis = new GridAnalysisForDefence(); gridAnalysis.isCellHasEmptySpace = IsRightTopToLeftBottomDiagnolHasEmptyCell(lastUsedCellID); CheckRightTopToLeftBottomDiagnol(lastUsedCellID, opponentValue, ref gridAnalysis); return(gridAnalysis); }
/// <summary> /// Attack the specified gridHandler. /// </summary> /// <param name="gridHandler">Grid handler.</param> private int Attack(GridHandler gridHandler) { C.CellState tempPlayerValue = this.playerValue == C.CellState.Circle ? C.CellState.Circle : C.CellState.Cross; int proposedCellID = -1; switch (this.lastUsedCellID) { case 0: case 8: proposedCellID = CheckRowForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckLeftTopToRightBottomDiagnolForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 1: case 3: case 5: case 7: proposedCellID = CheckRowForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 2: case 6: proposedCellID = CheckRowForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckRightTopToLeftBottomDiagnolForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } break; case 4: proposedCellID = CheckRowForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckColumnForForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckRightTopToLeftBottomDiagnolForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } proposedCellID = CheckLeftTopToRightBottomDiagnolForAttack(gridHandler, tempPlayerValue); if (proposedCellID != -1) { return(proposedCellID); } break; } proposedCellID = gridHandler.emptyCellsIndexes[Random.Range(0, gridHandler.emptyCellsIndexes.Count)]; return(proposedCellID); }
/// <summary> /// Checks the right top to left bottom diagnol for defence. /// </summary> /// <returns>The right top to left bottom diagnol for defence.</returns> /// <param name="gridHandler">Grid handler.</param> /// <param name="totalTurns">Total turns.</param> /// <param name="lastUsedCellID">Last used cell I.</param> /// <param name="opponentValue">Opponent value.</param> private int CheckRightTopToLeftBottomDiagnolForDefence(GridHandler gridHandler, int totalTurns, int lastUsedCellID, C.CellState opponentValue) { GridHandler.GridAnalysisForDefence analysis = gridHandler.GetRightTopToLeftBottomDiagnolAnalysis(lastUsedCellID, opponentValue); if (analysis.isCellHasEmptySpace) { if (analysis.isOpponentWinning) { return(analysis.proposedCellID); } } return(-1); }
/// <summary> /// Updates the state of the cell. /// </summary> /// <param name="cellID">Cell I.</param> /// <param name="cellState">Cell state.</param> public void UpdateCellState(int cellID, C.CellState cellState) { this.cells[cellID].UpdateCellState(cellState); this.emptyCellsIndexes.Remove(cellID); }
/// <summary> /// Evaluates the result. /// </summary> /// <returns><c>true</c>, if result was evaluated, <c>false</c> otherwise.</returns> /// <param name="cellID">Cell I.</param> /// <param name="playerValue">Player value.</param> public bool EvaluateResult(int cellID, C.CellState playerValue) { switch (cellID) { case 0: case 8: if (CheckRow(cellID, playerValue)) { return(true); } if (CheckColumn(cellID, playerValue)) { return(true); } if (CheckLeftTopToRightBottomDiagnol(cellID, playerValue)) { return(true); } break; case 1: case 3: case 5: case 7: if (CheckRow(cellID, playerValue)) { return(true); } if (CheckColumn(cellID, playerValue)) { return(true); } break; case 2: case 6: if (CheckRow(cellID, playerValue)) { return(true); } if (CheckColumn(cellID, playerValue)) { return(true); } if (CheckRightTopToLeftBottomDiagnol(cellID, playerValue)) { return(true); } break; case 4: if (CheckRow(cellID, playerValue)) { return(true); } if (CheckColumn(cellID, playerValue)) { return(true); } if (CheckRightTopToLeftBottomDiagnol(cellID, playerValue)) { return(true); } if (CheckLeftTopToRightBottomDiagnol(cellID, playerValue)) { return(true); } break; } return(false); }
public Player(string playerName, C.CellState playerValue, int score) { this.playerName = playerName; this.playerValue = playerValue; this.score = score; }
public void UpdateCellState(C.CellState cellState) { this.CellState = cellState; }
public void Reset() { this.CellState = C.CellState.None; }
/// <summary> /// Gets the right top to left bottom diagnol analysis for attack. /// </summary> /// <returns>The right top to left bottom diagnol analysis for attack.</returns> /// <param name="lastUsedCellID">Last used cell I.</param> /// <param name="playerValue">Player value.</param> public GridAnalysisForAttack GetRightTopToLeftBottomDiagnolAnalysisForAttack(int lastUsedCellID, C.CellState playerValue) { GridAnalysisForAttack gridAnalysis = new GridAnalysisForAttack(); gridAnalysis.proposedCellID = -1; CheckRightTopToLeftBottomDiagnolForAttack(lastUsedCellID, playerValue, ref gridAnalysis); return(gridAnalysis); }