Example #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="boardState"></param>
        /// <param name="move"></param>
        /// <param name="performCheckTest">
        /// This has a small performance impact when reverse engineering SAN from the board move
        /// (approx 20ms a game on my rig) which is why it's optional and defaults to off</param>
        /// <returns></returns>
        public StandardAlgebraicNotation BuildFrom(IBoardState <ChessPieceEntity> boardState, BoardMove move, bool performCheckTest = false)
        {
            var fromItem = boardState.GetItem(move.From);

            var piece    = fromItem.Item.Piece;
            int?fromFile = null;
            int?fromRank = null;
            var toFile   = move.To.X;
            var toRank   = move.To.Y;
            var moveType = boardState.IsEmpty(move.To) ? SanMoveTypes.Move : SanMoveTypes.Take;

            // Are they any other pieces,
            //      of same type as the from item
            //      that can also move to the same location
            var otherPieces = boardState.GetItems()
                              .Where(i => !i.Location.Equals(move.From))
                              .Where(i => i.Item.Is(fromItem.Item.Player, fromItem.Item.Piece))
                              .ThatCanMoveTo(move.To);

            // TODO: That I need this resharper disable is probably a smell
            // ReSharper disable PossibleMultipleEnumeration
            if (otherPieces.Any())
            {
                fromFile = move.From.X;
                var file = fromFile;
                otherPieces = otherPieces
                              .Where(i => i.Location.X == file);
            }
            if (otherPieces.Any())
            {
                fromRank    = move.From.Y;
                otherPieces = new List <LocatedItem <ChessPieceEntity> >();
            }

            if (otherPieces.Any())
            {
                Throw.InvalidSan($"Unable to disambiguate {move}");
            }
            // ReSharper restore PossibleMultipleEnumeration

            if (piece == ChessPieceName.Pawn && moveType == SanMoveTypes.Take)
            {
                fromFile = fromItem.Location.X;
            }

            ChessPieceName?promotionPiece = null;

            if (move.ExtraData is ChessPieceEntityFactory.ChessPieceEntityFactoryTypeExtraData data)
            {
                promotionPiece = data.PieceName;
            }

            var inCheck = performCheckTest && _checkDetectionService.DoesMoveCauseCheck(boardState, move);

            return(new StandardAlgebraicNotation(piece, fromFile, fromRank, toFile, toRank, moveType, promotionPiece, inCheck));
        }
        // Typically only used to produce correct san notation on output
        public bool DoesMoveCauseCheck(IBoardState <ChessPieceEntity> boardState, BoardMove move)
        {
            // TODO: Would it be quicker to
            var attackingPlayer = boardState.GetItem(move.From).Item.Player;

            var defender = boardState.GetItem(move.To);

            if (defender != null && defender.Item.Is(attackingPlayer.Enemy(), ChessPieceName.King))
            {
                return(true);
            }

            var clone = (IBoardState <ChessPieceEntity>)boardState.Clone();

            _moveService.Move(clone, move);

            var king = clone.GetItems((int)attackingPlayer.Enemy(), (int)ChessPieceName.King).Single();

            return(_playerStateService.IsLocationUnderCheck(clone, king.Location, king.Item.Player).result);
        }
        // Used more specifically to enforce board logic
        public bool DoesMoveLeaveUsInCheck(IBoardState <ChessPieceEntity> boardState, BoardMove move)
        {
            var attackingPlayer = boardState.GetItem(move.From).Item.Player;

            var clone = (IBoardState <ChessPieceEntity>)boardState.Clone();

            _moveService.Move(clone, move);

            var king = clone.GetItems((int)attackingPlayer, (int)ChessPieceName.King).Single();

            return(_playerStateService.IsLocationUnderCheck(clone, king.Location, king.Item.Player).result);
        }
        private void RemovePathsThatContainMovesThatLeaveUsInCheck(IBoardState <ChessPieceEntity> boardState, BoardLocation loc)
        {
            var piece      = boardState.GetItem(loc);
            var validPaths = new Paths();

            foreach (var path in piece.Paths)
            {
                var validPath = ValidatePathForDiscoveredCheck(boardState, path);
                if (validPath != null)
                {
                    validPaths.Add(validPath);
                }
            }
            piece.UpdatePaths(validPaths);
        }
Example #5
0
        private static (bool result, LocatedItem <ChessPieceEntity> attacker) PathsContainsAttack(Paths paths,
                                                                                                  ChessPieceName[] straightAttackPieces, Colours enemy, IBoardState <ChessPieceEntity> boardState)
        {
            foreach (var attackPath in paths)
            {
                foreach (var path in attackPath)
                {
                    var piece = boardState.GetItem(path.To);
                    if (piece != null)
                    {
                        if (straightAttackPieces.Any(p => piece.Item.Is(enemy, p)))
                        {
                            return(true, piece);
                        }

                        break;
                    }
                }
            }

            return(false, null);
        }