private string ValidateBasic() { var error = string.Empty; if (_pos.SideToMove != Player.White && _pos.SideToMove != Player.Black) { error = AddError(error, $"{nameof(_pos.SideToMove)} is not a valid"); } if (_board.PieceAt(_pos.GetKingSquare(Player.White)) != Pieces.WhiteKing) { error = AddError(error, "white king position is not a white king"); } if (_board.PieceAt(_pos.GetKingSquare(Player.Black)) != Pieces.BlackKing) { error = AddError(error, "black king position is not a black king"); } if (_pos.EnPassantSquare != Square.None && _pos.EnPassantSquare.RelativeRank(_pos.SideToMove) != Ranks.Rank6) { error = AddError(error, $"{nameof(_pos.EnPassantSquare)} square is not on rank 6"); } return(error); }
/// <summary> /// Computes whether the current position contains a pawn fence which makes the game a draw. /// </summary> /// <returns>true if the game is a draw position - otherwise false</returns> public bool IsBlocked() { // Quick check if there is only pawns and kings on the board It might be possible to // have a minor piece and exchange it into a passing pawn if (_pos.Board.PieceCount(PieceTypes.AllPieces) > _pos.Board.PieceCount(PieceTypes.Pawn) + 2) { return(false); } var up = _us.PawnPushDistance(); MarkOurPawns(up); MarkTheirPawns(); var isFenceFormed = IsFenceFormed(); if (!isFenceFormed) { return(false); } ComputeFenceRanks(); var ourKsq = _pos.GetKingSquare(_us); var theirKsq = _pos.GetKingSquare(_them); if (ourKsq.Rank.RelativeRank(_us) > _fenceRank[ourKsq.File.AsInt()].RelativeRank(_us)) { return(false); } _dynamicPawns |= ComputeDynamicFencedPawns(_them); while (_dynamicPawns) { var sq = BitBoards.PopLsb(ref _dynamicPawns); var(r, f) = sq.RankFile; var rr = sq.RelativeRank(_us); if (r > _fenceRank[f.AsInt()]) { if ((_theirPawns & sq.PassedPawnFrontAttackSpan(_us)).IsEmpty && (theirKsq.File != f || theirKsq.Rank.RelativeRank(_us) < rr)) { return(false); } } else if (_fence & sq) { if (rr >= Ranks.Rank6) { return(false); } if (_pos.GetPiece(sq + _us.PawnDoublePushDistance()) != _theirPawn) { if (theirKsq.File != f || theirKsq.Rank.RelativeRank(_us) < rr) { return(false); } if (f != Files.FileA && _pos.GetPiece(sq + Directions.West) != _ourPawn || BitBoards.PopCount(_ourPawns & PreviousFile(f)) > 1 || (_fixedPawn & (sq + Directions.West)).IsEmpty || (_fence & (sq + Directions.West)).IsEmpty) { return(false); } if (f != Files.FileH && _pos.GetPiece(sq + Directions.East) != _ourPawn || BitBoards.PopCount(_ourPawns & NextFile(f)) > 1 || (_fixedPawn & (sq + Directions.East)).IsEmpty || (_fence & (sq + Directions.East)).IsEmpty) { return(false); } } if ((sq + _us.PawnDoublePushDistance()).PawnAttack(_us) & _theirPawns) { return(false); } if (BitBoards.PopCount(_ourPawns & f) > 1) { return(false); } } else if (r < _fenceRank[f.AsInt()]) { sq += up; r = sq.Rank; rr = sq.RelativeRank(_us); while ((_fence & Square.Make(r, f)).IsEmpty) { var pawnAttacks = sq.PawnAttack(_us); if (_theirPawns & pawnAttacks) { return(false); } if (_pos.GetPiece(sq) == _ourPawn) { break; } sq += up; r = sq.Rank; } if ((_fence & Square.Make(r, f)).IsEmpty || _pos.IsOccupied(sq)) { continue; } if (rr >= Ranks.Rank6) { return(false); } if ((_theirPawns & (sq + _us.PawnDoublePushDistance())).IsEmpty) { if (theirKsq.File != f || theirKsq.Rank.RelativeRank(_us) < rr) { return(false); } if (f != Files.FileA && _pos.GetPiece(sq + Directions.West) != _ourPawn || BitBoards.PopCount(_ourPawns & (f - 1)) > 1 || (_fixedPawn & Square.Make(r, PreviousFile(f))).IsEmpty || (_fence & Square.Make(r, PreviousFile(f))).IsEmpty) { return(false); } if (f != Files.FileH && _pos.GetPiece(sq + Directions.East) != _ourPawn || BitBoards.PopCount(_ourPawns & (f + 1)) > 1 || (_fixedPawn & Square.Make(r, NextFile(f))).IsEmpty || (_fence & Square.Make(r, NextFile(f))).IsEmpty) { return(false); } } if ((sq + up).PawnAttack(_us) & _theirPawns) { return(false); } } } return(true); }