Пример #1
0
        public void SetGameStateSnapshot(GameState oldGameState, GameState newGameState, StateInfo stateInfo, int piecePosition, int newPiecePosition)
        {
            var fenPosition          = getFENPosition(newGameState.Squares);
            var castlingAvailability = getCastlingAvailability(newGameState, newGameState.CastlingAvailability, piecePosition, newPiecePosition);
            var enPassantCoord       = getEnPassantCoord(newGameState.Squares, newGameState.ActiveColor, piecePosition, newPiecePosition);
            var newHalfmoveClock     = getHalfmoveClock(oldGameState.Squares, oldGameState.HalfmoveClock, piecePosition, newPiecePosition);
            var activeColor          = newGameState.ActiveColor.Reverse();

            newGameState.PiecePlacement        = fenPosition;
            newGameState.ActiveColor           = activeColor;
            newGameState.CastlingAvailability  = castlingAvailability;
            newGameState.EnPassantTargetSquare = enPassantCoord;
            if (enPassantCoord != "-")
            {
                newGameState.EnPassantTargetPosition = NotationEngine.CoordinateToPosition(enPassantCoord);
            }
            newGameState.HalfmoveClock = newHalfmoveClock;
            //better to calculate this value after setting the ActiveColor
            var fullmoveNumber = getFullmoveNumber(newGameState.FullmoveNumber, newGameState.ActiveColor);

            newGameState.FullmoveNumber = fullmoveNumber;
            var pgnMove = stateInfo.IsPawnPromotion
                ? _pgnService.SquarePairToPGNMove(oldGameState, oldGameState.ActiveColor, piecePosition, newPiecePosition, stateInfo.PawnPromotedTo)
                : _pgnService.SquarePairToPGNMove(oldGameState, oldGameState.ActiveColor, piecePosition, newPiecePosition);

            newGameState.PGNMoves.Add(pgnMove);
            newGameState.PGN = getUpdatedPGN(newGameState, oldGameState.ActiveColor, fullmoveNumber, pgnMove);
        }
Пример #2
0
        private string squarePairToPGNMove(GameState gameState, Color playerColor, string startSquare, string endSquare)
        {
            var startPos = NotationEngine.CoordinateToPosition(startSquare);
            var endPos   = NotationEngine.CoordinateToPosition(endSquare);

            return(squarePairToPGNMove(gameState, playerColor, startPos, endPos));
        }
Пример #3
0
        private OperationResult verifyMove(GameState gameState, int piecePosition, int newPiecePosition)
        {
            var oldSquare = gameState.Squares.GetSquare(piecePosition);
            var attacks   = gameState.Attacks.GetPositionAttacksOnPosition(piecePosition, newPiecePosition);

            if (!attacks.Any())
            {
                return(OperationResult.Fail($"Can't find an attack by this piece ({ oldSquare.Index } : { oldSquare.Piece.PieceType }) on this position ({ newPiecePosition })."));
            }
            var badPawnAttacks = attacks.Where(a =>
                                               a.AttackingSquare.Index == piecePosition &&
                                               a.Index == newPiecePosition &&
                                               a.Piece == null &&
                                               a.MayOnlyMoveHereIfOccupiedByEnemy
                                               );

            if (badPawnAttacks.Any())
            {
                if (
                    badPawnAttacks.Count() > 1 ||
                    gameState.EnPassantTargetSquare == "-" ||
                    newPiecePosition != NotationEngine.CoordinateToPosition(gameState.EnPassantTargetSquare)
                    )
                {
                    return(OperationResult.Fail($"This piece can only move here if the new square is occupied. ({ oldSquare.Index } : { oldSquare.Piece.PieceType }) on this position ({ newPiecePosition })."));
                }
            }
            return(OperationResult.Ok());
        }
Пример #4
0
        public OperationResult <GameState> MakeMove(GameState gameState, string beginning, string destination, PieceType?piecePromotionType = null)
        {
            var pos1 = NotationEngine.CoordinateToPosition(beginning);
            var pos2 = NotationEngine.CoordinateToPosition(destination);

            return(this.MakeMove(gameState, pos1, pos2, piecePromotionType));
        }
