public double GetScore(IChessBoard board, ChessColor sideToDraw) { // get allied pieces and calculate the score double allyScore = board.GetPiecesOfColor(sideToDraw).Select(x => getPieceScore(board, x.Position)).Sum(); double enemyScore = board.GetPiecesOfColor(sideToDraw.Opponent()).Select(x => getPieceScore(board, x.Position)).Sum(); // calculate the relative score: the own score compared to the opponent's score return(allyScore - enemyScore); }
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> /// 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); }
private ChessDraw[] generateDraws(IChessBoard board, ChessDraw?lastDraw = null) { ChessDraw[] draws = new ChessDraw[0]; var drawingSide = lastDraw?.DrawingSide.Opponent() ?? ChessColor.White; if (board?.GetType() == typeof(ChessBoard)) { var alliedPieces = board.GetPiecesOfColor(drawingSide); draws = alliedPieces.SelectMany(x => ChessDrawGenerator.Instance.GetDraws(board, x.Position, lastDraw, true)).ToArray(); } else if (board?.GetType() == typeof(ChessBitboard)) { draws = ((ChessBitboard)board).GetAllDraws(drawingSide, lastDraw, true); } return(draws); }
private bool canAchieveCheckmate(IChessBoard board, ChessColor side) { // minimal pieces required for checkmate: // ====================================== // (1) king + queen // (2) king + rook // (3) king + 2 bishops (onto different chess field colors) // (4) king + bishop + knight // (5) king + 3 knights // (6) king + peasant (with promotion) // // source: http://www.eudesign.com/chessops/basics/cpr-mate.htm // get all allied pieces var alliedPieces = board.GetPiecesOfColor(side); // determine whether the allied side can still achieve a checkmate bool ret = ( // check if ally at least has his king + another piece (precondition for all options) alliedPieces.Count() >= 2 && alliedPieces.Any(x => x.Piece.Type == ChessPieceType.King) && ( // check for options 1, 2, 6 alliedPieces.Any(x => x.Piece.Type == ChessPieceType.Queen || x.Piece.Type == ChessPieceType.Rook || x.Piece.Type == ChessPieceType.Peasant) || // check for options 3, 4, 5 ( // check precondition of options 3, 4, 5 alliedPieces.Count() >= 3 && ( // check for option 3 alliedPieces.Where(x => x.Piece.Type == ChessPieceType.Bishop).Select(x => x.Position.ColorOfField)?.Distinct().Count() == 2 || // check for option 4 alliedPieces.Any(x => x.Piece.Type == ChessPieceType.Bishop) && alliedPieces.Any(x => x.Piece.Type == ChessPieceType.Knight) || // check for option 5 alliedPieces.Where(x => x.Piece.Type == ChessPieceType.Knight).Count() >= 3 ) ) ) ); return(ret); }
/// <summary> /// Compute the field positions that can be captured by the given chess piece. /// </summary> /// <param name="board">The chess board representing the game situation</param> /// <param name="drawingPiecePosition">The chess position of the chess piece to be drawn</param> /// <param name="precedingEnemyDraw">The last draw made by the opponent</param> /// <param name="analyzeDrawIntoCheck">Indicates whether drawing into a check situation should be analyzed</param> /// <returns>a list of all possible chess draws</returns> public IEnumerable <ChessDraw> GetDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null, bool analyzeDrawIntoCheck = false) { var piece = board.GetPieceAt(drawingPiecePosition); // make sure the chess piece is a king if (piece.Type != ChessPieceType.King) { throw new InvalidOperationException("The chess piece is not a king."); } // get the possible draw positions var positions = getStandardDrawPositions(drawingPiecePosition); // only retrieve positions that are not captured by an allied chess piece var alliedPieces = board.GetPiecesOfColor(piece.Color); positions = positions.Except(alliedPieces.Select(x => x.Position)); // only retrieve positions that cannot be captured by the enemy king (-> avoid draw into check) var enemyKing = piece.Color == ChessColor.White ? board.BlackKing : board.WhiteKing; var enemyKingDrawPositons = getStandardDrawPositions(enemyKing.Position); positions = positions.Except(enemyKingDrawPositons); // transform positions to draws IEnumerable <ChessDraw> draws = positions.Select(newPos => new ChessDraw(board, drawingPiecePosition, newPos)).ToArray(); // analyze draw into a check situation if (analyzeDrawIntoCheck && draws?.Count() > 0) { draws = draws.Where(draw => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw)).ToArray(); } // add rochade draws bool canRochade = (drawingPiecePosition == new ChessPosition("E1") || drawingPiecePosition == new ChessPosition("E8")); if (canRochade) { draws = draws.Concat(getRochadeDraws(board, piece.Color)); } return(draws); }