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> /// Compute whether the draw is valid or not. If it is invalid, an exception with an according message is thrown. /// </summary> /// <param name="board">the chess board where the draw should be applied to</param> /// <param name="predecedingEnemyDraw">The last draw that the oponent made</param> /// <returns>boolean whether the draw is valid</returns> public bool IsValid(IChessBoard board, ChessDraw?predecedingEnemyDraw = null) { // TODO: refactor this function!!! // get the piece to be drawn var piece = board.GetPieceAt(OldPosition); // make sure that there is a chess piece of the correct color that can be drawn if (!board.IsCapturedAt(OldPosition)) { throw new ArgumentException($"There is no chess piece on { OldPosition.FieldName }."); } if (piece.Color != DrawingSide) { throw new ArgumentException($"The chess piece on { OldPosition.FieldName } is owned by the opponent."); } // compute the possible chess draws for the given chess piece var possibleDraws = ChessDrawGenerator.Instance.GetDraws(board, OldPosition, predecedingEnemyDraw, true); // check if there is a possible draw with the same new position and type (this implies that the given draw is valid) var type = Type; var position = NewPosition; bool ret = (possibleDraws?.Count() > 0) && possibleDraws.Any(x => x.Type == type && x.NewPosition == position); return(ret); }
private static ChessDrawType getDrawType(IChessBoard board, ChessPosition oldPos, ChessPosition newPos, ChessPieceType?peasantPromotionType) { var piece = board.GetPieceAt(oldPos); var type = ChessDrawType.Standard; // check for a peasant promotion if (peasantPromotionType != null && piece.Type == ChessPieceType.Peasant && ((newPos.Row == 7 && piece.Color == ChessColor.White) || (newPos.Row == 0 && piece.Color == ChessColor.Black))) { type = ChessDrawType.PeasantPromotion; } // check for a rochade else if (piece.Type == ChessPieceType.King && Math.Abs(oldPos.Column - newPos.Column) == 2) { type = ChessDrawType.Rochade; } // check for an en-passant else if (piece.Type == ChessPieceType.Peasant && !board.IsCapturedAt(newPos) && Math.Abs(oldPos.Column - newPos.Column) == 1) { type = ChessDrawType.EnPassant; } return(type); }
private IEnumerable <ChessDraw> getForewardDraws(IChessBoard board, ChessPosition drawingPiecePosition) { var draws = new List <ChessDraw>(); var piece = board.GetPieceAt(drawingPiecePosition); var coordsPosOneForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column); var coordsPosTwoForeward = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 2 : -2), drawingPiecePosition.Column); if (ChessPosition.AreCoordsValid(coordsPosOneForeward)) { var posOneForeward = new ChessPosition(coordsPosOneForeward); bool oneForeward = !board.IsCapturedAt(posOneForeward); if (oneForeward) { draws.Add(new ChessDraw(board, drawingPiecePosition, posOneForeward)); if (!piece.WasMoved && ChessPosition.AreCoordsValid(coordsPosTwoForeward)) { var posTwoForeward = new ChessPosition(coordsPosTwoForeward); if (!board.IsCapturedAt(posTwoForeward)) { draws.Add(new ChessDraw(board, drawingPiecePosition, posTwoForeward)); } } } } return(draws); }
public ChessDraw(IChessBoard board, ChessPosition oldPos, ChessPosition newPos, ChessPieceType?peasantPromotionType = null) { // get the drawing piece var piece = board.GetPieceAt(oldPos); // determine all property values var type = getDrawType(board, oldPos, newPos, peasantPromotionType); var drawingSide = piece.Color; var drawingPieceType = piece.Type; var takenPieceType = (type == ChessDrawType.EnPassant) ? (ChessPieceType?)ChessPieceType.Peasant : (board.IsCapturedAt(newPos) ? (ChessPieceType?)board.GetPieceAt(newPos).Type : null); // transform property values to a hash code _hashCode = toHashCode(type, drawingSide, drawingPieceType, takenPieceType, peasantPromotionType, oldPos, newPos, !piece.WasMoved); }
public void UpdatePieces(IChessBoard board) { for (byte pos = 0; pos < 64; pos++) { var field = Fields[pos]; field.UpdatePiece(board.IsCapturedAt(pos) ? (ChessPiece?)board.GetPieceAt(pos) : null); } _board = (IChessBoard)((ICloneable)board).Clone(); }
/// <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) { // determine the drawing piece and the required draw generator var piece = board.GetPieceAt(drawingPiecePosition); var generator = _explicitGenerators[piece.Type]; // compute all possible chess draws for the given chess piece var draws = generator.GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck).ToArray(); return(draws); }
/// <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 knight if (piece.Type != ChessPieceType.Knight) { throw new InvalidOperationException("The chess piece is not a knight."); } // get positions next to the current position of the king (all permutations of { -1, 0, +1 }^2 except (0, 0)) var coords = new Tuple <int, int>[] { new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column - 1), new Tuple <int, int>(drawingPiecePosition.Row - 2, drawingPiecePosition.Column + 1), new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column - 2), new Tuple <int, int>(drawingPiecePosition.Row - 1, drawingPiecePosition.Column + 2), new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column - 2), new Tuple <int, int>(drawingPiecePosition.Row + 1, drawingPiecePosition.Column + 2), new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column - 1), new Tuple <int, int>(drawingPiecePosition.Row + 2, drawingPiecePosition.Column + 1), }; // only retrieve positions that are actually onto the chess board (and not off scale) var positions = coords.Where(x => ChessPosition.AreCoordsValid(x)).Select(x => new ChessPosition(x)); // do not draw into positions captured by allied chess pieces positions = positions.Where(x => !board.IsCapturedAt(x) || board.GetPieceAt(x).Color != piece.Color); // transform positions to chess draws var draws = positions.Select(newPos => new ChessDraw(board, drawingPiecePosition, newPos)); if (analyzeDrawIntoCheck && draws?.Count() > 0) { // remove draws that would draw into a check situation draws = draws.Where(x => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, x)); } return(draws); }
private double getKnightScore(IChessBoard board, ChessPosition position) { // Shannon's chess piece evaluation // TODO: check this heuristic double score = BASE_SCORE_KNIGHT; // bonus for developing and gained mobility if (board.GetPieceAt(position).WasMoved) { score += getMovabilityBonus(board, position); } return(score); }
/// <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 queen if (piece.Type != ChessPieceType.Queen) { throw new InvalidOperationException("The chess piece is not a queen."); } // combine the positions that a rock or a bishop could capture var draws = new RookChessDrawGenerator().GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck) .Union(new BishopChessDrawGenerator().GetDraws(board, drawingPiecePosition, precedingEnemyDraw, analyzeDrawIntoCheck)); return(draws); }
/// <summary> /// Help converting a chess board instance to a hash string. /// </summary> /// <param name="board">the chess board to be converted</param> /// <returns>a hash string containing the data from the chess board</returns> public static Bitboard ToBitboard(this IChessBoard board) { // init a new bitboard with 40 byte var bitboard = new Bitboard(40 * 8); // loop through all chess positions for (byte pos = 0; pos < 64; pos++) { // get the chess piece bits var position = new ChessPosition(pos); byte pieceCode = (byte)(board.GetPieceAt(position).GetHashCode() << 3); // apply bits to bitboard bitboard.SetBitsAt(pos * 5, pieceCode, 5); } return(bitboard); }
/// <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); }
/// <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.Peasant) { throw new InvalidOperationException("The chess piece is not a peasant."); } // get all possible draws var draws = getForewardDraws(board, drawingPiecePosition).Union(getCatchDraws(board, drawingPiecePosition, precedingEnemyDraw)); // handle peasant promotion draws = draws.SelectMany(x => { // check if the chess draw is a peasant promotion if ((x.NewPosition.Row == 7 && piece.Color == ChessColor.White) || (x.NewPosition.Row == 0 && piece.Color == ChessColor.Black)) { // return all 4 promotion options for the input draw return(new ChessDraw[] { new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Queen), new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Rook), new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Bishop), new ChessDraw(board, x.OldPosition, x.NewPosition, ChessPieceType.Knight), }); } // return the input draw unchanged return(new ChessDraw[] { x }); }); if (analyzeDrawIntoCheck && draws?.Count() > 0) { // remove draws that would draw into a check situation draws = draws.Where(x => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, x)); } return(draws); }
private double getPeasantScore(IChessBoard board, ChessPosition position) { // Shannon's chess piece evaluation // TODO: check this heuristic double score = BASE_SCORE_PEASANT; var piece = board.GetPieceAt(position); // bonus the more the peasant advances (but don't punish if peasant is not drawn) int advanceFactor = (piece.Color == ChessColor.White) ? (position.Row - 2) : (5 - position.Row); if (advanceFactor > 0) { score += advanceFactor * 0.04; } //// bonus for connected peasants / malus for an isolated peasant //int protectedRow = (piece.Color == ChessColor.White) ? (position.Row + 1) : (position.Row - 1); //var posLeft = new ChessPosition(protectedRow, position.Column - 1); //var posRight = new ChessPosition(protectedRow, position.Column + 1); //bool isConnected = // (ChessPosition.AreCoordsValid(protectedRow, position.Column - 1) && board.IsCapturedAt(posLeft) && board.GetPieceAt(posLeft).Color == piece.Color) // || (ChessPosition.AreCoordsValid(protectedRow, position.Column + 1) && board.IsCapturedAt(posRight) && board.GetPieceAt(posRight).Color == piece.Color); //score += (isConnected ? 1 : -1) * 0.05; //// malus for doubled peasants //bool isDoubled = board.GetPiecesOfColor(piece.Color).Any(x => x.Piece.Type == ChessPieceType.Peasant && x.Position.Column == position.Column && x.Position.Row != position.Row); //if (isConnected) { score -= 0.1; } //// malus if peasant was passed by an enemy peasant //bool isPassed = board.GetPiecesOfColor(piece.Color.Opponent()).Any(x => // x.Piece.Type == ChessPieceType.Peasant && Math.Abs(x.Position.Column - position.Column) == 1 // && ((x.Position.Row < position.Row && x.Piece.Color == ChessColor.White) || (x.Position.Row > position.Row && x.Piece.Color == ChessColor.Black)) //); //if (isPassed) { score -= 0.1; } return(score); }
private double getPieceScore(IChessBoard board, ChessPosition position) { double score; var piece = board.GetPieceAt(position); switch (piece.Type) { case ChessPieceType.King: score = getKingScore(board, position); break; case ChessPieceType.Queen: score = getQueenScore(board, position); break; case ChessPieceType.Rook: score = getRookScore(board, position); break; case ChessPieceType.Bishop: score = getBishopScore(board, position); break; case ChessPieceType.Knight: score = getKnightScore(board, position); break; case ChessPieceType.Peasant: score = getPeasantScore(board, position); break; default: throw new ArgumentException("unknown chess piece type detected!"); } return(score); }
private double getPieceScore(IChessBoard board, ChessPosition position) { double score; var piece = board.GetPieceAt(position); switch (piece.Type) { case ChessPieceType.King: score = BASE_SCORE_KING; break; case ChessPieceType.Queen: score = BASE_SCORE_QUEEN; break; case ChessPieceType.Rook: score = BASE_SCORE_ROOK; break; case ChessPieceType.Bishop: score = BASE_SCORE_BISHOP; break; case ChessPieceType.Knight: score = BASE_SCORE_KNIGHT; break; case ChessPieceType.Peasant: score = BASE_SCORE_PEASANT; break; default: throw new ArgumentException("unknown chess piece type detected!"); } return(score); }
/// <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 bishop-like if (piece.Type != ChessPieceType.Bishop && piece.Type != ChessPieceType.Queen) { throw new InvalidOperationException("The chess piece is not a bishop."); } var draws = new List <ChessDraw>(); // get upper left-side draws for (int i = 1; i < 8; i++) { // get position and make sure it is valid (otherwise exit loop) var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column - i); if (!ChessPosition.AreCoordsValid(coords)) { break; } var newPos = new ChessPosition(coords); if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color) { draws.Add(new ChessDraw(board, drawingPiecePosition, newPos)); } if (board.IsCapturedAt(newPos)) { break; } } // get lower left-side draws for (int i = 1; i < 8; i++) { // get position and make sure it is valid (otherwise exit loop) var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column - i); if (!ChessPosition.AreCoordsValid(coords)) { break; } var newPos = new ChessPosition(coords); if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color) { draws.Add(new ChessDraw(board, drawingPiecePosition, newPos)); } if (board.IsCapturedAt(newPos)) { break; } } // get upper right-side draws for (int i = 1; i < 8; i++) { // get position and make sure it is valid (otherwise exit loop) var coords = new Tuple <int, int>(drawingPiecePosition.Row + i, drawingPiecePosition.Column + i); if (!ChessPosition.AreCoordsValid(coords)) { break; } var newPos = new ChessPosition(coords); if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color) { draws.Add(new ChessDraw(board, drawingPiecePosition, newPos)); } if (board.IsCapturedAt(newPos)) { break; } } // get lower right-side draws for (int i = 1; i < 8; i++) { // get position and make sure it is valid (otherwise exit loop) var coords = new Tuple <int, int>(drawingPiecePosition.Row - i, drawingPiecePosition.Column + i); if (!ChessPosition.AreCoordsValid(coords)) { break; } var newPos = new ChessPosition(coords); if (!board.IsCapturedAt(newPos) || board.GetPieceAt(newPos).Color != piece.Color) { draws.Add(new ChessDraw(board, drawingPiecePosition, newPos)); } if (board.IsCapturedAt(newPos)) { break; } } // analyze draw into a check situation if (analyzeDrawIntoCheck && draws?.Count() > 0) { draws = draws.Where(draw => !ChessDrawSimulator.Instance.IsDrawIntoCheck(board, draw)).ToList(); } return(draws); }
/// <summary> /// Make a human user put the next draw via CLI. /// </summary> /// <param name="board">The chess board representing the current game situation.</param> /// <param name="previousDraw">The preceding draw made by the enemy.</param> /// <returns>the next chess draw</returns> public ChessDraw GetNextDraw(IChessBoard board, ChessDraw?previousDraw) { ChessPosition oldPosition; ChessPosition newPosition; ChessPieceType?promotionPieceType = null; do { // get draw from user input Console.Write("Please make your next draw (e.g. 'e2-e4): "); string userInput = Console.ReadLine().Trim().ToLower(); // parse user input if (userInput.Length == 5) { // parse coord strings string oldPosString = userInput.Substring(0, 2); string newPosString = userInput.Substring(3, 2); // validate coord strings if (ChessPosition.AreCoordsValid(oldPosString) && ChessPosition.AreCoordsValid(newPosString)) { // init chess positions oldPosition = new ChessPosition(oldPosString); newPosition = new ChessPosition(newPosString); // make sure that the player possesses the the chess piece he is moving (simple validation) if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Color == Side) { break; } else { Console.Write("There is no chess piece to be moved onto the field you put! "); } } } else { Console.Write("Your input needs to be of the syntax in the example! "); } }while (true); // handle peasant promotion if (board.IsCapturedAt(oldPosition) && board.GetPieceAt(oldPosition).Type == ChessPieceType.Peasant && (Side == ChessColor.White && newPosition.Row == 7) || (Side == ChessColor.Black && newPosition.Row == 0)) { do { // get draw from user input Console.Write("You have put a promotion draw. Please choose the type you want to promote to (options: Bishop=B, Knight=N, Rook=R, Queen=Q): "); string userInput = Console.ReadLine().Trim().ToLower().ToLower(); if (userInput.Length == 1) { switch (userInput[0]) { case 'b': promotionPieceType = ChessPieceType.Bishop; break; case 'n': promotionPieceType = ChessPieceType.Knight; break; case 'r': promotionPieceType = ChessPieceType.Rook; break; case 'q': promotionPieceType = ChessPieceType.Queen; break; } if (promotionPieceType == null) { Console.Write("Your input needs to be a letter like in the example! "); } } }while (promotionPieceType == null); } return(new ChessDraw(board, oldPosition, newPosition, promotionPieceType)); }
private IEnumerable <ChessDraw> getCatchDraws(IChessBoard board, ChessPosition drawingPiecePosition, ChessDraw?precedingEnemyDraw = null) { var draws = new List <ChessDraw>(); var piece = board.GetPieceAt(drawingPiecePosition); // get the possible chess field positions (info: right / left from the point of view of the white side player) var coordsPosCatchLeft = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column + 1); var coordsPosCatchRight = new Tuple <int, int>(drawingPiecePosition.Row + (piece.Color == ChessColor.White ? 1 : -1), drawingPiecePosition.Column - 1); // check for en-passant precondition bool wasLastDrawPeasantDoubleForeward = precedingEnemyDraw != null && precedingEnemyDraw.Value.DrawingPieceType == ChessPieceType.Peasant && Math.Abs(precedingEnemyDraw.Value.OldPosition.Row - precedingEnemyDraw.Value.NewPosition.Row) == 2; // check if left catch / en-passant is possible if (ChessPosition.AreCoordsValid(coordsPosCatchLeft)) { var posCatchLeft = new ChessPosition(coordsPosCatchLeft); bool catchLeft = board.IsCapturedAt(posCatchLeft) && board.GetPieceAt(posCatchLeft).Color != piece.Color; if (catchLeft) { draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft)); } if (wasLastDrawPeasantDoubleForeward) { // get the positions of an enemy chess piece taken by a possible en-passant var posEnPassantEnemyLeft = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column + 1); bool isLeftFieldCapturedByEnemy = precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyLeft && board.IsCapturedAt(posEnPassantEnemyLeft) && board.GetPieceAt(posEnPassantEnemyLeft).Color != piece.Color; bool enPassantLeft = isLeftFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyLeft.Column - drawingPiecePosition.Column) == 1; if (enPassantLeft) { draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchLeft)); } } } // check if right catch / en-passant is possible if (ChessPosition.AreCoordsValid(coordsPosCatchRight)) { var posCatchRight = new ChessPosition(coordsPosCatchRight); bool catchRight = board.IsCapturedAt(posCatchRight) && board.GetPieceAt(posCatchRight).Color != piece.Color; if (catchRight) { draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight)); } if (wasLastDrawPeasantDoubleForeward) { // get the positions of an enemy chess piece taken by a possible en-passant var posEnPassantEnemyRight = new ChessPosition(drawingPiecePosition.Row, drawingPiecePosition.Column - 1); bool isRightFieldCapturedByEnemy = precedingEnemyDraw.Value.NewPosition == posEnPassantEnemyRight && board.IsCapturedAt(posEnPassantEnemyRight) && board.GetPieceAt(posEnPassantEnemyRight).Color != piece.Color; bool enPassantRight = isRightFieldCapturedByEnemy && Math.Abs(posEnPassantEnemyRight.Column - drawingPiecePosition.Column) == 1; if (enPassantRight) { draws.Add(new ChessDraw(board, drawingPiecePosition, posCatchRight)); } } } return(draws); }