Exemplo n.º 1
0
        private void FindBishopMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPiecePinDirection)
        {
            //There are NO possible moves if the bishop is under any line threats.
            if (playerPiecePinDirection.HasThreats(ThreatDirection.Line))
            {
                return;
            }

            //we will use the threats matrix for this bishop to calculate our moves...
            var bishopThreatLocations = _threatProvider.FindThreatsForBoardLocation(_board, playerPieceLocation);
            var hasGradeThreats       = playerPiecePinDirection.HasThreats(ThreatDirection.Grade);
            var hasSlopeThreats       = playerPiecePinDirection.HasThreats(ThreatDirection.Slope);

            foreach (var location in bishopThreatLocations.Keys)
            {
                //only add moves that do a capture or move along the same threat vector
                if ((_board.LocationIsEmptyOrOccupiedBy(location, player.OpposingPlayer())) &&
                    ((hasGradeThreats == false) || (location.IsOnSameGradeAs(playerPieceLocation))) &&
                    ((hasSlopeThreats == false) || (location.IsOnSameSlopeAs(playerPieceLocation))))
                {
                    moves.Add(new Move(playerPieceLocation, location, _board[location]));
                }
            }
        }
Exemplo n.º 2
0
        private void FindQueenMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPiecePinDirection)
        {
            //we will use the threats matrix for this queen to calculate our moves...
            var queenThreatLocations = _threatProvider.FindThreatsForBoardLocation(_board, playerPieceLocation);
            var hasVerticalThreats   = playerPiecePinDirection.HasThreats(ThreatDirection.Vertical);
            var hasHorizontalThreats = playerPiecePinDirection.HasThreats(ThreatDirection.Horizontal);
            var hasSlopeThreats      = playerPiecePinDirection.HasThreats(ThreatDirection.Slope);
            var hasGradeThreats      = playerPiecePinDirection.HasThreats(ThreatDirection.Grade);

            foreach (var location in queenThreatLocations.Keys)
            {
                //only add moves that do a capture or move along the same threat vector
                if ((_board.LocationIsEmptyOrOccupiedBy(location, player.OpposingPlayer())) &&
                    ((hasGradeThreats == false) || (location.IsOnSameGradeAs(playerPieceLocation))) &&
                    ((hasSlopeThreats == false) || (location.IsOnSameSlopeAs(playerPieceLocation))) &&
                    ((hasVerticalThreats == false) || (location.IsOnSameColumnAs(playerPieceLocation))) &&
                    ((hasHorizontalThreats == false) || (location.IsOnSameRowAs(playerPieceLocation))))
                {
                    moves.Add(new Move(playerPieceLocation, location, _board[location]));
                }
            }
        }
Exemplo n.º 3
0
        private void FindKnightMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPiecePinDirection)
        {
            //There are NO possible moves if the knight is under non-direct threat because
            //he is not capable of removing any linear or diagonal threats ever. This is due to his L-shaped
            //move pattern (thank god for small favors)
            if (playerPiecePinDirection.HasThreats(ThreatDirection.NonDirect))
            {
                return;
            }

            //we will use the threats matrix for this knight to calculate our moves...
            var knightThreatLocations = _threatProvider.FindThreatsForBoardLocation(_board, playerPieceLocation);

            foreach (var location in knightThreatLocations.Keys)
            {
                if (_board.LocationIsEmptyOrOccupiedBy(location, player.OpposingPlayer()))
                {
                    moves.Add(new Move(playerPieceLocation, location, _board[location]));
                }
            }
        }
Exemplo n.º 4
0
        private void AddPawnThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            ThreatMatrix threatMatrix)
        {
            //PGN format for the board
            //    A  B  C  D  E  F  G  H
            //8:| 7|15|23|31|39|47|55|63|
            //7:| 6|14|22|30|38|46|54|62|
            //6:| 5|13|21|29|37|45|53|61|
            //5:| 4|12|20|28|36|44|52|60|
            //4:| 3|11|19|27|35|43|51|59|
            //3:| 2|10|18|26|34|42|50|58|
            //2:| 1| 9|17|25|33|41|49|57|
            //1:| 0| 8|16|24|32|40|48|56|

            BoardLocation?[] moves = new BoardLocation?[2];
            if (player == Player.White)
            {
                //then we are worried about the black guys pieces
                moves[0] = opposingPieceBoardLocation.SouthEast();
                moves[1] = opposingPieceBoardLocation.SouthWest();
            }
            else
            {
                moves[0] = opposingPieceBoardLocation.NorthEast();
                moves[1] = opposingPieceBoardLocation.NorthWest();
            }

            moves
            .Where(a => a.HasValue)
            .ForEach(a => AddThreat(threatMatrix, playerKingLocation, opposingPieceBoardLocation, a.Value, ThreatDirection.Direct));
        }