Пример #5
0
        private Square pgnLength4(GameState gameState, IEnumerable <AttackedSquare> potentialPositions, string newPgnMove)
        {
            var        ambiguityResolver = newPgnMove[1];
            var        isRank            = IsRank(ambiguityResolver); // this could be either a rank or a file
            List <int> ambiguityResolutionSet;

            if (isRank)
            {
                int rank = 0;
                Int32.TryParse(ambiguityResolver.ToString(), out rank);
                ambiguityResolutionSet = this._orthogonalService.GetEntireRank(rank - 1);// needs to be using zero-based rank offset
            }
            else
            {
                var iFile = NotationEngine.FileToInt(ambiguityResolver);
                ambiguityResolutionSet = this._orthogonalService.GetEntireFile(iFile);
            }
            var intersection = potentialPositions.Select(a => a.AttackingSquare.Index).Intersect(ambiguityResolutionSet);

            if (intersection.Count() > 1)
            {
                throw new Exception("There should not be more than one item found here.");
            }
            return(gameState.Squares.GetSquare(intersection.First()));
        }
Пример #6
0
        private string squarePairToPGNMove(GameState gameState, Color playerColor, int startPos, int endPos)
        {
            var destinationSquare = gameState.Squares.GetSquare(endPos);
            var isCapture         = destinationSquare.Occupied && destinationSquare.Piece.Color != playerColor;

            var attacks = gameState.Attacks.Where(a => a.AttackingSquare.Index == startPos);

            if (attacks == null || !attacks.Any() || !attacks.Any(a => a.Index == endPos))
            {
                throw new Exception("No attacks can be made on this ending square.");
            }

            var square = gameState.Squares.GetSquare(startPos);

            if (!square.Occupied)
            {
                throw new Exception("Bad coordinates were given.");
            }

            var piece = square.Piece;

            if (piece.Color != playerColor)
            {
                throw new Exception("Color doesn't match given positions.");
            }
            var notationPiece = char.ToUpper(piece.Identity);
            var coord         = NotationEngine.PositionToCoordinate(endPos);
            var pgnMove       = getPgnMove(notationPiece, piece, coord, startPos, endPos, isCapture, gameState);

            return(pgnMove);
        }
Пример #7
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);
        }
Пример #8
0
        private (int position, char promotedPiece, bool isCastle) getPositionFromPGNMove(string pgnMove, Color playerColor, string enPassantTargetSquare)
        {
            var promotedPiece = '-';
            var isCastle      = castlePattern.IsMatch(pgnMove);

            if (isCastle)
            {
                var castleResult = getCastlePositionFromPGNMove(pgnMove, playerColor, promotedPiece);
                return(castleResult.position, castleResult.promotedPiece, true);
            }
            var isEnPassant = false;

            if (enPassantTargetSquare != "-")
            {
                var isCapture = pgnMove[1] == 'x';
                if (isCapture)
                {
                    var len = pgnMove.Length;
                    if (len >= 6)
                    {
                        var rightSide = pgnMove.Substring(4, len - 4);
                        isEnPassant = rightSide.Contains("ep") || rightSide.Contains("e.p.");
                        if (isEnPassant)
                        {
                            return(NotationEngine.CoordinateToPosition(enPassantTargetSquare), promotedPiece, false);
                        }
                    }
                }
            }

            // could be a pawn promotion
            var pawnCapturePromotion = pawnCapturePromotionPattern.IsMatch(pgnMove);
            var pawnPromotion        = pawnPromotionPattern.IsMatch(pgnMove);

            if (pawnCapturePromotion || pawnPromotion)
            {
                // yeah, it is a pawn promotion
                promotedPiece = pgnMove.Last();
                if (promotedPiece == '+' || promotedPiece == '#')
                {
                    promotedPiece = pgnMove.Substring(pgnMove.Length - 2, 1)[0];
                }
                var dest = pawnCapturePromotion ? pgnMove.Substring(2, 2) : pgnMove.Substring(0, 2);
                return(NotationEngine.CoordinateToPosition(dest), promotedPiece, false);
            }
            // probably just a regular move
            pgnMove = pgnMove.Replace("x", "").Replace("+", "").Replace("#", "");
            // not sure why I needed this
            var x = 2;

            if (pgnMove.Contains("="))
            {
                x = 4;
                throw new Exception("I didn't think this could happen, so I tested it with an exception.");
            }
            return(NotationEngine.CoordinateToPosition(pgnMove.Substring(pgnMove.Length - x, 2)), promotedPiece, false);
        }
