Example #1
0
        /*
         * Check if this move puts the king in a less secure position.
         * Returns 0 if does not involve king, 1000 if move protects king, and -1000 if move leaves open spot next to king.
         */
        private static float EvaluateKingSafety(Dictionary <Square, AiChessPiece> board, Square initial, Square target, string owner)
        {
            AiChessPiece initialPiece = board[initial];

            if (initialPiece.Type == "king" && initialPiece.Owner.Name == owner)
            {
                return(0);
            }

            List <AiChessPiece> initialSurroundings = AiMovementUtil.SurroundingPieces(board, initial);
            List <AiChessPiece> targetSurroundings  = AiMovementUtil.SurroundingPieces(board, target);

            float score = 0;

            if (initialSurroundings.Any(piece => piece.Type == "king" && piece.Owner.Name == owner))
            {
                score -= 1000;
            }
            if (targetSurroundings.Any(piece => piece.Type == "king" && piece.Owner.Name == owner))
            {
                score += 1000;
            }

            return(score);
        }
Example #2
0
        // Logic for handling a move being made in AI evaluation
        private static void MakeMove(Dictionary <Square, AiChessPiece> board, ref float[,] strength, Stack <ChessMove> moves, ChessMove move, ref AiChessPiece holder, ref float[,] holderStrength, Player player, ref bool[] commanderState)
        {
            holderStrength = strength.Clone() as float[, ];
            moves.Push(move);

            AiChessPiece piece = board[move.InitialSquare];

            // make the next move
            if (move.Attack)
            {
                holder = board[move.TargetSquare];
                board.Remove(move.TargetSquare);
                if (!move.AttackOnly)
                {
                    board.Remove(move.InitialSquare);
                    board.Add(move.TargetSquare, piece);
                    piece.Position = move.TargetSquare;
                }
            }
            else
            {
                board.Remove(move.InitialSquare);
                board.Add(move.TargetSquare, piece);
                piece.Position = move.TargetSquare;
            }

            player.Commanders[piece.GetDivision()].Moved = true;
            //player.RemainingMoves--;
            commanderState[0] = player.Commanders["M"].Moved;
            commanderState[1] = player.Commanders["R"].Moved;
            commanderState[2] = player.Commanders["L"].Moved;
        }
Example #3
0
        public static List <Square> GetPossibleMoves(Dictionary <Square, AiChessPiece> board, AiChessPiece piece, bool updateStrength, float[,] strength)
        {
            string        owner         = piece.Owner.Name;
            int           direction     = owner == "player1" ? 1 : -1;
            List <Square> possibleMoves = null;

            switch (piece.Type)
            {
            case "pawn":
            case "bishop": {
                possibleMoves = InfantryMoves(piece.Position, direction, updateStrength, strength);
                break;
            }

            case "king":
            case "queen": {
                possibleMoves = RoyaltyMoves(board, piece.Position, 3, owner, updateStrength, strength);
                break;
            }

            case "knight": {
                possibleMoves = RoyaltyMoves(board, piece.Position, 4, owner, updateStrength, strength);
                break;
            }

            case "rook": {
                possibleMoves = ArcherMoves(board, piece.Position, owner, updateStrength, strength);
                break;
            }
            }

            List <Square> cleaned     = new List <Square>();
            List <Square> surrounding = MovementUtil.SurroundingSquares(piece.Position);

            foreach (Square s in possibleMoves.Where(s => ChessGrid.ValidPosition(s)))
            {
                if (board.ContainsKey(s))
                {
                    if (piece.Type != "knight" && !s.AttackOnly && !surrounding.Contains(s))
                    {
                        // remove this if statement if we want pieces to be able to attack any squares they can reach
                        continue;
                    }
                    AiChessPiece target = board[s];
                    if (target.Owner == piece.Owner)
                    {
                        continue;
                    }
                }
                cleaned.Add(s);
            }
            return(cleaned);
        }
Example #4
0
        private const int Randomness        = 0; // Degree of randomness, random number between -val to +val is added to each rating

        private static void EvaluateAiMove(Dictionary <Square, AiChessPiece> board, float[,] strength, Player currentPlayer)
        {
            List <ChessMove>     moves   = GetMovesForPlayer(board, strength, currentPlayer);
            List <Task <float> > threads = new List <Task <float> >();

            for (int i = 0; i < NumThreads; i++)
            {
                Player threadedPlayer = new Player(currentPlayer);

                List <ChessMove> threadedMoves = new List <ChessMove>();
                int threadIndex = _turns.Count;

                // split up best moves
                for (int j = 0; j < moves.Count; j += NumThreads)
                {
                    if (j + threadIndex >= moves.Count)
                    {
                        continue;
                    }
                    threadedMoves.Add(moves[j + threadIndex]);
                }

                // store new board for thread
                Dictionary <Square, AiChessPiece> threadedBoard = new Dictionary <Square, AiChessPiece>();
                foreach (Square s in board.Keys)
                {
                    AiChessPiece p = board[s];
                    threadedBoard.Add(s, new AiChessPiece(p.Name, p.Owner, p.Type, p.Position));
                }

                // init new strength for thread
                float[,] threadedStrength = EvaluationValues.InitStrength(threadedBoard);

                _turns.Add(new List <ChessMove[]>());
                _ratings.Add(new List <float>());
                _boards.Add(threadedBoard);

                Task <float> thread = new Task <float>(() => Minimax(threadedMoves, threadedBoard, threadedStrength, new Stack <ChessMove>(),
                                                                     threadedPlayer, TurnSearchDepth, 3, threadIndex, 0));
                threads.Add(thread);
                thread.Start();
            }

            // Wait for all threads to join
            foreach (Task <float> t in threads)
            {
                t.Wait();
            }
        }