Exemplo n.º 5
0
        public void MakeMove(IMove move)
        {
            if (GameIsOver)
            {
                throw new ChessException(ChessErrorCode.InvalidMoveGameOver, "The move is not valid because the game is over.");
            }

            if (!MoveIsLegal(move))
            {
                throw new ChessException(ChessErrorCode.IllegalMove, "The move is not valid because it is not legal.");
            }

            //Make the move
            MakeMoveForMoveType(move);

            //add the history
            _moveHistory.Add(move);

            //clear the moves and threats (for caching of next moves)
            _moves        = null;
            _threatMatrix = null;

            //determine the game state now that this move has been made
            DetermineGameState();
        }
Exemplo n.º 6
0
        private void FindRookMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPiecePinDirection)
        {
            //There are NO possible moves if the rook is under any diagonal threats.
            if (playerPiecePinDirection.HasThreats(ThreatDirection.Diagonal))
            {
                return;
            }

            //we will use the threats matrix for this rook to calculate our moves...
            var rookThreatLocations  = _threatProvider.FindThreatsForBoardLocation(_board, playerPieceLocation);
            var hasVerticalThreats   = playerPiecePinDirection.HasThreats(ThreatDirection.Vertical);
            var hasHorizontalThreats = playerPiecePinDirection.HasThreats(ThreatDirection.Horizontal);

            foreach (var location in rookThreatLocations.Keys)
            {
                //only add moves that do a capture or move along the same threat vector
                if ((_board.LocationIsEmptyOrOccupiedBy(location, player.OpposingPlayer())) &&
                    ((hasVerticalThreats == false) || (location.IsOnSameColumnAs(playerPieceLocation))) &&
                    ((hasHorizontalThreats == false) || (location.IsOnSameRowAs(playerPieceLocation))))
                {
                    moves.Add(new Move(playerPieceLocation, location, _board[location]));
                }
            }
        }
Exemplo n.º 7
0
        private void FindKingCastleMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation)
        {
            //When are you not allowed to castle?
            //    There are a number of cases when castling is not permitted:
            //    -Your king has been moved earlier in the game.
            //    -The rook that castles has been moved earlier in the game.
            //    -There are pieces standing between your king and rook.
            //    -The king is in check.
            //    -The king moves through a square that is attacked by a piece of the opponent.
            //    -The king would be in check after castling.

            if ((KingHasMoved(player)) ||                   //king has moved
                (threats.ContainsKey(playerPieceLocation))) //king in check
            {
                return;
            }

            if (CastleQueensideMoveAvailable(player, threats))
            {
                moves.Add(new Move(playerPieceLocation, player == Player.White ? BoardLocation.C1 : BoardLocation.C8, SpecialMoveType.CastleQueenside));
            }

            if (CastleKingsideMoveAvailable(player, threats))
            {
                moves.Add(new Move(playerPieceLocation, player == Player.White ? BoardLocation.G1 : BoardLocation.G8, SpecialMoveType.CastleKingside));
            }
        }
Exemplo n.º 8
0
 private void AddKingThreats(
     Board board,
     Player player,
     BoardLocation playerKingLocation,
     BoardLocation opposingPieceBoardLocation,
     ThreatMatrix threatMatrix)
 {
     opposingPieceBoardLocation
     .Neighbors()
     .ForEach(a => AddThreat(threatMatrix, playerKingLocation, opposingPieceBoardLocation, a, ThreatDirection.Direct));
 }
