Example #1
0
            private void getOptimalCell(byte i_PlayerIndex, out Board.Cell o_ResultMove)
            {
                const byte k_FirstHumanMoveIndex     = 0;
                const byte k_LastUnblockingEmptyCell = 0;
                Random     rnd = new Random();

                Board.Cell        targetedCell         = this.gameLogic.Players[GetOtherPlayerIndex(i_PlayerIndex)].m_MovesList[k_FirstHumanMoveIndex];
                List <Board.Cell> unblockingEmptyCells = this.getUnblockingEmptyCells(targetedCell);

                if (unblockingEmptyCells.Count != k_LastUnblockingEmptyCell)
                {
                    o_ResultMove = unblockingEmptyCells[rnd.Next(unblockingEmptyCells.Count)];
                    if (!this.gameLogic.checkIfPlayerLost(o_ResultMove, i_PlayerIndex))
                    {
                        unblockingEmptyCells.Remove(o_ResultMove);
                    }
                }
                else
                {
                    List <Board.Cell> freeCellsInBoard = this.getFreeCellsInBoard();
                    o_ResultMove = freeCellsInBoard[rnd.Next(freeCellsInBoard.Count)];
                    while (this.gameLogic.checkIfPlayerLost(o_ResultMove, i_PlayerIndex))
                    {
                        const int k_LastComputerOptionalCell = 1;
                        if (freeCellsInBoard.Count == k_LastComputerOptionalCell)
                        {
                            break;
                        }

                        freeCellsInBoard.Remove(o_ResultMove);
                        o_ResultMove = freeCellsInBoard[rnd.Next(freeCellsInBoard.Count)];
                    }
                }
            }
Example #2
0
        /// <summary>
        /// Set the text (Nought or Cross) for a button, and then
        /// disable it so user cannot click it again during this game.
        /// </summary>
        /// <param name="button">Button to set</param>
        /// <param name="cell">Nought, Cross or Empty</param>
        private void SetButtonCell(Button button, Board.Cell cell)
        {
            switch (cell)
            {
            case Board.Cell.Computer:
            {
                button.Text    = Board.CellToString(cell);
                button.Enabled = false;
                break;
            }

            case Board.Cell.Human:
            {
                button.Text    = Board.CellToString(cell);
                button.Enabled = false; break;
            }

            case Board.Cell.Empty:
            {
                button.Text    = Board.CellToString(cell);
                button.Enabled = true;
                break;
            }
            }
        }
