private IEnumerable <ChessDraw> getRochadeDraws(IChessBoard board, ChessColor drawingSide) { // TODO: do optimizations!!! // get enemy capturable positions var enemyKing = (drawingSide == ChessColor.White) ? board.BlackKing : board.WhiteKing; var enemyCapturablePositions = board.GetPiecesOfColor(drawingSide.Opponent()).Where(x => x.Piece.Type != ChessPieceType.King) .SelectMany(x => ChessDrawGenerator.Instance.GetDraws(board, x.Position, null, false)).Select(x => x.NewPosition) .Concat(getStandardDrawPositions(enemyKing.Position)); // get the allied king and towers int row = (drawingSide == ChessColor.White) ? 0 : 7; var alliedKing = (drawingSide == ChessColor.White) ? board.WhiteKing : board.BlackKing; var farAlliedTowerPos = new ChessPosition(row, 0); var farAlliedTower = board.GetPieceAt(farAlliedTowerPos); var nearAlliedTowerPos = new ChessPosition(row, 7); var nearAlliedTower = board.GetPieceAt(nearAlliedTowerPos); // define the fields that must not be capturable by the opponent var bigRochadeKingPassagePositions = (drawingSide == ChessColor.White) ? whiteKingBigRochadePassagePositions : blackKingBigRochadePassagePositions; var smallRochadeKingPassagePositions = (drawingSide == ChessColor.White) ? whiteKingSmallRochadePassagePositions : blackKingSmallRochadePassagePositions; bool canBigRochade = // check for preconditions of big rochade (board.IsCapturedAt(farAlliedTowerPos) && !alliedKing.Piece.WasMoved && !farAlliedTower.WasMoved && bigRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King)) && !board.IsCapturedAt(new ChessPosition(row, 1))) // make sure that no rochade field can be captured by the opponent && !enemyCapturablePositions.Any(pos => bigRochadeKingPassagePositions.Contains(pos)); bool canSmallRochade = // check for preconditions of small rochade (board.IsCapturedAt(nearAlliedTowerPos) && !alliedKing.Piece.WasMoved && !nearAlliedTower.WasMoved && smallRochadeKingPassagePositions.All(x => !board.IsCapturedAt(x) || (board.GetPieceAt(x).Color == drawingSide && board.GetPieceAt(x).Type == ChessPieceType.King))) // make sure that no rochade field can be captured by the opponent and the rochade field on the B-line is not captured && !enemyCapturablePositions.Any(pos => smallRochadeKingPassagePositions.Contains(pos)); // write result draws int index = 0; int drawsCount = (canSmallRochade ? 1 : 0) + (canBigRochade ? 1 : 0); ChessDraw[] draws = new ChessDraw[drawsCount]; if (canSmallRochade) { draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 6)); } if (canBigRochade) { draws[index++] = new ChessDraw(board, alliedKing.Position, new ChessPosition(row, 2)); } return(draws); }
/// <summary> /// Simulate the given chess draw on the given chess board and determine whether it draws into an allied check situation. /// </summary> /// <param name="board">The chess board with the game situation to evaluate</param> /// <param name="draw">The chess draw to be evaluated</param> /// <returns>boolean that indicates whether the draw would cause an allied check situation</returns> public bool IsDrawIntoCheck(IChessBoard board, ChessDraw draw) { // TODO: remove clone operation if it causes performance issues // clone chess board and simulate the draw var simulatedBoard = board.ApplyDraw(draw); // get all enemy chess pieces and their possible answers var enemyPieces = simulatedBoard.GetPiecesOfColor(draw.DrawingSide.Opponent()); var possibleEnemyAnswers = enemyPieces.SelectMany(piece => ChessDrawGenerator.Instance.GetDraws(simulatedBoard, piece.Position, draw, false)); // find out if the allied king could be taken by at least one enemy answer var alliedKing = (draw.DrawingSide == ChessColor.White) ? simulatedBoard.WhiteKing : simulatedBoard.BlackKing; bool ret = possibleEnemyAnswers.Any(x => x.NewPosition == alliedKing.Position); return(ret); }
// TODO: maybe rework this attibute as this is quite "quick n dirty" #endregion Members #region Methods /// <summary> /// Apply the chess draw to the current game situation on the chess board. /// Furthermore change the side that has to draw and store the chess draw in the chess draws history (stack). /// </summary> /// <param name="draw">The chess draw to be made</param> /// <param name="validate">Indicates whether the chess draw should be validated</param> /// <returns>boolean whether the draw could be applied</returns> public bool ApplyDraw(ChessDraw draw, bool validate = false) { var lastDraw = (_drawHistory?.Count > 0) ? (ChessDraw?)_drawHistory.Peek() : null; bool isDrawValid = !validate || draw.IsValid(Board, lastDraw); // info: Validate() throws an exception if the draw is invalid -> catch this exception and make use of the exception message if (isDrawValid) { // draw the chess piece Board = Board.ApplyDraw(draw); // apply the chess draw to the chess draws history _drawHistory.Push(draw); // change the side that has to draw SideToDraw = SideToDraw.Opponent(); } return(isDrawValid); }
/// <summary> /// Check whether the game situation on the given chess board is a simple check, checkmate or tie situation. /// </summary> /// <param name="board">the chess board to be evaluated</param> /// <param name="precedingEnemyDraw">the preceding opponent chess draw</param> /// <returns>a check game status</returns> public ChessGameStatus GetCheckGameStatus(IChessBoard board, ChessDraw precedingEnemyDraw) { var alliedSide = (precedingEnemyDraw.DrawingSide == ChessColor.White) ? ChessColor.Black : ChessColor.White; var enemySide = precedingEnemyDraw.DrawingSide; // analyze the chess piece types on the board => determine whether any player can even achieve a checkmate with his remaining pieces bool canAllyCheckmate = canAchieveCheckmate(board, alliedSide); bool canEnemyCheckmate = canAchieveCheckmate(board, enemySide); // quit game status analysis if ally has lost due to unsufficient pieces if (!canAllyCheckmate && canEnemyCheckmate) { return(ChessGameStatus.UnsufficientPieces); } if (!canAllyCheckmate && !canEnemyCheckmate) { return(ChessGameStatus.Tie); } // find out if any allied chess piece can draw var alliedPieces = board.GetPiecesOfColor(alliedSide); bool canAllyDraw = alliedPieces.Any(piece => ChessDrawGenerator.Instance.GetDraws(board, piece.Position, precedingEnemyDraw, true).Count() > 0); // find out whether the allied king is checked var alliedKing = (alliedSide == ChessColor.White) ? board.WhiteKing : board.BlackKing; var enemyPieces = board.GetPiecesOfColor(alliedSide.Opponent()); bool isAlliedKingChecked = enemyPieces.Any(piece => ChessDrawGenerator.Instance.GetDraws(board, piece.Position, null, false).Any(y => y.NewPosition == alliedKing.Position)); // none: ally can draw and is not checked // check: ally is checked, but can at least draw // stalemate: ally cannot draw but is also not checked (end of game) // checkmate: ally is checked and cannot draw anymore (end of game) var status = canAllyDraw ? (isAlliedKingChecked ? ChessGameStatus.Check : ChessGameStatus.None) : (isAlliedKingChecked ? ChessGameStatus.Checkmate : ChessGameStatus.Stalemate); return(status); }