Exemplo n.º 9
0
        public IReadOnlyList <IMove> FindMoves()
        {
            if (_moves != null)
            {
                return(_moves);
            }

            var moves = new List <Move>();

            //get threats against current player
            var threats = _threatProvider.FindThreatsForPlayer(_board, CurrentPlayer);

            _threatMatrix = threats;

            if (GameIsOver)
            {
                _moves = moves;
                return(moves);
            }

            //find da man and
            //find if any chumps be threatenin da man
            var playerKingLocation = _board.GetKingsLocation(CurrentPlayer);
            var playerKingThreat   = threats.ContainsKey(playerKingLocation) ? threats[playerKingLocation] : null;

            //if da king has multiple threats then fleeing is his only option
            if (playerKingThreat != null && playerKingThreat.HasMultipleKingThreats)
            {
                //only chance for is for the king to move to a location that is not threatened.
                FindMoves(moves, threats, playerKingLocation);
            }
            else
            {//we have a few more options
                //get all pieces for current player.
                var playerPieceLocations = _board.FindPlayerPieceLocations(CurrentPlayer);

                //find moves for each given piece
                playerPieceLocations
                .ForEach(a => FindMoves(moves, threats, a));

                //if the king is in check, now we need to trim the moves appropriately
                if (playerKingThreat != null)
                {
                    moves = TrimMovesForKingInCheck(moves, threats, playerKingLocation, playerKingThreat);
                }
            }

            //cache the moves
            _moves = moves;

            //return list of available moves
            return(moves);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Finds all threats for the given player and board. Finds all the opposing players
        /// pieces and calculates the threats against the passed in player.
        /// </summary>
        /// <param name="board"></param>
        /// <param name="player"></param>
        /// <returns></returns>
        public ThreatMatrix FindThreatsForPlayer(Board board, Player player)
        {
            //find all opposing pieces
            var opposingPlayer         = player.OpposingPlayer();
            var playerKingLocation     = board.GetKingsLocation(player);
            var opposingPieceLocations = board.FindPlayerPieceLocations(opposingPlayer);

            ThreatMatrix threatMatrix = new ThreatMatrix();

            opposingPieceLocations
            .ForEach(a => AddThreats(board, player, playerKingLocation, a, threatMatrix));

            return(threatMatrix);
        }
Exemplo n.º 11
0
        /// <summary>
        /// Finds all threats generated by the given piece at the specified board location.
        /// returns an empty dictionary if the location does not contain a chess piece.
        /// </summary>
        /// <param name="board"></param>
        /// <param name="boardLocation"></param>
        /// <returns></returns>
        public ThreatMatrix FindThreatsForBoardLocation(Board board, BoardLocation boardLocation)
        {
            ThreatMatrix threatMatrix   = new ThreatMatrix();
            var          chessPiece     = board[boardLocation];
            var          player         = chessPiece.Player().OpposingPlayer();
            var          opposingPlayer = chessPiece.Player();

            if (chessPiece != ChessPiece.None)
            {
                AddThreats(board, player, board.GetKingsLocation(player), boardLocation, threatMatrix);
            }

            return(threatMatrix);
        }
Exemplo n.º 12
0
        private void AddBishopThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            ThreatMatrix threatMatrix)
        {
            //slope
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.NorthWest, threatMatrix);
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.SouthEast, threatMatrix);

            //grade
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.SouthWest, threatMatrix);
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.NorthEast, threatMatrix);
        }
Exemplo n.º 13
0
        private void AddRookThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            ThreatMatrix threatMatrix)
        {
            //horizontal
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.East, threatMatrix);
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.West, threatMatrix);

            //vertical
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.North, threatMatrix);
            AddDirectionalThreats(board, player, playerKingLocation, opposingPieceBoardLocation, Direction.South, threatMatrix);
        }
Exemplo n.º 14
0
        private void AddThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            ThreatMatrix threatMatrix)
        {
            var chessPiece = board[opposingPieceBoardLocation];

            switch (chessPiece)
            {
            case ChessPiece.BlackPawn:
            case ChessPiece.WhitePawn:
                AddPawnThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            case ChessPiece.BlackRook:
            case ChessPiece.WhiteRook:
                AddRookThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            case ChessPiece.BlackKnight:
            case ChessPiece.WhiteKnight:
                AddKnightThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            case ChessPiece.BlackBishop:
            case ChessPiece.WhiteBishop:
                AddBishopThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            case ChessPiece.BlackQueen:
            case ChessPiece.WhiteQueen:
                //queen is rook and bishop so we can cheat it
                AddRookThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                AddBishopThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            case ChessPiece.BlackKing:
            case ChessPiece.WhiteKing:
                AddKingThreats(board, player, playerKingLocation, opposingPieceBoardLocation, threatMatrix);
                break;

            default:
                throw new Exception($"Unexpected chessPiece value {opposingPieceBoardLocation.ToString()}");
            }
        }