Пример #9
0
        private Square pgnLength5(GameState gameState, string newPgnMove)
        {
            var _file = NotationEngine.FileToInt(newPgnMove[1]);
            var _rank = 0;

            Int32.TryParse(newPgnMove[2].ToString(), out _rank);
            var pos = NotationEngine.CoordinatePairToPosition(_file, _rank);

            return(gameState.Squares.GetSquare(pos));
        }
Пример #10
0
        private Square getOriginationPositionForCastling(GameState gameState, Color color)
        {
            var rank        = color == Color.White ? 1 : 8;
            var file        = 4;
            var fileChar    = NotationEngine.IntToFile(file);
            var coord       = string.Concat(fileChar, rank);
            var origination = NotationEngine.CoordinateToPosition(coord);

            return(gameState.Squares.GetSquare(origination));
        }
Пример #11
0
        private Square pgnLength3(IEnumerable <AttackedSquare> potentialPositions, string newPgnMove)
        {
            var ambiguityResolver = newPgnMove[0];
            var files             = this._orthogonalService.GetEntireFile(NotationEngine.FileToInt(ambiguityResolver)); // this will always be a file if this is a pawn
            var potentialSquares  = potentialPositions.Where(a => files.Contains(a.AttackingSquare.Index)).ToList();

            if (potentialSquares.Count() > 1)
            {
                throw new Exception("There should not be more than one item found here.");
            }
            return(potentialSquares.First().AttackingSquare);
        }
Пример #12
0
        public OperationResult <GameState> MakeMove(GameState gameState, string pgnMove)
        {
            var pair = _pgnService.PGNMoveToSquarePair(gameState, pgnMove);

            //todo: what about piece promotion?
            if (pair.promotedPiece == '-')
            {
                return(this.MakeMove(gameState, pair.piecePosition, pair.newPiecePosition));
            }
            var promotedPieceType = NotationEngine.GetPieceTypeFromCharacter(pair.promotedPiece);

            return(this.MakeMove(gameState, pair.piecePosition, pair.newPiecePosition, promotedPieceType));
        }
Пример #13
0
        private void getPawnDiagonalAttack(List <Square> squares, Square square, Color pieceColor, int fileIndicator, int nextRank, List <AttackedSquare> attacks)
        {
            var pos            = NotationEngine.CoordinatePairToPosition(fileIndicator, nextRank);
            var attackedSquare = squares.GetSquare(pos);

            if (attackedSquare.Occupied && attackedSquare.Piece.Color != pieceColor)
            {
                attacks.Add(new AttackedSquare(square, attackedSquare, false, true));
            }
            else
            {
                attacks.Add(new AttackedSquare(square, attackedSquare, false, true, true));
            }
        }
Пример #14
0
        public OperationResult <StateInfo> GetStateInfo(GameState gameState, int piecePosition, int newPiecePosition)
        {
            var newActiveColor = gameState.ActiveColor.Reverse();
            var stateInfo      = new StateInfo();
            var oldSquare      = gameState.Squares.GetSquare(piecePosition);

            var isValidCastleAttempt = this.IsValidCastleAttempt(gameState, oldSquare, newPiecePosition, gameState.Attacks);

            if (isValidCastleAttempt.Success)
            {
                stateInfo.IsCastle = isValidCastleAttempt.Result;
            }
            else
            {
                return(OperationResult <StateInfo> .Fail(isValidCastleAttempt.Message));
            }

            stateInfo.IsPawnPromotion = this.isPawnPromotion(oldSquare, newPiecePosition);
            if (gameState.EnPassantTargetSquare != "-" && oldSquare.Piece.PieceType == PieceType.Pawn)
            {
                var pawnEnPassantPosition = NotationEngine.CoordinateToPosition(gameState.EnPassantTargetSquare);
                if (newPiecePosition == pawnEnPassantPosition)
                {
                    stateInfo.IsEnPassant = true;
                }
            }

            var isResign = false;
            var isDraw   = false;

            // todo: i don't think we can get here
            // also, this is incomplete
            if (isDraw || isResign)
            {
                if (isDraw)
                {
                    var score = string.Concat(" ", "1/2-1/2");
                    gameState.PGN += score;
                }
                if (isResign)
                {
                    var score = string.Concat(" ", newActiveColor == Color.White ? "1-0" : "0-1");
                    gameState.PGN += score;
                }
            }

            return(OperationResult <StateInfo> .Ok(stateInfo));
        }