Example #5
0
        // Movement for the Rook and its Attack range
        private static List <Square> ArcherMoves(Dictionary <Square, AiChessPiece> board, Square start, string owner, bool updateStrength, float[,] strength)
        {
            int           direction = owner == "player1" ? 1 : -1;
            List <Square> moves     = MovementUtil.SurroundingSquares(start);

            foreach (Square s in moves)
            {
                if (!board.ContainsKey(s))
                {
                    continue;
                }
                AiChessPiece target = board[s];
                if (target.Owner.Name != owner)
                {
                    s.AttackOnly = true;
                }
            }

            for (int i = -3; i <= 3; i++)
            {
                for (int j = -3; j <= 3; j++)
                {
                    if (i == 0 && j == 0)
                    {
                        continue;
                    }
                    Square s = new Square(start.X + i, start.Y + j);
                    if (updateStrength && ChessGrid.ValidPosition(s))
                    {
                        strength[s.X, s.Y] += direction * EvaluationValues.PieceStrength["rook"];
                    }
                    if (!board.ContainsKey(s))
                    {
                        continue;
                    }
                    AiChessPiece target = board[s];
                    if (target.Owner.Name != owner)
                    {
                        moves.Add(new Square(s.X, s.Y, true));
                    }
                }
            }
            return(moves);
        }
Example #6
0
        public float EvaluateChessMove(Dictionary <Square, AiChessPiece> board, float[,] strength, Square initialSquare, Square targetSquare, string owner)
        {
            AiChessPiece        initialPiece        = board[initialSquare];
            List <AiChessPiece> initialSurroundings = AiMovementUtil.SurroundingPieces(board, initialSquare);
            List <AiChessPiece> targetSurroundings  = AiMovementUtil.SurroundingPieces(board, targetSquare);
            float initial = EvaluateChessSquare(strength, initialSquare, owner, initialPiece.Type, initialSurroundings);
            float target  = EvaluateChessSquare(strength, targetSquare, owner, initialPiece.Type, targetSurroundings);
            var   score   = target - initial; // take into account if the target square is better than initial square

            if (targetSurroundings.Any(p => p.Type == "king" && p.Owner.Name != owner))
            {
                score += 30;
            }
            if (board.ContainsKey(targetSquare))
            {
                score += 20; // be more aggressive
                AiChessPiece targetPiece = board[targetSquare];
                score += weightEvalPriority * EvaluatePiecePriority(targetPiece);
                score += weightEvalWinChance * EvaluateWinChance(board, strength, initialPiece, targetPiece);
            }
            score += weightEvalKingSafety * EvaluateKingSafety(board, initialSquare, targetSquare, owner);
            return(score * (owner == "player1" ? 1 : -1));
        }
Example #7
0
        // Logic for handling a move being unmade in AI evaluation
        private static void UnmakeMove(Dictionary <Square, AiChessPiece> board, ref float[,] strength, Stack <ChessMove> moves, ref AiChessPiece holder, ref float[,] holderStrength, Player player, ref bool[] commanderState)
        {
            strength = holderStrength.Clone() as float[, ];
            ChessMove    move = moves.Pop();
            AiChessPiece piece;

            if (!move.Attack)
            {
                piece = board[move.TargetSquare];
                board.Remove(move.TargetSquare);
                board.Add(move.InitialSquare, piece);
                piece.Position = move.InitialSquare;
            }
            else
            {
                if (!move.AttackOnly)
                {
                    piece = board[move.TargetSquare];
                    board.Remove(move.TargetSquare);
                    board.Add(move.InitialSquare, piece);
                    piece.Position = move.InitialSquare;
                }
                board.Add(move.TargetSquare, holder);
                holder.Position = move.TargetSquare;
            }

            //player.RemainingMoves++;
            player.Commanders["M"].Moved = commanderState[0];
            player.Commanders["R"].Moved = commanderState[1];
            player.Commanders["L"].Moved = commanderState[2];
        }