Exemplo n.º 15
0
        private List <Move> TrimMovesForKingInCheck(
            List <Move> moves,
            ThreatMatrix threats,
            BoardLocation playerKingLocation,
            Threat playerKingThreat)
        {
            var pieceThreateningKing = Board[playerKingThreat.FirstPieceThreateningKingBoardLocation.Value];

            //if we have a direct threat to the king then the only moves allowed are ones that capture
            //the piece which is threatening the king, or of course the ones that represent the king itself moving
            if (playerKingThreat.ThreatDirection == ThreatDirection.Direct)
            {
                return(moves
                       .Where(a => playerKingLocation == a.Source || a.Destination == playerKingThreat.FirstPieceThreateningKingBoardLocation.Value)
                       .ToList());
            }
            else
            {
                //ok, so if this is a non-direct threat then any move that is either
                //captures the piece in question or blocks the threat path is valid
                //AND of course, any move that represents the king moving
                List <BoardLocation> allowedBoardLocations = new List <BoardLocation>();
                BoardLocation?       currentLocation       = playerKingThreat.FirstPieceThreateningKingBoardLocation.Value;
                var direction = playerKingThreat.ThreatDirection.ToDirection();

                //get all allowable moves
                while ((currentLocation != null) && (currentLocation.Value != playerKingLocation))
                {
                    allowedBoardLocations.Add(currentLocation.Value);

                    currentLocation = currentLocation.Neighbor(direction);
                }

                //get kings moves and remove them from the original moves list and put them into the finalmoves
                var finalMoves = moves.Where(a => a.Source == playerKingLocation).ToList();
                moves.RemoveAll(a => a.Source == playerKingLocation);

                //Now that the moves list only contains the moves that are non king moves, we can simply
                //join to the allowableboardlocations and add this to the final moves
                finalMoves.AddRange(
                    moves
                    .Join(allowedBoardLocations, a => a.Destination, a => a, (a, b) => a));

                return(finalMoves);
            }
        }
Exemplo n.º 16
0
        private void FindMoves(
            List <Move> moves,
            ThreatMatrix threats,
            BoardLocation playerPieceLocation)
        {
            var chessPiece = _board[playerPieceLocation];
            var player     = chessPiece.Player();
            var playerPiecePinDirection = threats.ContainsKey(playerPieceLocation) ? threats[playerPieceLocation].Pin : default(ThreatDirection?);

            switch (chessPiece)
            {
            case ChessPiece.BlackPawn:
            case ChessPiece.WhitePawn:
                FindPawnMoves(moves, threats, player, playerPieceLocation, playerPiecePinDirection);
                break;

            case ChessPiece.BlackKnight:
            case ChessPiece.WhiteKnight:
                FindKnightMoves(moves, threats, player, playerPieceLocation, playerPiecePinDirection);
                break;

            case ChessPiece.BlackBishop:
            case ChessPiece.WhiteBishop:
                FindBishopMoves(moves, threats, player, playerPieceLocation, playerPiecePinDirection);
                break;

            case ChessPiece.BlackRook:
            case ChessPiece.WhiteRook:
                FindRookMoves(moves, threats, player, playerPieceLocation, playerPiecePinDirection);
                break;

            case ChessPiece.BlackQueen:
            case ChessPiece.WhiteQueen:
                FindQueenMoves(moves, threats, player, playerPieceLocation, playerPiecePinDirection);
                break;

            case ChessPiece.BlackKing:
            case ChessPiece.WhiteKing:
                //da king cant be pinned yo!
                FindKingMoves(moves, threats, player, playerPieceLocation);
                break;

            default:
                break;
            }
        }
Exemplo n.º 17
0
 private bool CastleKingsideMoveAvailable(Player player, ThreatMatrix threats)
 {
     if (player == Player.White)
     {
         return
             ((!_moveHistory.Any(a => a.Source == BoardLocation.H1)) &&                             //rook has not moved
              (!threats.ContainsKey(BoardLocation.F1) && !threats.ContainsKey(BoardLocation.G1)) && //no threats in path
              (_board[BoardLocation.G1].IsEmpty() && _board[BoardLocation.G1].IsEmpty()));          //path is empty
     }
     else
     {
         return
             ((!_moveHistory.Any(a => a.Source == BoardLocation.H8)) &&                             //rook has not moved
              (!threats.ContainsKey(BoardLocation.F8) && !threats.ContainsKey(BoardLocation.G8)) && //no threats in path
              (_board[BoardLocation.F8].IsEmpty() && _board[BoardLocation.G8].IsEmpty()));          //path is empty
     }
 }