Пример #15
0
        private string getEnPassantCoord(List <Square> squares, Color activeColor, int piecePosition, int newPiecePosition)
        {
            var piece = squares.GetPiece(newPiecePosition);

            if (piece.PieceType != PieceType.Pawn)
            {
                return("-");
            }
            var diff = Math.Abs(piecePosition - newPiecePosition);

            if (diff != 16)
            {//16 is two rows
                return("-");
            }
            var moveMarker      = activeColor == Color.White ? 8 : -8;
            var enPassantSquare = piecePosition + moveMarker;

            return(NotationEngine.PositionToCoordinate(enPassantSquare));
        }
Пример #16
0
        private string getPGNMoveBeginState(char notationPiece, string coord, int startPos, int endPos, bool isCapture)
        {
            string pgnMove = string.Empty;

            switch (notationPiece)
            {
            case 'P':
                if (isCapture)
                {
                    var file = NotationEngine.PositionToFileChar(startPos);
                    pgnMove = string.Concat(file, coord);
                }
                else
                {
                    pgnMove = coord;
                }
                break;

            case 'K':
                var moveDiff = startPos - endPos;
                switch (moveDiff)
                {
                case -2:
                    pgnMove = "O-O";
                    break;

                case 2:
                    pgnMove = "O-O-O";
                    break;

                default:
                    pgnMove = string.Concat(notationPiece, coord);
                    break;
                }
                break;

            default:
                pgnMove = string.Concat(notationPiece, coord);
                break;
            }
            return(pgnMove);
        }
Пример #17
0
        private void getPawnAttacks(GameState gameState, Square square, List <AttackedSquare> accumulator)
        {
            var squares    = gameState.Squares;
            var position   = square.Index;
            var pieceColor = square.Piece.Color;
            var coord      = NotationEngine.PositionToCoordinate(position);
            int file       = NotationEngine.FileToInt(coord[0]);
            int rank       = NotationEngine.PositionToRankInt(position);

            var directionIndicator = pieceColor == Color.White ? 1 : -1;
            var homeRankIndicator  = pieceColor == Color.White ? 2 : 7;

            var nextRank             = (rank + directionIndicator);
            var aheadOneRankPosition = NotationEngine.CoordinatePairToPosition(file, nextRank);
            var aheadOneRankSquare   = squares.GetSquare(aheadOneRankPosition);
            var attacks = new List <AttackedSquare>();

            if (!aheadOneRankSquare.Occupied)
            {
                //can't attack going forward
                attacks.Add(new AttackedSquare(square, aheadOneRankSquare, true));
            }

            managePawnAttacks(squares, square, pieceColor, file, rank, directionIndicator, homeRankIndicator, nextRank, attacks, aheadOneRankSquare.Occupied);

            //add en passant position: -1 indicates null here
            if (gameState.EnPassantTargetSquare != "-")
            {
                var enPassantTargetPosition = NotationEngine.CoordinateToPosition(gameState.EnPassantTargetSquare);
                var leftPos  = NotationEngine.CoordinatePairToPosition(file - 1, nextRank);
                var rightPos = NotationEngine.CoordinatePairToPosition(file + 1, nextRank);
                if (enPassantTargetPosition == leftPos || enPassantTargetPosition == rightPos)
                {
                    var enPassantSquare = squares.GetSquare(enPassantTargetPosition);
                    attacks.Add(new AttackedSquare(square, enPassantSquare));
                }
            }
            if (attacks.Any())
            {
                accumulator.AddRange(attacks);
            }
        }
