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); }
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); }
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(); }
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); }
/// <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); }
/// <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); }
/// <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); }