Exemplo n.º 18
0
        private void AddThreat(
            ThreatMatrix threatMatrix,
            BoardLocation playerKingLocation,
            BoardLocation threateningPieceLocation,
            BoardLocation boardLocationBeingThreatening,
            ThreatDirection direction,
            ThreatDirection?pin = null)
        {
            if (!threatMatrix.ContainsKey(boardLocationBeingThreatening))
            {
                threatMatrix.Add(boardLocationBeingThreatening, direction, pin);
            }
            else
            {
                //update the threat direction
                threatMatrix[boardLocationBeingThreatening].AddDirection(direction);

                //can only be pinned in one direction (since there is only one king)
                if (pin != null)
                {
                    threatMatrix[boardLocationBeingThreatening].AddPin(pin.Value);
                }
            }

            //if this is a king threat
            if (playerKingLocation == boardLocationBeingThreatening)
            {
                //we set the piece that is threatening the king here. Please note that it is possible more than one piece
                //is threatening the king but it is IMPOSSIBLE for a triple check to occur.
                var threat = threatMatrix[boardLocationBeingThreatening];
                if (threat.FirstPieceThreateningKingBoardLocation.HasValue)
                {
                    threat.SecondPieceThreateningKingBoardLocation = threateningPieceLocation;
                }
                else
                {
                    threat.FirstPieceThreateningKingBoardLocation = threateningPieceLocation;
                }
            }
        }
Exemplo n.º 19
0
        private void FindKingMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation)
        {
            //we will use the threats matrix for this king to calculate our moves...
            var kingThreatLocations = _threatProvider.FindThreatsForBoardLocation(_board, playerPieceLocation);

            foreach (var location in kingThreatLocations.Keys)
            {
                //only add moves that do not have a threat on them
                if ((_board.LocationIsEmptyOrOccupiedBy(location, player.OpposingPlayer())) &&
                    (threats.ContainsKey(location) == false))
                {
                    moves.Add(new Move(playerPieceLocation, location, _board[location]));
                }
            }

            //find our castle moves
            FindKingCastleMoves(moves, threats, player, playerPieceLocation);
        }
Exemplo n.º 20
0
        public void UndoLastMove()
        {
            if (_moveHistory?.Any() == false)
            {
                throw new ChessException(ChessErrorCode.UndoMoveIllegal,
                                         $"Unable to undo last move because no moves have been made");
            }

            //undo this move now
            var lastMove = _moveHistory[_moveHistory.Count - 1];

            UndoLastMoveForMoveType(lastMove);

            _moveHistory.RemoveAt(_moveHistory.Count - 1);

            //clear the moves and threats (for caching of next moves)
            _moves        = null;
            _threatMatrix = null;

            //we put the game back into play. We KNOW we can do this because we are
            //UNDOING a previous move which means the game MUST have been in play in order to allow the move
            //to be made in the first place.
            GameState = GameState.InPlay;
        }
