Пример #1
0
        private bool mayKingMoveOrthogonallyHere(AttackedSquare clearMove, IEnumerable <AttackedSquare> attacksOnKing, List <AttackedSquare> attacks)
        {
            var kingSquare = (Square)attacksOnKing.First();
            //need to detect if we're moving into check
            var anybodyAttackingThisSquare = attacks.Any(a => a.Index == clearMove.Index && a.AttackingSquare.Piece.Color != kingSquare.Piece.Color);

            if (anybodyAttackingThisSquare)
            {
                return(false);
            }
            //now make sure we're not ignoring the issue where an attack isn't displayed because the king was blocking the square
            //that he would move into, that is still being attacked by the original attacker.
            var isRankMove = GeneralEngine.GivenOrthogonalMove_IsItARankMove(clearMove.AttackingSquare.Index, clearMove.Index);
            //find all attackers who attack orthogonally and determine if they are on the same line
            var orthogonalAttacksOnKing = attacksOnKing.Where(a => orthogonalAttackers.Contains(a.AttackingSquare.Piece.PieceType));

            foreach (var x in orthogonalAttacksOnKing)
            {
                var oxs = getEntireOrthogonalLine(isRankMove ? false : true, x);
                //if oxs contains the clearMove.Index, then the king has not moved out of check
                if (oxs.Contains(clearMove.Index))
                {
                    return(false);
                }
            }
            return(true);
        }
Пример #2
0
 /// <summary>
 /// In the future, I should be passing back all the moves rather than a boolean
 /// that way the engine can have metadata about all the possible moves that
 /// could be taken and maybe offer a suggestion.
 /// </summary>
 /// <param name="attacksOnKing"></param>
 /// <param name="teamAttacks"></param>
 /// <returns></returns>
 private bool interpositionsExist(IEnumerable <AttackedSquare> attacksOnKing, IEnumerable <AttackedSquare> teamAttacks)
 {
     foreach (var attackOnKing in attacksOnKing)
     {
         var attackIsOrthogonal = GeneralEngine.IsOrthogonal(attackOnKing.AttackingSquare.Index, attackOnKing.Index);
         var attackIsDiagonal   = DiagonalEngine.IsDiagonal(attackOnKing.AttackingSquare.Index, attackOnKing.Index);
         var range = new List <Square>();
         if (attackIsOrthogonal)
         {
             var isRankMove = GeneralEngine.GivenOrthogonalMove_IsItARankMove(attackOnKing.AttackingSquare.Index, attackOnKing.Index);
             var oxs        = getEntireOrthogonalLine(isRankMove, attackOnKing, true);
             var ixs        = teamAttacks.Select(a => a.Index).Intersect(oxs);
             if (ixs.Any())
             {
                 return(true);
             }
         }
         else if (attackIsDiagonal)
         {
             var dxs = DiagonalEngine.GetDiagonalLine(attackOnKing.AttackingSquare.Index, attackOnKing.Index);
             //if dxs contains the clearMove.Index, then the king has not moved out of check
             var ixs = teamAttacks.Select(a => a.Index).Intersect(dxs);
             if (ixs.Any())
             {
                 return(true);
             }
         }
         //else it could be a knight attack, but no interpositions would exist
     }
     return(false);
 }
Пример #3
0
        public List <AttackedSquare> GetOrthogonalLine(GameState gameState, Square square, Direction direction)
        {
            var attacks               = new List <AttackedSquare>();
            var currentPosition       = square.Index;
            var lineTerminator        = getOrthogonalLineTerminator(direction, currentPosition);
            var iterator              = getIteratorByDirectionEnum(direction);
            var nextPositionInTheLine = currentPosition + iterator;

            for (var position = nextPositionInTheLine; position != lineTerminator; position = position + iterator)
            {
                var isValidCoordinate = GeneralEngine.IsValidCoordinate(position);
                if (!isValidCoordinate)
                {
                    break;
                }
                var moveViability = GeneralEngine.DetermineMoveViability(gameState, square.Piece, position);
                //these conditions shouldn't occur
                if (!moveViability.IsValidCoordinate || moveViability.SquareToAdd == null)
                {
                    continue;
                }
                var attack = new AttackedSquare(square, moveViability.SquareToAdd, isProtecting: moveViability.IsTeamPiece);
                attacks.Add(attack);
                if (moveViability.SquareToAdd.Occupied)
                {
                    break;
                }
            }
            return(attacks);
        }