Пример #18
0
        public List <Square> GetSquares(Snapshot fen)
        {
            var squares = new List <Square>();
            var rows    = fen.PiecePlacement.Split('/');

            for (int i = 0; i < 8; i++)
            {
                int rowIndex = 7 - i;
                //leftSideIndex is the left side of the board, in numbers: 0 8 16 24 32 40 48 56
                int leftSideIndex = 8 * (rowIndex);
                int charIndex     = 0;
                var row           = rows[i];
                foreach (char c in row)
                {
                    if (char.IsNumber(c))
                    {
                        int advanceSquare = 0;
                        Int32.TryParse(c.ToString(), out advanceSquare);
                        //gotta make empty squares
                        for (int j = 0; j < advanceSquare; j++)
                        {
                            var index = leftSideIndex + charIndex + j;
                            squares.Add(
                                new Square(index, NotationEngine.PositionToCoordinate(index), null)
                                );
                        }
                        //in FEN we move ahead the number of squares that the number says
                        charIndex = charIndex + advanceSquare;
                    }
                    else
                    {
                        var index = leftSideIndex + charIndex;
                        squares.Add(
                            new Square(index, NotationEngine.PositionToCoordinate(index), NotationEngine.GetPieceFromCharacter(c))
                            );
                        charIndex++;
                    }
                }
            }
            return(squares.OrderBy(a => a.Index).ToList());
        }
Пример #19
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);
            }
        }
Пример #20
0
        public static Snapshot Create(string fen)
        {
            // 5 could be a bad number
            if (fen.Length < 5 || !fen.Contains(' '))
            {
                return(null);
            }
            var fenRecord = new Snapshot();
            var gameData  = fen.Split(' ');

            fenRecord.PiecePlacement = gameData[0];

            fenRecord.ActiveColor = gameData[1][0] == 'w' ? Color.White : Color.Black;

            fenRecord.CastlingAvailability = gameData[2];

            fenRecord.EnPassantTargetSquare = gameData[3];
            if (fenRecord.EnPassantTargetSquare != "-")
            {
                fenRecord.EnPassantTargetPosition = NotationEngine.CoordinateToPosition(fenRecord.EnPassantTargetSquare);
            }

            var enPassantTargetPosition = -1;

            Int32.TryParse(gameData[3], out enPassantTargetPosition);
            fenRecord.EnPassantTargetPosition = enPassantTargetPosition;

            int halfmoveClock = 0;

            Int32.TryParse(gameData[4], out halfmoveClock);
            fenRecord.HalfmoveClock = halfmoveClock;

            int fullmoveNumber = 0;

            Int32.TryParse(gameData[5], out fullmoveNumber);
            fenRecord.FullmoveNumber = fullmoveNumber;

            return(fenRecord);
        }
Пример #21
0
        private void managePawnAttacks(List <Square> squares, Square square, Color pieceColor, int file, int rank, int directionIndicator, int homeRankIndicator, int nextRank, List <AttackedSquare> attacks, bool aheadOneRankSquareOccupied)
        {
            var notOnFarLeftFile  = file - 1 >= 0;
            var notOnFarRightFile = file + 1 <= 7;

            if (notOnFarLeftFile)
            {
                //get attack square on left
                var fileIndicator = file - 1;
                getPawnDiagonalAttack(squares, square, pieceColor, fileIndicator, nextRank, attacks);
            }
            if (notOnFarRightFile)
            {
                //get attack square on right
                var fileIndicator = file + 1;
                getPawnDiagonalAttack(squares, square, pieceColor, fileIndicator, nextRank, attacks);
            }
            //can't move ahead two if the one in front of you is blocked.
            if (aheadOneRankSquareOccupied)
            {
                return;
            }
            //have to plus one here because rank is zero based and coordinate is base 1
            //if this pawn is on it's home rank, then add a second attack square.
            var isOnHomeRank = rank + 1 == homeRankIndicator;

            if (isOnHomeRank)
            {
                var forwardOne          = nextRank + directionIndicator;
                var rankForwardPosition = NotationEngine.CoordinatePairToPosition(file, forwardOne);
                var rankForwardSquare   = squares.GetSquare(rankForwardPosition);
                //pawns don't attack forward, so we don't have attacks when people occupy ahead of us
                if (!rankForwardSquare.Occupied)
                {
                    attacks.Add(new AttackedSquare(square, rankForwardSquare, true));
                }
            }
        }