Example #3
0
        private bool checkDiagonalLose(Board.Cell i_LastMove, byte i_PlayerIndex, eSign i_PlayerSign)
        {
            bool minorDiagonalLoseFlag = true;
            bool majorDiagonalLoseFlag = true;

            for (byte colRowIndex = 0; colRowIndex < this.Board.BoardSize; colRowIndex++)
            {
                if (i_LastMove != this.Board[(byte)(this.m_BoardSize - colRowIndex - 1), colRowIndex])
                {
                    if (minorDiagonalLoseFlag && this.Board[(byte)(this.Board.BoardSize - colRowIndex - 1), colRowIndex].m_CellSign != i_PlayerSign)
                    {
                        minorDiagonalLoseFlag = false;
                    }
                }

                if (i_LastMove != this.Board[colRowIndex, colRowIndex])
                {
                    if (majorDiagonalLoseFlag && this.Board[colRowIndex, colRowIndex].m_CellSign != i_PlayerSign)
                    {
                        majorDiagonalLoseFlag = false;
                    }
                }
            }

            bool minorOrMajorDiagonalLose = minorDiagonalLoseFlag || majorDiagonalLoseFlag;

            if (minorOrMajorDiagonalLose)
            {
                this.Players[i_PlayerIndex].RoundStatus = minorDiagonalLoseFlag ? eRoundStatus.MinorDiagonalLose : eRoundStatus.MajorDiagonalLose;
                this.Players[GetOtherPlayerIndex(i_PlayerIndex)].RoundStatus = eRoundStatus.Win;
            }

            return(minorOrMajorDiagonalLose);
        }
        /// <summary>
        /// Calculate the node
        /// </summary>
        /// <param name="board">Current board state</param>
        /// <param name="currentPosition">Position in board to set</param>
        /// <param name="currentMove">Current move (either Computer or Human)</param>
        /// <param name="depth">Current depth. Used for choosing earliest winning/losing move</param>
        public MiniMaxNode(Board board, int currentPosition, Board.Cell currentMove, int depth)
        {
            // Create the child nodes list
            this.ChildNodes = new List <MiniMaxNode>();

            // Save the index to the cell we are updating. This way we always know what move
            // this node corresponds to
            this.UpdatedCellIndex = currentPosition;
            // Set the cell to Computer/Human
            board.Cells[this.UpdatedCellIndex] = currentMove;

            if (board.GetState() == Board.State.ComputerWins)
            {
                // If Computer wins, give it a high score, but deduct the current depth
                // (So that quick wins have higher scores than lengthy wins)
                this.Score = 10 - depth;
            }
            else if (board.GetState() == Board.State.HumanWins)
            {
                // If Human wins, give it a low score, but add the current depth
                // (So that quick loses have lower scores than lengthy loses)
                this.Score = -10 + depth;
            }
            else if (board.GetState() == Board.State.Draw)
            {
                // If it's a draw, just set to neutral
                this.Score = 0;
            }
            else
            {
                // Invert the player
                var nextMove = currentMove == Board.Cell.Computer ? Board.Cell.Human : Board.Cell.Computer;

                for (var i = 0; i < Board.BoardSize; i++)
                {
                    // For each empty cell
                    if (board.Cells[i] == Board.Cell.Empty)
                    {
                        // Clone the board
                        var childBoard = board.Clone();
                        // Calculate child moves
                        var miniMaxNode = new MiniMaxNode(childBoard, i, nextMove, depth + 1);
                        ChildNodes.Add(miniMaxNode);
                    }
                }

                if (currentMove == Board.Cell.Computer)
                {
                    // Since this isn't a terminal node, give the current node the best score
                    // amongst the child nodes..
                    this.Score = this.ChildNodes.OrderBy(n => n.Score).First().Score;
                }
                else
                {
                    // ..or for Human moves, give it the worst score amongst the children
                    this.Score = this.ChildNodes.OrderBy(n => n.Score).Last().Score;
                }
            }
        }
Example #5
0
        private bool checkIfPlayerLost(Board.Cell i_LastMove, byte i_PlayerIndex)
        {
            eSign playerSign = this.Players[i_PlayerIndex].Sign;

            bool gameFinishedFlag = this.checkRowOrColLose(i_LastMove, i_PlayerIndex, playerSign);

            if (!gameFinishedFlag && this.isCellOnDiagonal(i_LastMove))
            {
                gameFinishedFlag = this.checkDiagonalLose(i_LastMove, i_PlayerIndex, playerSign);
            }

            return(gameFinishedFlag);
        }
        internal void HandleComputerMove()
        {
            this.m_CurrentNumOfMoves++;
            Board.Cell computerMove = this.r_GameLogic.GetAIMove(this.m_PlayerIndexTurn);
            this.r_GameLogic.RegisterMove(computerMove, this.m_PlayerIndexTurn);
            this.MarkCellWithComputerSign(computerMove, this.m_PlayerIndexTurn);
            this.m_IsGameFinished  = this.r_GameLogic.CheckEndGame(computerMove, this.m_CurrentNumOfMoves, this.m_PlayerIndexTurn);
            this.m_PlayerIndexTurn = GameLogic.GetOtherPlayerIndex(this.m_PlayerIndexTurn);
            if (this.m_IsGameFinished)
            {
                this.showResults(this.m_PlayerIndexTurn);
                this.resetRound();
            }

            this.boldPlayer(k_Player1Index);
        }
Example #7
0
        internal bool CheckEndGame(Board.Cell i_CurrentMove, byte i_CurrentNumOfMoves, byte i_PlayerIndex)
        {
            bool isGameFinished = false;

            if (this.checkIfPlayerLost(i_CurrentMove, i_PlayerIndex))
            {
                isGameFinished = true;
                this.Players[GetOtherPlayerIndex(i_PlayerIndex)].Score++;
            }

            if (!isGameFinished)
            {
                isGameFinished = this.handleFullBoard(i_CurrentNumOfMoves);
            }

            return(isGameFinished);
        }