Пример #4
0
        private bool isValidKnightMove(int position, int tempPosition, int file, int rank)
        {
            var isValidCoordinate = GeneralEngine.IsValidCoordinate(tempPosition);

            if (!isValidCoordinate)
            {
                return(false);
            }

            var tempCoord = NotationEngine.PositionToCoordinate(tempPosition);
            var tempFile  = NotationEngine.FileToInt(tempCoord[0]);
            var tempRank  = (int)tempCoord[1];

            var fileDiff = Math.Abs(tempFile - file);
            var rankDiff = Math.Abs(tempRank - rank);

            if (fileDiff > 2 || fileDiff < 1)
            {
                return(false);
            }
            if (rankDiff > 2 || rankDiff < 1)
            {
                return(false);
            }

            return(true);
        }
Пример #5
0
 public void IsOrthogonal()
 {
     Assert.IsTrue(GeneralEngine.IsOrthogonal(0, 7));
     Assert.IsTrue(GeneralEngine.IsOrthogonal(7, 0));
     Assert.IsTrue(GeneralEngine.IsOrthogonal(56, 0));
     Assert.IsTrue(GeneralEngine.IsOrthogonal(0, 56));
     Assert.IsFalse(GeneralEngine.IsOrthogonal(0, 9));
 }
Пример #6
0
        private bool kingMovesExist(GameState gameState, Color kingColor, IEnumerable <AttackedSquare> attacksOnKing)
        {
            var opponentAttacks = gameState.Attacks.Where(a => a.AttackingSquare.Piece.Color == kingColor.Reverse()).ToList();
            var kingMoves       = gameState.Attacks
                                  .Where(a =>
                                         a.AttackingSquare.Piece.PieceType == PieceType.King &&
                                         a.AttackingSquare.Piece.Color == kingColor &&
                                         !a.IsProtecting
                                         ).ToList();
            var clearMoves = kingMoves.Select(a => a.Index).Except(opponentAttacks.Select(b => b.Index));

            if (!clearMoves.Any())
            {
                return(false);
            }
            //todo: there is a bug here: when the king is checked like so (5rk1/5pbp/5Qp1/8/8/8/5PPP/3q2K1 w - - 0 1)
            //he is boxed in, but h1 looks a valid move for him because the Queen doesn't currently have it as an attack square
            //because the King is blocking it.
            //fix this by examining if the king is moving orthoganally or diagonally and determine if any attackers are on that line as well
            var clearMoveCount = clearMoves.Count();

            foreach (var clearMoveIndex in clearMoves)
            {
                //clearMove.AttackerSquare is the king here
                //clearMove.Index is where he is going
                var clearMove        = kingMoves.GetSquare(clearMoveIndex);
                var isOrthogonal     = GeneralEngine.IsOrthogonal(clearMove.AttackingSquare.Index, clearMove.Index);
                var _mayKingMoveHere = false;
                if (isOrthogonal)
                {
                    _mayKingMoveHere = this.mayKingMoveOrthogonallyHere(clearMove, attacksOnKing, gameState.Attacks);
                    if (!_mayKingMoveHere)
                    {
                        clearMoveCount--;
                    }
                }
                else
                {
                    //has to be diagonal
                    _mayKingMoveHere = this.mayKingMoveDiagonallyHere(clearMove, attacksOnKing, gameState.Attacks);
                    if (!_mayKingMoveHere)
                    {
                        clearMoveCount--;
                    }
                }
            }
            return(clearMoveCount > 0);
        }
