Untitled

 avatar
unknown
plain_text
2 years ago
7.7 kB
5
Indexable
using Piskvorky_JanNeuC3a;
using System;
using System.Threading.Tasks;

namespace Piskvorky_JanNeuC3a
{
    class ComputerPlayer : Player
    {

        private const Int32 BEST_VALUE = 1000;
        private const Int32 WORST_VALUE = -1000;
        private const Int32 VICTORY_VALUE = 10;


        private event Action<Move> BestMoveFound;

        private bool _isFirstTurn = true;
        private Board.ElementType _computer = Board.ElementType.O;
        private Board.ElementType _opponent = Board.ElementType.X;

        private DifficultyType _difficulty;

        public ComputerPlayer(DifficultyType difficulty)
        {
            _difficulty = difficulty;

            BestMoveFound += ComputerPlayer_BestMoveFound;
        }

        private void ComputerPlayer_BestMoveFound(Move bestMove)
        {
            CurrentBoard[bestMove.Row, bestMove.Col] = _computer;
            CurrentBoard.UpdateBoardUI();
        }


        protected override Task MakeTurnAsync()
        {
            Action action = () =>
            {
                if (PlayersTurn == TicTacToe.Turn.PlayerX)
                {
                    _computer = Board.ElementType.X;
                    _opponent = Board.ElementType.O;
                }
                else
                {
                    _isFirstTurn = false;
                    _computer = Board.ElementType.O;
                    _opponent = Board.ElementType.X;
                }

                var bestMove = new Move();
                if (_isFirstTurn)
                {
                    bestMove = Move.Random(0, 3, 0, 3);
                    _isFirstTurn = false;
                }
                else
                {
                    var maxDepth = 0;
                    switch (_difficulty)
                    {
                        case DifficultyType.Easy:
                            maxDepth = 1;
                            break;
                        case DifficultyType.Medium:
                            maxDepth = 4;
                            break;
                        case DifficultyType.Hard:
                            maxDepth = 7;
                            break;
                        default:
                            break;
                    }

                    bestMove = FindBestMove(CurrentBoard, maxDepth);
                }

                BestMoveFound.Invoke(bestMove);
            };
            var task = Task.Factory.StartNew(action);

            return task;
        }

        public override void OnPlayerMoved()
        {
            throw new NotImplementedException();
        }


        #region BestMoveCalculation
        private Move FindBestMove(Board board, Int32 maxDepth)
        {
            Int32 bestVal = WORST_VALUE;
            Move bestMove = new Move
            {
                Row = -1,
                Col = -1
            };

            for (var i = 0; i < board.WIDTH; i++)
            {
                for (var j = 0; j < board.HEIGHT; j++)
                {
                    if (board[i, j] == Board.ElementType.Empty)
                    {
                        board[i, j] = _computer;

                        Int32 moveVal = Minimax(board, 0, maxDepth, false);

                        board[i, j] = Board.ElementType.Empty;

                        if (moveVal > bestVal)
                        {
                            bestMove.Row = i;
                            bestMove.Col = j;
                            bestVal = moveVal;
                        }
                    }
                }
            }

            return bestMove;
        }

        private Int32 Minimax(Board board, Int32 depth, Int32 maxDepth, bool isMax)
        {
            Int32 score = Evaluate(board);

            if (score == VICTORY_VALUE || score == -VICTORY_VALUE)
                return score - depth;

            if (!board.IsMovesLeft() || depth == maxDepth)
                return 0;

            if (isMax)
            {
                Int32 best = WORST_VALUE;

                for (Int32 i = 0; i < board.WIDTH; i++)
                {
                    for (Int32 j = 0; j < board.HEIGHT; j++)
                    {
                        if (board[i, j] == Board.ElementType.Empty)
                        {
                            board[i, j] = _computer;

                            best = Math.Max(best,
                                Minimax(board, depth + 1, maxDepth, !isMax));
                            board[i, j] = Board.ElementType.Empty;
                        }
                    }
                }
                return best;
            }
            else
            {
                Int32 best = BEST_VALUE;

                for (Int32 i = 0; i < board.WIDTH; i++)
                {
                    for (Int32 j = 0; j < board.HEIGHT; j++)
                    {
                        if (board[i, j] == Board.ElementType.Empty)
                        {
                            board[i, j] = _opponent;

                            best = Math.Min(best, Minimax(board, depth + 1, maxDepth, !isMax));

                            board[i, j] = Board.ElementType.Empty;
                        }
                    }
                }
                return best;
            }
        }
        private Int32 Evaluate(Board board)
        {

            for (var row = 0; row < board.WIDTH; row++)
            {
                if (board[row, 0] == board[row, 1] &&
                    board[row, 1] == board[row, 2])
                {
                    if (board[row, 0] == _computer)
                        return VICTORY_VALUE;
                    else if (board[row, 0] == _opponent)
                        return -VICTORY_VALUE;
                }
            }


            for (Int32 col = 0; col < board.HEIGHT; col++)
            {
                if (board[0, col] == board[1, col] &&
                    board[1, col] == board[2, col])
                {
                    if (board[0, col] == _computer)
                        return VICTORY_VALUE;

                    else if (board[0, col] == _opponent)
                        return -VICTORY_VALUE;
                }
            }


            if (board[0, 0] == board[1, 1] && board[1, 1] == board[2, 2])
            {
                if (board[0, 0] == _computer)
                    return VICTORY_VALUE;
                else if (board[0, 0] == _opponent)
                    return -VICTORY_VALUE;
            }

            if (board[0, 2] == board[1, 1] && board[1, 1] == board[2, 0])
            {
                if (board[0, 2] == _computer)
                    return VICTORY_VALUE;
                else if (board[0, 2] == _opponent)
                    return -VICTORY_VALUE;
            }

            return 0;
        }
        #endregion

        private struct Move
        {
            public Int32 Row { get; set; }
            public Int32 Col { get; set; }

            public static Move Random(Int32 minRow, Int32 maxRow, Int32 minCol, Int32 maxCol)
            {
                Random random = new Random();

                Int32 row = random.Next(minRow, maxRow);
                Int32 col = random.Next(minCol, maxCol);

                Move move = new Move()
                {
                    Row = row,
                    Col = col
                };

                return move;
            }
        };
    }
}
Editor is loading...