Пример #22
0
        private int getOrthogonalLineTerminator(Direction direction, int position)
        {
            var file     = NotationEngine.PositionToFileInt(position);
            var rank     = NotationEngine.PositionToRankInt(position);
            var iterator = getIteratorByDirectionEnum(direction);

            switch (direction)
            {
            case Direction.Forward:
                return(this.GetEntireFile(file).Max() + iterator);

            case Direction.Backward:
                return(this.GetEntireFile(file).Min() + iterator);

            case Direction.Right:
                return(this.GetEntireRank(rank).Max() + iterator);

            case Direction.Left:
                return(this.GetEntireRank(rank).Min() + iterator);
            }

            return(0);
        }
Пример #23
0
        //private List<int> getEntireDiagonalLine(int pos1, int pos2)
        //{
        //    //diagonal moves: rise LtoR /  or RtoL \
        //    var diff = Math.Abs(pos1 - pos2);
        //    var ltr = diff % 9 == 0;
        //    var rtl = diff % 7 == 0;
        //    if (!ltr && !rtl)
        //    {
        //        throw new Exception("What? This is supposed to be diagonal.");
        //    }
        //    var dxs = new List<int> { pos1, pos2 };
        //    //smallest # will be closest to the left or right in the line
        //    //the left terminating position is evenly divisible by 8
        //    //the right terminating position is evently divisible by 7
        //    //find terminators
        //    //left
        //    var increment = ltr ? 9 : 7;
        //    var smallest = dxs.Min();
        //    var largest = dxs.Max();
        //    var nextSmallest = smallest;
        //    while (nextSmallest % 8 > 0 && nextSmallest >= 0)
        //    {
        //        nextSmallest = nextSmallest - increment;
        //        if (nextSmallest >= 0 && !dxs.Contains(nextSmallest))
        //        {
        //            dxs.Add(nextSmallest);
        //        }
        //    };
        //    //right
        //    var nextLargest = largest;
        //    while (nextLargest % 7 > 0 && nextLargest <= 63)
        //    {
        //        nextLargest = nextLargest + increment;
        //        if (nextLargest <= 63 && !dxs.Contains(nextLargest))
        //        {
        //            dxs.Add(nextLargest);
        //        }
        //    };
        //    //fill in the middle
        //    var mid = smallest;
        //    var nextMid = mid;
        //    if (diff > increment)
        //    {
        //        while (nextMid < largest)
        //        {
        //            nextMid = nextMid + increment;
        //            if (!dxs.Contains(nextMid))
        //            {
        //                dxs.Add(nextMid);
        //            }
        //        }
        //    }
        //    return dxs;
        //}

        private List <int> getEntireOrthogonalLine(bool isRankMove, AttackedSquare x, bool trim = false)
        {
            List <int> result;

            if (isRankMove)
            {
                var file = NotationEngine.PositionToFile(x.Index);
                result = this._orthogonalService.GetEntireFile(file);
            }
            else
            {
                var rank = NotationEngine.PositionToRank(x.Index);
                result = this._orthogonalService.GetEntireRank(rank);
            }
            if (!trim)
            {
                return(result);
            }
            var low  = x.Index > x.AttackingSquare.Index ? x.AttackingSquare.Index : x.Index;
            var high = x.Index < x.AttackingSquare.Index ? x.AttackingSquare.Index : x.Index;

            return(result.Where(a => a > low && a < high).ToList());
        }