Пример #7
0
        private static (bool IsValid, bool CanAttackOccupyingPiece) basicMoveValidity(Color pieceColor, Square square)
        {
            if (!square.Occupied)
            {
                // go for it
                return(true, true);
            }

            // if it is your teammate, you can't do that
            if (GeneralEngine.IsTeamPiece(pieceColor, square.Piece))
            {
                return(true, true);
            }
            else
            {
                return(true, false);
            }
        }
Пример #8
0
        private void getKnightAttacks(GameState gameState, Square square, List <AttackedSquare> accumulator)
        {
            var squares            = gameState.Squares;
            var currentPosition    = square.Index;
            var pieceColor         = square.Piece.Color;
            var attacks            = new List <AttackedSquare>();
            var coord              = NotationEngine.PositionToCoordinate(currentPosition);
            var file               = NotationEngine.FileToInt(coord[0]);
            var rank               = (int)coord[1];
            var potentialPositions = new List <int> {
                6, 10, 15, 17, -6, -10, -15, -17
            };

            foreach (var potentialPosition in potentialPositions)
            {
                var position           = currentPosition + potentialPosition;
                var _isValidKnightMove = isValidKnightMove(currentPosition, position, file, rank);
                var _isValidMove       = isValidMove(accumulator, gameState, square, position, pieceColor);
                var _isValidCoordinate = GeneralEngine.IsValidCoordinate(position);

                if (!_isValidKnightMove || !_isValidMove.IsValid || !_isValidCoordinate)
                {
                    continue;
                }

                var attackedSquare = squares.GetSquare(position);
                if (!attackedSquare.Occupied)
                {
                    attacks.Add(new AttackedSquare(square, attackedSquare));
                }
                else
                {
                    attacks.Add(new AttackedSquare(square, attackedSquare, isProtecting: attackedSquare.Piece.Color == pieceColor));
                }
            }
            if (attacks.Any())
            {
                accumulator.AddRange(attacks);
            }
        }
Пример #9
0
 public List <int> GetEntireRank(int rank)
 {
     return(GeneralEngine.GetEntireRank(rank));
 }
Пример #10
0
 public List <int> GetEntireFile(int file)
 {
     return(GeneralEngine.GetEntireFile(file));
 }
Пример #11
0
        private void getKingAttacks(GameState gameState, Square square, List <AttackedSquare> accumulator)
        {
            var attacks    = new List <AttackedSquare>();
            var squares    = gameState.Squares;
            var offsets    = getKingOffsets(square.Index);
            var pieceColor = square.Piece.Color;

            foreach (var offset in offsets)
            {
                var destinationPosition = square.Index + offset;
                var isValidCoordinate   = GeneralEngine.IsValidCoordinate(destinationPosition);
                if (!isValidCoordinate)
                {
                    continue;
                }
                var _isValidMove = isValidMove(accumulator, gameState, square, destinationPosition, pieceColor);
                if (!_isValidMove.IsValid)
                {
                    continue;
                }
                attacks.Add(
                    new AttackedSquare(square, squares.GetSquare(destinationPosition), isProtecting: !_isValidMove.CanAttackOccupyingPiece)
                    );
            }

            //*********************
            //castling stuff
            //*********************
            var castleAvailability = gameState.CastlingAvailability;

            if (pieceColor == Color.White)
            {
                if (castleAvailability.Contains("K"))
                {
                    addCastleAttackIfPossible(
                        square,
                        attacks,
                        squares,
                        7,
                        new List <int> {
                        5, 6
                    },
                        6
                        );
                }
                if (castleAvailability.Contains("Q"))
                {
                    addCastleAttackIfPossible(
                        square,
                        attacks,
                        squares,
                        0,
                        new List <int> {
                        1, 2, 3
                    },
                        2
                        );
                }
            }
            else if (pieceColor == Color.Black)
            {
                if (castleAvailability.Contains("k"))
                {
                    addCastleAttackIfPossible(
                        square,
                        attacks,
                        squares,
                        63,
                        new List <int> {
                        61, 62
                    },
                        62
                        );
                }
                if (castleAvailability.Contains("q"))
                {
                    addCastleAttackIfPossible(
                        square,
                        attacks,
                        squares,
                        56,
                        new List <int> {
                        57, 58, 59
                    },
                        58
                        );
                }
            }
            //*********************
            //end castling stuff
            //*********************

            if (!attacks.Any())
            {
                return;
            }
            accumulator.AddRange(attacks);
        }