Example #8
0
        // Get all possible moves for a piece on the board
        private static List <ChessMove> GetMovesForPiece(Dictionary <Square, AiChessPiece> board, float[,] strength, AiChessPiece piece)
        {
            List <Square>    possibleSquares = AiMovementUtil.GetPossibleMoves(board, piece, false, null);
            List <ChessMove> possibleMoves   = new List <ChessMove>();

            foreach (Square s in possibleSquares)
            {
                if (piece.Position.Equals(s))
                {
                    continue;
                }
                ChessMove move = new ChessMove(board, piece.Position, s,
                                               EvaluateMove.Instance.EvaluateChessMove(board, strength, piece.Position, s, piece.Owner.Name));
                move.AttackOnly = s.AttackOnly;
                possibleMoves.Add(move);
            }
            return(possibleMoves);
        }
Example #9
0
        // Recursively find best moves
        private static float Minimax(List <ChessMove> allMoves, Dictionary <Square, AiChessPiece> board, float[,] strength, Stack <ChessMove> moveStack, Player currentPlayer, int turnDepth, int moveDepth, int threadIndex, int turnIndex)
        {
            // Base case
            if (turnDepth == 0)
            {
                return(EvaluationValues.BoardEvaluate(board, strength, false));
            }

            // If new turn, switch players
            if (moveDepth == 0)
            {
                Player opposite = currentPlayer.Name == "player1" ? Game.Controller.Player2 : Game.Controller.Player1;
                opposite.Commanders["M"].Moved    = false;
                opposite.Commanders["R"].Moved    = false;
                opposite.Commanders["L"].Moved    = false;
                _ratings[threadIndex][turnIndex] += Minimax(GetMovesForPlayer(board, strength, opposite), board, strength, moveStack,
                                                            opposite, turnDepth - 1, 3, threadIndex, turnIndex);
            }
            else
            {
                int movesSearched = 0;
                // Iterate over possible moves
                for (int i = 0; i < allMoves.Count; i++)
                {
                    if (i >= allMoves.Count || movesSearched >= PossibleMoveDepth)
                    {
                        break;
                    }

                    ChessMove move = allMoves[i];
                    if (!board.ContainsKey(move.InitialSquare) || move.Attack && !board.ContainsKey(move.TargetSquare))
                    {
                        continue;
                    }

                    int parentNodes = 3 - moveDepth;

                    // Store results in _turns
                    if (turnDepth == TurnSearchDepth)
                    {
                        turnIndex = GetIndex(_turns[threadIndex], _ratings[threadIndex]);
                        for (int j = 0; j < parentNodes; j++)
                        {
                            _turns[threadIndex][turnIndex][j] = moveStack.Skip(parentNodes - j - 1).First();
                            _ratings[threadIndex][turnIndex] += _ratings[threadIndex][turnIndex - (j + 1)];
                        }
                    }

                    movesSearched++;
                    _totalMovesSearched++;
                    if (turnDepth == TurnSearchDepth)
                    {
                        _turns[threadIndex][turnIndex][parentNodes] = move;
                    }

                    // Save state of piece/board before making a move
                    AiChessPiece holder = null;
                    float[,] holderStrength = null;
                    bool[] commanderState = new bool[3];

                    // Make a move
                    MakeMove(board, ref strength, moveStack, move, ref holder, ref holderStrength, currentPlayer, ref commanderState);

                    // Determine next best move
                    _ratings[threadIndex][turnIndex] += Minimax(GetMovesForPlayer(board, strength, currentPlayer), board, strength,
                                                                moveStack, currentPlayer, turnDepth, moveDepth - 1, threadIndex, turnIndex);

                    // Unmake move
                    UnmakeMove(board, ref strength, moveStack, ref holder, ref holderStrength, currentPlayer, ref commanderState);
                }
            }

            return(EvaluationValues.BoardEvaluate(board, strength, false));
        }
Example #10
0
        /**
         * Evaluate the win change against an enemy piece.
         */
        private static float EvaluateWinChance(Dictionary <Square, AiChessPiece> board, float[,] strength, AiChessPiece initial, AiChessPiece target)
        {
            List <AiChessPiece> surroundings = AiMovementUtil.SurroundingPieces(board, initial.Position);
            bool addOne = false;

            switch (initial.Type)
            {
            case "knight":
            {
                if (!surroundings.Contains(target))
                {
                    addOne = true;
                }

                break;
            }

            case "rook":
                return(10 * EvaluationValues.PieceValues[target.Type]);
            }

            float minRoll = CaptureMatrix.GetMin(initial.Type, target.Type, addOne);

            if (minRoll > 6)
            {
                return(-10000);
            }
            return(minRoll);
        }
Example #11
0
 /**
  * Evaluate the priority of an enemy piece.
  */
 private static float EvaluatePiecePriority(AiChessPiece target)
 {
     return(EvaluationValues.PieceValues[target.Type]);
 }