Пример #24
0
        // duplicated code?
        //public bool IsDiagonalMove(int startPosition, int endPosition)
        //{
        //    var startMod = startPosition % 8;
        //    var endMod = endPosition % 8;
        //    var modDiff = Math.Abs(startMod - endMod);

        //    var startRow = NotationUtility.PositionToRankInt(startPosition);
        //    var endRow = NotationUtility.PositionToRankInt(endPosition);
        //    var rowDiff = Math.Abs(startRow - endRow);
        //    if (modDiff == rowDiff)
        //    {
        //        return true;
        //    }
        //    return false;
        //}

        //	var remainingKingAttacks = enemyKingAttacks.Except(opponentAttacks);
        //	if (remainingKingAttacks.Any()) {
        //		kingHasEscape = true;
        //	}
        //	if (kingHasEscape) {
        //		return false;
        //	}
        //	//make sure that interposition is not possible
        //	var attackers = opponentAttacks.Where(a => a.Index == enemyKingPosition.Index);
        //	//if there are no attackers there cannot be a single interposition that saves the king
        //	if (attackers == null || !attackers.Any() || attackers.Count() > 1) {
        //		return true;
        //	}
        //	var attacker = attackers.FirstOrDefault();
        //	var theAttack = this.AttackService.GetKingAttack(attacker, gameState, enemyKingPosition);
        //	var interposers = friendlyAttacks.ToList().Intersect(theAttack);
        //	if (interposers.Any()) {
        //		return false;
        //	}
        //	//there were no friendlies to save the king, checkmate is true
        //	return true;
        //}
        public bool IsEnPassant(Square square, int newPiecePosition, string enPassantTargetSquare)
        {
            if (enPassantTargetSquare == "-")
            {
                return(false);
            }
            var piece = square.Piece;

            if (piece.PieceType != PieceType.Pawn)
            {
                return(false);
            }                                                        //only pawns can perform en passant
            var enPassantPosition = NotationEngine.CoordinateToPosition(enPassantTargetSquare);

            if (enPassantPosition != newPiecePosition)
            {
                return(false);
            }                                                            //if we're not moving to the en passant position, this is not en passant
            var moveDistance = Math.Abs(square.Index - newPiecePosition);

            if (!new List <int> {
                7, 9
            }.Contains(moveDistance))
            {
                return(false);
            }                                                                     //is this a diagonal move?
            if (piece.Color == Color.Black && square.Index < newPiecePosition)
            {
                return(false);
            }                                                                                    //black can't move up
            if (piece.Color == Color.White && square.Index > newPiecePosition)
            {
                return(false);
            }                                                                                    //white can't move down
            return(true);
        }
Пример #25
0
        private string getPgnMove(char notationPiece, Piece piece, string coord, int startPos, int endPos, bool isCapture, GameState gameState)
        {
            var captureMarker = isCapture ? "x" : string.Empty;
            var pgnMove       = getPGNMoveBeginState(notationPiece, coord, startPos, endPos, isCapture);
            var result        = string.Empty;

            // figure out if additional information needs to be placed on the pgn move
            // this should only need to happen if the pieces are of the same type
            var movingSquare = gameState.Squares.Where(a => a.Index == startPos).First();
            var otherSquaresOfThisTypeWithThisAttack = from s in gameState.Attacks
                                                       where s.Index == endPos &&
                                                       s.AttackingSquare.Index != movingSquare.Index &&
                                                       s.AttackingSquare.Piece.PieceType == movingSquare.Piece.PieceType &&
                                                       s.AttackingSquare.Piece.Color == gameState.ActiveColor
                                                       select s;

            if (otherSquaresOfThisTypeWithThisAttack.Count() <= 0)
            {
                return(string.Concat(pgnMove.Substring(0, 1), captureMarker, pgnMove.Substring(1, pgnMove.Length - 1)));
            }

            var secondPiece = otherSquaresOfThisTypeWithThisAttack.First();

            if (secondPiece.AttackingSquare.Piece.PieceType == PieceType.Pawn && !isCapture)
            {
                result = string.Concat(pgnMove.Substring(0, 1), captureMarker, pgnMove.Substring(1, pgnMove.Length - 1));
                return(result);
            }

            // if other piece is on same the file of departure (if they differ); or
            var movingPieceFile = NotationEngine.PositionToFileChar(startPos);
            var otherPieceFile  = NotationEngine.PositionToFileChar(secondPiece.Index);

            if (movingPieceFile != otherPieceFile)
            {
                if (notationPiece == 'P')
                {
                    result = string.Concat(movingPieceFile, captureMarker, pgnMove);
                }
                else
                {
                    result = string.Concat(pgnMove.Substring(0, 1), movingPieceFile, captureMarker, pgnMove.Substring(1, pgnMove.Length - 1));
                }
                return(result);
            }
            else
            {
                // the rank of departure (if the files are the same but the ranks differ)
                // these are index = 0 rank/file, so add one for PGN output
                var movingPieceRank = NotationEngine.PositionToRankInt(startPos) + 1;
                var otherPieceRank  = NotationEngine.PositionToRankInt(secondPiece.Index) + 1;
                if (movingPieceRank != otherPieceRank)
                {
                    result = string.Concat(pgnMove.Substring(0, 1), movingPieceRank, captureMarker, pgnMove.Substring(1, pgnMove.Length - 1));
                    return(result);
                }
                else
                {
                    // both the rank and file
                    // (if neither alone is sufficient to identify the piece—which occurs only in rare cases where one or more pawns have promoted,
                    // resulting in a player having three or more identical pieces able to reach the same square).
                    result = string.Concat(pgnMove.Substring(0, 1), movingPieceFile, movingPieceRank, captureMarker, pgnMove.Substring(1, 2));
                    return(result);
                }
            }
        }