Пример #12
0
        private (bool IsValid, bool CanAttackOccupyingPiece) isValidMove(List <AttackedSquare> attacks, GameState gameState, Square locationSquare, int destination, Color pieceColor)
        {
            var isValidCoordinate = GeneralEngine.IsValidCoordinate(destination);

            if (!isValidCoordinate || !gameState.Squares.Any(a => a.Index == destination))
            {
                // throw new Exception($"Invalid position passed: { position }");
                // probably doing this just as an easy way to not have to trim squares from every algorithm
                return(false, false);
            }
            var destinationSquare = gameState.Squares.GetSquare(destination);

            // if you're not a king you've got simpler rules
            // but if you're the king, you still have to obey the basics
            var basics = basicMoveValidity(pieceColor, destinationSquare);

            if (locationSquare.Piece.PieceType != PieceType.King || !basics.CanAttackOccupyingPiece)
            {
                return(basics);
            }

            // check to make sure that this move would get us out of check
            var newPositionAttacks = attacks.Where(a => a.Index == destination && a.AttackingSquare.Piece.Color != locationSquare.Piece.Color);

            if (newPositionAttacks.Any())
            {
                // king can't move into check
                return(true, false);
            }
            // no-one is attacking the destination that we can tell, let's make sure
            // piece currently being attacked?
            var attacksOnThisPosition = attacks.Where(a => a.Index == locationSquare.Index && a.AttackingSquare.Piece.Color != locationSquare.Piece.Color);

            if (!attacksOnThisPosition.Any())
            {
                // nobody is attacking this king now, or in the new position
                return(true, true);
            }
            var dangerSquares = attacksOnThisPosition.Where(a => _dangerPieceTypes.Contains(a.AttackingSquare.Piece.PieceType) && a.AttackingSquare.Piece.Color != locationSquare.Piece.Color);

            if (!dangerSquares.Any())
            {
                // nobody dangerous is attacking this king now, or in the new position
                return(true, true);
            }
            // which direction are we moving?
            var directionInfo = GeneralEngine.GetDirectionInfo(locationSquare.Index, destination);
            var directionalDangerPieceTypes = directionInfo.IsDiagonal ? _diagonalDangerPieceTypes : _orthogonalFangerPieceTypes;
            var directionalDangerSquares    = attacksOnThisPosition.Where(a => directionalDangerPieceTypes.Contains(a.AttackingSquare.Piece.PieceType) && a.AttackingSquare.Piece.Color != locationSquare.Piece.Color);

            foreach (var dangerSquare in directionalDangerSquares)
            {
                // is that going to get us out of the attack path that this piece would normally have?
                var dangerPieceDirectionInfo = GeneralEngine.GetDirectionInfo(dangerSquare.AttackingSquare.Index, locationSquare.Index);
                if (dangerPieceDirectionInfo.IsDiagonal && directionInfo.IsOrthogonal)
                {
                    // won't intersect paths
                    continue;
                }
                if (dangerPieceDirectionInfo.IsOrthogonal && directionInfo.IsDiagonal)
                {
                    // won't intersect paths
                    continue;
                }

                if (dangerPieceDirectionInfo.IsDiagonal && directionInfo.IsDiagonal)
                {
                    // are we moving on the same diagonal plane?
                    if (dangerPieceDirectionInfo.DiagonalDirection == directionInfo.DiagonalDirection)
                    {
                        // not safe
                        return(false, false);
                    }
                }
                if (dangerPieceDirectionInfo.IsOrthogonal && directionInfo.IsOrthogonal)
                {
                    // are we moving on the same orthogonal plane?
                    if (dangerPieceDirectionInfo.Direction == directionInfo.Direction)
                    {
                        // not safe
                        return(false, false);
                    }
                }
            }
            // safe
            return(true, true);
        }