private void RefreshPathsFeature(IBoardState <ChessPieceEntity> boardState, Colours currentPlayer)
        {
            if (FeatureFlags.CachingPaths)
            {
                // Need proper boardstate key I think, currently a few tests fail, I guess around some state related
                // so something not encoded in the textboard (enpassant  and castle viability namely)
                var stateKey = ChessGameConvert.SerialiseBoard(boardState);
                if (_stateCache.TryGetValue(stateKey, out var items))
                {
                    boardState.UpdatePaths(items);
                }
                else
                {
                    RefreshChessPaths(boardState, currentPlayer);

                    if (FeatureFlags.CachingPaths)
                    {
                        _stateCache.Add(stateKey, boardState.GetItems().ToArray());
                    }
                }
            }
            else
            {
                RefreshChessPaths(boardState, currentPlayer);
            }
        }
Example #2
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));
        }
        private static void RefreshChessPaths(IBoardState <ChessPieceEntity> boardState, Colours whoseTurn)
        {
            // NOTE: Kings cannot move in to check, so we regenerate their state last so the know
            // all of the enemy piece attack paths
            var nonKings = boardState.GetItems().Where(i => i.Item.EntityType != (int)ChessPieceName.King);
            var kings    = boardState.GetItems().Where(i => i.Item.EntityType == (int)ChessPieceName.King).ToList();

            boardState.RefreshPathsFor(nonKings);

            // NOTE: Kings can't move next to each other, so we update the enemy kings state first so that we can
            // so when regen the friendly kings state it knows where the enemy kings can move to, and therefore
            // where it cannot

            if (whoseTurn == Colours.White)
            {
                boardState.RefreshPathsFor(kings.Where(k => k.Item.Owner == (int)Colours.Black));
                boardState.RefreshPathsFor(kings.Where(k => k.Item.Owner == (int)Colours.White));
            }
            else
            {
                boardState.RefreshPathsFor(kings.Where(k => k.Item.Owner == (int)Colours.White));
                boardState.RefreshPathsFor(kings.Where(k => k.Item.Owner == (int)Colours.Black));
            }
        }
        public void RefreshAllPaths(IBoardState <ChessPieceEntity> boardState, int currentPlayer)
        {
            RefreshPathsFeature(boardState, (Colours)currentPlayer);

            // NOTE: IMPORTANT: Kings must be evaluated last to ensure that moves
            // from other pieces that would cause check are generated first!
            // kings have an EntityType of int.MaxValue
            var boardStateGetAllItemLocations = boardState.GetItems()
                                                .OrderBy(i => i.Item.EntityType)
                                                .Select(i => i.Location).ToList();

            foreach (var loc in boardStateGetAllItemLocations)
            {
                RemovePathsThatContainMovesThatLeaveUsInCheck(boardState, loc);
            }
        }
Example #5
0
        // TODO: Needs tests
        public PlayerState CurrentPlayerState(
            IBoardState <ChessPieceEntity> boardState,
            Colours currentPlayer
            )
        {
            var king = boardState.GetItems((int)currentPlayer, (int)ChessPieceName.King).Single();

            var locationUnderCheck = IsLocationUnderCheck(boardState, king.Location, king.Item.Player);

            if (locationUnderCheck.result)
            {
                return(CheckForCheckMate(boardState, king, locationUnderCheck.attacker));
            }


            return(PlayerState.None);
        }
Example #6
0
 public void RefreshAllPaths(IBoardState <TEntity> boardState, int currentPlayer)
 => boardState.GetItems().ToList()
 .ForEach(boardState.RegenerateValidatedPaths);