Exemplo n.º 21
0
        private void AddDirectionalThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            Direction direction,
            ThreatMatrix threatMatrix)
        {
            //get the next square in the given direction
            BoardLocation?currentLocation = opposingPieceBoardLocation.Neighbor(direction);

            //for directional threats the king might be pinned...
            var kingCouldBePinned = playerKingLocation.IsInGivenDirectionFrom(opposingPieceBoardLocation, direction);
            var threatDirection   = direction.ToThreatDirection();

            while (currentLocation != null)
            {
                //get the piece
                var piece = board[currentLocation.Value];

                //as long as we are empty we can keep moving!
                if (piece == ChessPiece.None)
                {
                    //empty square, no pin possible
                    AddThreat(threatMatrix, playerKingLocation, opposingPieceBoardLocation, currentLocation.Value, threatDirection);
                }
                else
                {
                    ThreatDirection?pinDirection = null;

                    //our piece which MIGHT have a pin if our king is on the same directional vector..check for it
                    if ((piece.BelongsTo(player)) &&
                        (kingCouldBePinned) &&
                        PieceIsPinned(board, currentLocation.Value, playerKingLocation, direction))
                    {
                        pinDirection = direction.ToThreatDirection();
                    }

                    AddThreat(
                        threatMatrix,
                        playerKingLocation,
                        opposingPieceBoardLocation,
                        currentLocation.Value,
                        threatDirection,
                        pinDirection);

                    //NOTE: This is a hack, but its a domain hack. From a threat perspective, we can pretend
                    //that the enemy king is 'invisible'. This will allow long range threats to penetrate the king
                    //and proceed to any columns, rows, or diagonals he is on. This in turn will help us
                    //when determining the kings moves by making 'backing up' an invalid strategy for him.
                    //without this check, a king himself would demarcate the end of a long range threat (since a piece is like a stop)
                    //but THAT would create the problem of making it seem like the square behind him was 'safe'. For Example:
                    //   |  |  |  |  |         |  |  |  |  |
                    //   |  |WR|BK|  |  To=>   |  |WR|  |BK|  would be allowed
                    //   |  |  |  |  |         |  |  |  |  |
                    //Where it is kind of a hack is by treating the king as invisible it means the white rook is threatening
                    //'beyond' a piece. Theoretically, this would then also allow it to move into those spaces, in essence just
                    //'hoping over' the king. This would be a HUGE problem if not for the golden rule of chess that it is impossible
                    //to make a move that actually captures a king. The game literally ends as soon as a board state emerges where
                    //a king is able to captured on the next turn. Not sure why this is, I am sure it harkens back to some
                    //haughty rule about how 'ignoble' it would be to ever allow the capture of a royal.
                    if (piece.IsKing(player) == false)
                    {
                        //short circuit search since we are done
                        break;
                    }
                }

                currentLocation = currentLocation.Neighbor(direction);
            }
        }
Exemplo n.º 22
0
        private void AddKnightThreats(
            Board board,
            Player player,
            BoardLocation playerKingLocation,
            BoardLocation opposingPieceBoardLocation,
            ThreatMatrix threatMatrix)
        {
            //PGN format for the board
            //    A  B  C  D  E  F  G  H
            //8:| 7|15|23|31|39|47|55|63|
            //7:| 6|  |22|  |38|46|54|62|
            //6:|  |13|21|29|  |45|53|61|
            //5:| 4|12|20|28|36|44|52|60|
            //4:|  |11|19|27|  |43|51|59|
            //3:| 2|  |18|  |34|42|50|58|
            //2:| 1| 9|17|25|33|41|49|57|
            //1:| 0| 8|16|24|32|40|48|56|

            //A knights move from postion 20.
            //-17
            //-15
            //-10
            //-6
            //+17
            //+15
            //+10
            //+6

            List <BoardLocation> possibleMoves = new List <BoardLocation>();
            var knightLocation = opposingPieceBoardLocation.ToByte();

            //same column
            var leftDown = knightLocation - 17;
            var leftUp   = knightLocation - 15;
            //same row
            var upLeft  = knightLocation - 6;
            var upRight = knightLocation + 10;
            //same column
            var rightUp   = knightLocation + 17;
            var rightDown = knightLocation + 15;
            //same row
            var downLeft  = knightLocation - 10;
            var downRight = knightLocation + 6;

            if ((leftDown >= 0) &&
                ((knightLocation / 8) - (leftDown / 8) == 2))
            {
                possibleMoves.Add((BoardLocation)leftDown);
            }
            if ((leftUp >= 0) &&
                ((knightLocation / 8) - (leftUp / 8) == 2))
            {
                possibleMoves.Add((BoardLocation)leftUp);
            }

            if ((upLeft >= 0) &&
                ((knightLocation / 8) - (upLeft / 8) == 1))
            {
                possibleMoves.Add((BoardLocation)upLeft);
            }
            if ((downLeft >= 0) &&
                ((knightLocation / 8) - (downLeft / 8) == 1))
            {
                possibleMoves.Add((BoardLocation)downLeft);
            }

            if ((upRight < Constants.BoardSize) &&
                ((knightLocation / 8) - (upRight / 8) == -1))
            {
                possibleMoves.Add((BoardLocation)upRight);
            }
            if ((downRight < Constants.BoardSize) &&
                ((knightLocation / 8) - (downRight / 8) == -1))
            {
                possibleMoves.Add((BoardLocation)downRight);
            }

            if ((rightUp < Constants.BoardSize) &&
                ((knightLocation / 8) - (rightUp / 8) == -2))
            {
                possibleMoves.Add((BoardLocation)rightUp);
            }
            if ((rightDown < Constants.BoardSize) &&
                ((knightLocation / 8) - (rightDown / 8) == -2))
            {
                possibleMoves.Add((BoardLocation)rightDown);
            }

            possibleMoves
            .ForEach(a => AddThreat(threatMatrix, playerKingLocation, opposingPieceBoardLocation, a, ThreatDirection.Direct));
        }