Пример #26
0
        public Square GetCurrentPositionFromPGNMove(GameState gameState, Piece piece, int newPiecePosition, string pgnMove, bool isCastle)
        {
            if (isCastle)
            {
                return(getOriginationPositionForCastling(gameState, piece.Color));
            }
            // adding !a.MayOnlyMoveHereIfOccupiedByEnemy fixed the test I was working on, but there may be a deeper issue here.
            var potentialSquares = gameState.Attacks.Where(a =>
                                                           a.Index == newPiecePosition &&
                                                           (
                                                               a.Occupied || (!a.Occupied && !a.MayOnlyMoveHereIfOccupiedByEnemy)
                                                           ) &&
                                                           a.AttackingSquare.Piece.PieceType == piece.PieceType &&
                                                           a.AttackingSquare.Piece.Color == piece.Color
                                                           );

            if (!potentialSquares.Any())
            {
                // this could be a pawn en passant
                if (
                    piece.PieceType == PieceType.Pawn &&
                    gameState.EnPassantTargetSquare != "-" &&
                    NotationEngine.CoordinateToPosition(gameState.EnPassantTargetSquare) == newPiecePosition
                    )
                {
                    var enPassant = gameState.Attacks.Where(a =>
                                                            a.Index == newPiecePosition &&
                                                            a.AttackingSquare.Piece.PieceType == piece.PieceType &&
                                                            a.AttackingSquare.Piece.Color == piece.Color
                                                            ).First().AttackingSquare;
                    return(enPassant);
                }
                var msg = $"No squares found. PGN Move: { pgnMove }";
                throw new Exception(msg);
            }
            if (potentialSquares.Count() == 1)
            {
                return(potentialSquares.First().AttackingSquare);
            }
            // differentiate
            var potentialPositions = from s in gameState.Squares
                                     join p in potentialSquares on s.Index equals p.AttackingSquare.Index
                                     where s.Piece.Identity == piece.Identity
                                     select p;

            if (!potentialPositions.Any())
            {
                var msg = $"Attempting to differentiate. No squares found. PGN Move: { pgnMove }";
                throw new Exception(msg);
            }
            // x means capture and shouldn't be used in the equation below
            var capture = isCapture(pgnMove);
            var check   = isCheck(pgnMove);

            // todo: refactor to eliminate redundancy
            // look at the beginning of the pgnMove string to determine which of the pieces are the one that should be moved.
            // this should only happen if there are two pieces of the same type that can attack here.
            var newPgnMove = pgnMove.Replace("x", "").Replace("+", "");
            var moveLength = newPgnMove.Length;

            switch (moveLength)
            {
            case 2:
                return(pgnLength2(piece, potentialPositions, capture));

            case 3:
                // this should be a pawn attack that can be made by two pawns
                // this can also be a pawn promotion
                return(pgnLength3(potentialPositions, newPgnMove));

            case 4:     // this would be any other piece
                return(pgnLength4(gameState, potentialPositions, newPgnMove));

            case 5:     // we have rank and file, so just find the piece. this should be very rare
                return(pgnLength5(gameState, newPgnMove));

            default:
                throw new Exception("Failed to find square.");
            }
        }