Example #8
0
        internal void RegisterMove(Board.Cell i_CurrentMove, byte i_PlayerIndex)
        {
            this.Board[i_CurrentMove]            = i_CurrentMove;
            this.Board[i_CurrentMove].m_CellSign = this.Players[i_PlayerIndex].Sign;
            if (this.Players[i_PlayerIndex].PlayerType == ePlayerType.Human)
            {
                this.Players[i_PlayerIndex].m_MovesList.Add(i_CurrentMove);
            }

            CellChosenEventArgs e =
                new CellChosenEventArgs
            {
                m_CellSign  = i_CurrentMove.m_CellSign,
                m_CellIndex = Board.GetCellIndexInBoard(i_CurrentMove)
            };

            OnCellChosen(e);
        }
        internal void MarkCellWithComputerSign(Board.Cell i_ComputerMove, byte i_PlayerIndex)
        {
            bool   found           = false;
            string cellCoordinates = $"{i_ComputerMove.m_CellRow},{i_ComputerMove.m_CellCol}";

            while (!found)
            {
                foreach (Button cellButton in this.r_CellButtons)
                {
                    if (cellButton.Name == cellCoordinates)
                    {
                        found = true;
                        this.changeCellButtonAppearance(cellButton, i_ComputerMove.m_CellSign);
                        break;
                    }
                }
            }
        }
Example #10
0
            private List <Board.Cell> getUnblockingEmptyCells(Board.Cell i_TargetedCell)
            {
                List <Board.Cell> optionalCells = new List <Board.Cell>();

                for (byte rowIndex = 0; rowIndex < this.gameLogic.m_BoardSize; rowIndex++)
                {
                    for (byte colIndex = 0; colIndex < this.gameLogic.m_BoardSize; colIndex++)
                    {
                        if (this.gameLogic.Board[rowIndex, colIndex].m_CellSign == eSign.Empty)
                        {
                            if (rowIndex != i_TargetedCell.m_CellRow &&
                                colIndex != i_TargetedCell.m_CellCol &&
                                !this.gameLogic.isCellOnDiagonal(this.gameLogic.Board[rowIndex, colIndex]))
                            {
                                optionalCells.Add(this.gameLogic.Board[rowIndex, colIndex]);
                            }
                        }
                    }
                }

                return(optionalCells);
            }
Example #11
0
        private bool checkRowOrColLose(Board.Cell i_LastMove, byte i_PlayerIndex, eSign i_PlayerSign)
        {
            bool rowLoseFlag = true;
            bool colLoseFlag = true;
            byte currentCol  = i_LastMove.m_CellCol;
            byte currentRow  = i_LastMove.m_CellRow;

            for (byte colRowIndex = 0; colRowIndex < this.Board.BoardSize && (colLoseFlag || rowLoseFlag); colRowIndex++)
            {
                if (i_LastMove != this.Board[colRowIndex, currentCol])
                {
                    if (colLoseFlag && this.Board[colRowIndex, currentCol].m_CellSign != i_PlayerSign)
                    {
                        colLoseFlag = false;
                    }
                }

                if (i_LastMove != this.Board[currentRow, colRowIndex])
                {
                    if (rowLoseFlag && this.Board[currentRow, colRowIndex].m_CellSign != i_PlayerSign)
                    {
                        rowLoseFlag = false;
                    }
                }
            }

            bool rowOrColLoseFlag = rowLoseFlag || colLoseFlag;

            if (rowOrColLoseFlag)
            {
                this.Players[i_PlayerIndex].RoundStatus = rowLoseFlag ? eRoundStatus.RowLose : eRoundStatus.ColLose;
                this.Players[GetOtherPlayerIndex(i_PlayerIndex)].RoundStatus = eRoundStatus.Win;
            }

            return(rowOrColLoseFlag);
        }
Example #12
0
            private void getRandomCell(out Board.Cell o_ResultMove)
            {
                Random rnd = new Random();

                o_ResultMove = new Board.Cell((byte)rnd.Next(this.gameLogic.m_BoardSize), (byte)rnd.Next(this.gameLogic.m_BoardSize));
            }
Example #13
0
 internal bool CheckCellLegality(Board.Cell o_ResultMove)
 {
     return(this.Board.IsCellInRange(o_ResultMove) && this.Board.IsCellUsed(o_ResultMove));
 }
Example #14
0
 private bool isCellOnDiagonal(Board.Cell i_LastMove)
 {
     return(i_LastMove.m_CellRow == i_LastMove.m_CellCol ||
            i_LastMove.m_CellRow + i_LastMove.m_CellCol + 1 == this.Board.BoardSize);
 }