Exemplo n.º 23
0
        private void FindPawnMoves(
            List <Move> moves,
            ThreatMatrix threats,
            Player player,
            BoardLocation playerPieceLocation,
            ThreatDirection?playerPieceThreatDirection)
        {
            var opposingPlayer       = player.OpposingPlayer();
            var marchDirection       = player == Player.White ? Direction.North : Direction.South;
            var gradeAttackDirection = player == Player.White ? Direction.NorthEast : Direction.SouthWest;
            var slopeAttackDirection = player == Player.White ? Direction.NorthWest : Direction.SouthEast;

            //check to see if we can move up/down
            //note that any diagonal or horizontal threats will block these moves
            if ((playerPieceThreatDirection.HasThreats(ThreatDirection.Horizontal | ThreatDirection.Diagonal) == false) &&
                (_board.NeighboringLocationIsEmpty(playerPieceLocation, marchDirection)))
            {
                var firstMarchLocation = playerPieceLocation.Neighbor(marchDirection).Value;
                var row = firstMarchLocation.Row();
                if (row == 0 || row == 7)//we can assume this is a pawn promotion
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionKnight));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionBishop));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionRook));
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation, SpecialMoveType.PawnPromotionQueen));
                }
                else
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation));
                }

                //we can also move up two spaces if the next northern square is empty
                if ((playerPieceLocation.IsPawnStartingLocation(player)) &&
                    (_board.NeighboringLocationIsEmpty(firstMarchLocation, marchDirection)))
                {
                    moves.Add(new Move(playerPieceLocation, firstMarchLocation.Neighbor(marchDirection).Value));
                }
            }

            //check to see if we can move along the grade
            //note that any line or slope threats will block this move
            if (playerPieceThreatDirection.HasThreats(ThreatDirection.Line | ThreatDirection.Slope) == false)
            {
                //if we have an opposing piece in the next square, make hte move
                if (_board.NeighboringLocationIsOccupiedBy(playerPieceLocation, gradeAttackDirection, opposingPlayer))
                {
                    var neighbor = playerPieceLocation.Neighbor(gradeAttackDirection).Value;
                    var row      = neighbor.Row();

                    //capture pawn promotion
                    if (row == 0 || row == 7)
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionKnight));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionBishop));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionRook));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionQueen));
                    }
                    else//normal capture
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor]));
                    }
                }
                else if (LastMoveAllowsEnPassantFor(playerPieceLocation, gradeAttackDirection))
                {//we can do an en passant.
                    var neighbor = playerPieceLocation.Neighbor(gradeAttackDirection).Value;
                    moves.Add(new Move(playerPieceLocation, neighbor, CurrentPlayer == Player.White ? ChessPiece.BlackPawn : ChessPiece.WhitePawn, SpecialMoveType.AuPassant));
                }
            }

            //check to see if we can move along the slope
            //note that any line or grade threats will block this move
            if (playerPieceThreatDirection.HasThreats(ThreatDirection.Line | ThreatDirection.Grade) == false)
            {
                //if we have an opposing piece in the next square, make hte move
                if (_board.NeighboringLocationIsOccupiedBy(playerPieceLocation, slopeAttackDirection, opposingPlayer))
                {
                    var neighbor = playerPieceLocation.Neighbor(slopeAttackDirection).Value;
                    var row      = neighbor.Row();

                    //capture pawn promotion
                    if (row == 0 || row == 7)
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionKnight));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionBishop));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionRook));
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor], SpecialMoveType.PawnPromotionQueen));
                    }
                    else//normal capture
                    {
                        moves.Add(new Move(playerPieceLocation, neighbor, _board[neighbor]));
                    }
                }
                else if (LastMoveAllowsEnPassantFor(playerPieceLocation, slopeAttackDirection))
                {//we can do an en passant.
                    var neighbor = playerPieceLocation.Neighbor(slopeAttackDirection).Value;
                    moves.Add(new Move(playerPieceLocation, neighbor, CurrentPlayer == Player.White ? ChessPiece.BlackPawn : ChessPiece.WhitePawn, SpecialMoveType.AuPassant));
                }
            }
        }