/// <summary> /// Clona el tablero /// </summary> public SquareModel Clone() { SquareModel target = new SquareModel(); // Clona los datos for (int row = 0; row < 8; row++) { for (int column = 0; column < 8; column++) { PieceBaseModel piece = this[row, column]; if (this[row, column] == null) { target[row, column] = null; } else { target.Create(piece.Type, piece.Color, row, column); target[row, column].IsMoved = piece.IsMoved; } } } // Clona los parámetros target.Parameters = Parameters.Clone(); // Devuelve el tablero return(target); }
/// <summary> /// Crea las acciones asociadas a un movimiento /// </summary> internal void CreateActions(GameBoardModel board, MovementFigureModel movement, CellModel target, CellModel origin, PieceBaseModel.PieceType?targetPiece) { PieceBaseModel piece = board.SearchMoveTo(movement, target, origin); // Comprueba que se haya localizado la pieza que hizo el movimiento if (piece == null) { throw new Exceptions.GameReaderException($"No se encuentra ninguna pieza que pueda realizar el movimiento {movement.Text}"); } // Crea el movimiento CreateMoveAction(piece.Type, piece.Color, piece.Cell, target); // Crea la captura if (movement.Type == MovementFigureModel.MovementType.Capture || movement.Type == MovementFigureModel.MovementType.CaptureEnPassant) { CreateCaptureAction(board, targetPiece, GetNextColor(movement.Color), target); } // Crea la promoción if (movement.PromotedPiece != null) { // Crea un movimiento para eliminar el peón que se ha promocionado //? No llama a CreateCaptureAction porque si ha habido una captura en este mismo movimiento //? la pieza aún no se habrá eliminado del destino y por tanto nos creará una captura //? sobre la pieza que se ha eliminado ya Add(new ActionCaptureModel(piece.Type, movement.Color, target)); // Crea una promoción CreatePromoteAction(movement.PromotedPiece, movement.Color, target); } }
/// <summary> /// Mueve la pieza a una fila / columna /// </summary> private void Move(ActionMoveModel action) { PieceBaseModel piece = GetPiece(action.Type, action.Color, action.From); // Mueve la pieza piece.Cell = action.To; piece.IsMoved = true; }
/// <summary> /// Crea una captura /// </summary> private void CreateCaptureAction(GameBoardModel board, PieceBaseModel.PieceType?piece, PieceBaseModel.PieceColor color, CellModel from) { PieceBaseModel targetPiece = board.Pieces.GetPiece(from); //? En ocasiones la pieza leída no es la real del tablero, por eso buscamos la pieza adecuada // Añade la pieza Add(new ActionCaptureModel(targetPiece?.Type ?? piece ?? PieceBaseModel.PieceType.Unknown, color, from)); }
/// <summary> /// Obtiene el texto del tablero /// </summary> public string GetText() { string board = " 0 1 2 3 4 5 6 7" + Environment.NewLine + " A B C D E F G H" + Environment.NewLine; // Obtiene el texto for (int row = 0; row < 8; row++) { // Añade el carácter con la fila board += $"{8 - row} "; for (int column = 0; column < 8; column++) { PieceBaseModel piece = this[row, column]; if (piece == null) { board += "."; } else { switch (piece.Type) { case PieceBaseModel.PieceType.Pawn: board += piece.Color == PieceBaseModel.PieceColor.White ? "P" : "p"; break; case PieceBaseModel.PieceType.Bishop: board += piece.Color == PieceBaseModel.PieceColor.White ? "B" : "b"; break; case PieceBaseModel.PieceType.Knight: board += piece.Color == PieceBaseModel.PieceColor.White ? "N" : "n"; break; case PieceBaseModel.PieceType.Rook: board += piece.Color == PieceBaseModel.PieceColor.White ? "R" : "r"; break; case PieceBaseModel.PieceType.King: board += piece.Color == PieceBaseModel.PieceColor.White ? "K" : "k"; break; case PieceBaseModel.PieceType.Queen: board += piece.Color == PieceBaseModel.PieceColor.White ? "Q" : "q"; break; } } board += " "; } // Añade el número de fila y un salto de línea board += $" {8 - row} {row}" + Environment.NewLine; } // Añade el número de columna board += " A B C D E F G H" + Environment.NewLine + " 0 1 2 3 4 5 6 7"; // Devuelve el texto return(board); }
/// <summary> /// Inicializa las piezas /// </summary> private void InitPieces() { for (int row = 0; row < 8; row++) { for (int column = 0; column < 8; column++) { PieceBaseModel piece = ViewModel.Board[row, column]; if (piece != null) { Scapes.Add(new FigureViewModel(row, column, piece.Type, piece.Color)); } } } }
/// <summary> /// Comprueba si se puede realizar un enroque (las piezas no se han movido y no hay nada entre medias) /// </summary> private bool CanMoveCastle(PieceBaseModel.PieceColor color, int column) { bool canMove = false; int row = GetRowKing(color); PieceBaseModel king = this[row, 4]; PieceBaseModel rook = this[row, column]; //TODO --> Debería comprobar además si las celdas intermedias no está en jaque // Comprueba el movimiento if (king != null && rook != null && !king.IsMoved && !rook.IsMoved) { canMove = IsPathEmpty(row, 4, row, column); } // Devuelve el valor que indica si se puede mover return(canMove); }
/// <summary> /// Promociona una pieza /// </summary> public bool Promote(int row, int column, PieceBaseModel.PieceType type) { bool canPromote = false; PieceBaseModel piece = this[row, column]; if (piece != null && piece.Type == PieceBaseModel.PieceType.Pawn && piece.Color == Parameters.GetTurnColor() && type != PieceBaseModel.PieceType.Pawn && type != PieceBaseModel.PieceType.King && ((piece.Color == PieceBaseModel.PieceColor.White && row == 0) || (piece.Color == PieceBaseModel.PieceColor.Black && row == 7))) { // Promociona la pieza this[row, column] = CreatePiece(type, piece.Color); // Indica que se ha promocionado canPromote = true; } // Devuelve el valor que indica si ha podido promocionar return(canPromote); }
/// <summary> /// Comprueba si se puede mover de un lugar a otro /// </summary> public bool CanMove(int fromRow, int fromColumn, int toRow, int toColumn) { bool canMove = false; // Si realmente hay un movimiento if (fromRow != toRow || fromColumn != toColumn) { PieceBaseModel pieceSource = this[fromRow, fromColumn]; // Si hay una pieza en el origen del color que toca jugar y no hay nada en el destino o en el destino hay una pieza de otro color if (pieceSource != null && pieceSource.Color == Parameters.GetTurnColor() && (this[toRow, toColumn] == null || this[toRow, toColumn].Color != pieceSource.Color)) { canMove = pieceSource.CanMoveTo(this, fromRow, fromColumn, toRow, toColumn); } } // Devuelve el valor que indica si se puede mover return(canMove); }
/// <summary> /// Realiza un movimiento (sin comprobaciones por los enroques) /// </summary> private void MoveWithoutCheck(int fromRow, int fromColumn, int toRow, int toColumn, bool adjustParameters = true) { PieceBaseModel piece = this[fromRow, fromColumn]; if (piece != null) { // Mueve la pieza this[toRow, toColumn] = piece; this[fromRow, fromColumn] = null; // Asigna los datos para la captura al paso CheckEnPassantMove(piece, fromRow, toRow, toColumn); // Indica que se ha movido piece.IsMoved = true; // Ajusta los parámetros (en el caso del enroque, se hacen dos movimientos pero sólo se debe contabilizar uno) if (adjustParameters) { // Añade el movimiento Parameters.HalfMoveClock++; if (Parameters.HalfMoveClock % 2 == 0) { Parameters.FullMoveCount++; } // Cambia el turno Parameters.IsWhiteMove = !Parameters.IsWhiteMove; // Si es un rey o una torre, invalida los movimientos de enroque if (piece.Type == PieceBaseModel.PieceType.King) { Parameters.DisableCastle(piece.Color); } else if (piece.Type == PieceBaseModel.PieceType.Rook) { if (fromColumn == 0) { Parameters.DisableCastleQueenSide(piece.Color); } else if (fromColumn == 7) { Parameters.DisableCastleKingSide(piece.Color); } } } } }
/// <summary> /// Busca la pieza de un color que se puede mover a una celda /// </summary> public (int row, int column, PieceBaseModel piece) SearchMoveTo(PieceBaseModel.PieceType type, PieceBaseModel.PieceColor color, int fromRow, int fromColumn, int toRow, int toColumn) { List <(int row, int column, PieceBaseModel piece)> pieces = new List <(int row, int column, PieceBaseModel piece)>(); // Busca las piezas for (int row = 0; row < 8; row++) { for (int column = 0; column < 8; column++) { PieceBaseModel piece = this[row, column]; if (piece != null && piece.Type == type && piece.Color == color && piece.CanMoveTo(this, row, column, toRow, toColumn)) { pieces.Add((row, column, piece)); } } } // Si se le ha pasado una fila / columna para ajustarlo, obtiene la pieza que estaba inicialmente en esa posición if (pieces.Count > 1 && (fromRow != -1 || fromColumn != -1)) { foreach ((int row, int column, PieceBaseModel piece)piece in pieces) { if ((fromColumn == -1 && piece.row == fromRow) || (fromRow == -1 && piece.column == fromColumn) || (piece.row == fromRow && piece.column == fromColumn)) { return(piece); } } } // Devuelve la primera pieza localizada if (pieces.Count > 0) { return(pieces[0]); } else { return(-1, -1, null); } }
/// <summary> /// Comprueba un movimiento al paso /// </summary> private void CheckEnPassantMove(PieceBaseModel piece, int fromRow, int toRow, int toColumn) { if (piece is PawnModel && Math.Abs(fromRow - toRow) == 2) { // Asigna la celda donde se coloca el peón que se puede capturar Parameters.EnPassantCell = new CellModel(toRow, toColumn); // Asigna la celda que se puede capturar al paso if (piece.Color == PieceBaseModel.PieceColor.White) { Parameters.EnPassantCellTarget = new CellModel(toRow + 1, toColumn); } else { Parameters.EnPassantCellTarget = new CellModel(toRow - 1, toColumn); } // Asigna el color que se puede capturar al paso Parameters.EnPassantColor = piece.Color; } else { Parameters.EnPassantCellTarget = null; } }
public PieceWithCellModel(PieceBaseModel piece, CellModel cell) { Piece = piece; Cell = cell; }
/// <summary> /// Comprueba si puede capturar una pieza /// </summary> internal bool CanCapture(PieceBaseModel piece, CellModel cell) { PieceBaseModel target = Pieces.GetPiece(cell); return(target != null && target.Color != piece.Color); }
/// <summary> /// Comprueba si es una captura al paso /// </summary> public bool IsCaptureEnPassant(PieceBaseModel piece, int row, int column, PieceBaseModel target) { return(piece is PawnModel && target == null && Parameters.EnPassantCellTarget != null && Parameters.EnPassantCellTarget.Row == row && Parameters.EnPassantCellTarget.Column == column && Parameters.EnPassantColor != piece.Color); }
/// <summary> /// Comprueba si puede capturar una pieza /// </summary> internal bool CanCapture(PieceBaseModel piece, int row, int column) { PieceBaseModel target = this[row, column]; return(IsCaptureEnPassant(piece, row, column, target) || target != null && target.Color != piece.Color); }
/// <summary> /// Comprueba si es legal colocar una pieza en una posición /// </summary> internal bool IsLegalMoveTo(PieceBaseModel piece, int row, int column) { PieceBaseModel target = this[row, column]; return(target == null || target.Color != piece.Color); }