internal BoardPosition(int internalFile, int internalRank) { if (!(internalFile >= 0 && internalFile <= 7)) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("InternalFile", internalFile); throw ex; } if (!(internalRank >= 0 && internalRank <= 7)) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("InternalRank", internalRank); throw ex; } this.InternalFile = internalFile; this.InternalRank = internalRank; this.File = (char)('A' + (char)internalFile); this.Rank = internalRank + 1; }
/// <summary> /// Initialises a new instance of the BoardPosition class with the given vertical file and horizontal rank. /// </summary> /// <param name="file">Vertical file - 'A' through 'H'.</param> /// <param name="rank">Horizontal rank - 1 through 8.</param> public BoardPosition(char file, int rank) { if (!((file >= 'A' && file <= 'H') || (file >= 'a' && file <= 'h'))) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("File", file); throw ex; } if (!(rank >= 1 && rank <= 8)) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("Rank", rank); throw ex; } this.File = file; this.Rank = rank; this.InternalFile = (file >= 'A' && file <= 'H') ? file - 'A' : file - 'a'; this.InternalRank = rank - 1; }
/// <summary> /// Move a chess piece from one board position to another. /// </summary> /// <param name="fromBoardPosition">The board position to move a chess piece from</param> /// <param name="toBoardPosition">The board position to move a chess piece to</param> public void MakeMove(BoardPosition from, BoardPosition to) { Square fromSquare = GetSquare(from); Square toSquare = GetSquare(to); ChessPiece pieceBeingMoved = fromSquare.ChessPiece; if (pieceBeingMoved == null) { var ex = new ChessBoardException(ExceptionReason.FromSquareIsNotOccupied); throw ex; } GameResult? gameResult = null; ExceptionReasonDetail exceptionReasonDetail; MoveResult moveResult = pieceBeingMoved.ValidateMove(this, from, to, out exceptionReasonDetail); switch (moveResult) { case MoveResult.Valid: // Does this move involve a piece being taken ? if (toSquare.ChessPiece != null) { ChessPiece takenPiece = toSquare.ChessPiece; RaisePieceTaken(toSquare, takenPiece); takenPiece.BoardPosition = null; gameResult = (pieceBeingMoved.Colour == Colour.White) ? GameResult.WhiteWin : GameResult.BlackWin; } fromSquare.ChessPiece = null; toSquare.ChessPiece = pieceBeingMoved; pieceBeingMoved.BoardPosition = to; RaiseMoveMade(from, to, pieceBeingMoved); break; case MoveResult.Collision: gameResult = GameResult.Draw; break; case MoveResult.Illegal: var ex = new ChessBoardException(ExceptionReason.IllegalMove, exceptionReasonDetail); throw ex; default: break; } // By convention, White always goes first so if we just moved // a Black piece, this must be the end of a round. // NOTE: There is nothing in the SpecFlow features regarding :- // - which colour goes first // - checking that turns alternate colour // - checking the maximum number of rounds (meant to be 2) // - etc. if (pieceBeingMoved.Colour == Colour.Black) { this.Round++; } if (gameResult.HasValue) { RaiseGameOver(gameResult.Value); } }
/// <summary> /// Add a chess piece to the board at a given position. /// </summary> /// <param name="boardPosition">The initial position at which to place the chess piece</param> /// <param name="chessPiece">The chess piece to be placed</param> public void SetInitialPosition(BoardPosition boardPosition, ChessPiece chessPiece) { Square square = GetSquare(boardPosition); if (square.ChessPiece != null) { var ex = new ChessBoardException(ExceptionReason.InitialPositionAlreadyOccupied); throw ex; } square.ChessPiece = chessPiece; chessPiece.BoardPosition = boardPosition; }
public static void SetChessBoardException(ChessBoardException ex) { ScenarioContext.Current[CHESSBOARD_EXCEPTION_KEY] = ex; }
private void Parse(string name) { if (name.Length != 2) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("Name", name); throw ex; } char file = name[0]; char rankChar = name[1]; if (!((file >= 'A' && file <= 'H') || (file >= 'a' && file <= 'h'))) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("File", file); throw ex; } if (!(rankChar >= '1' && rankChar <= '8')) { var ex = new ChessBoardException(ExceptionReason.InvalidBoardPosition); ex.Data.Add("Rank", rankChar); throw ex; } int rank = rankChar - '0'; this.File = file; this.Rank = rank; this.InternalFile = (file >= 'A' && file <= 'H') ? file - 'A' : file - 'a'; this.InternalRank = rank - 1; }
// If we were testing against a real GUI instead of just a domain model, // the GUI might handle events/exceptions and update a UI element such as // a status bar to display a message. We mimic that here by storing a message // in the ScenarioContext. private void SetChessBoardExceptionMessage(ChessBoardException ex) { string message = null; string messageDetail = null; switch (ex.ExceptionReason) { case ExceptionReason.IllegalMove: message = ILLEGAL_MOVE_EXCEPTION_MESSAGE; switch (ex.ExceptionReasonDetail) { case ExceptionReasonDetail.PawnCannotMoveTwoSpacesAtThisTime: messageDetail = ILLEGAL_PAWN_MOVE_DETAIL_TWO_SPACES; break; case ExceptionReasonDetail.PawnCannotMoveDiagonallyUnlessCapturing: messageDetail = ILLEGAL_PAWN_MOVE_DETAIL_DIAGONAL; break; } break; case ExceptionReason.InvalidBoardPosition: message = ILLEGAL_MOVE_EXCEPTION_MESSAGE; break; } if (message != null) { ScenarioContextUtils.SetChessBoardMessage(message); } if (messageDetail != null) { ScenarioContextUtils.SetChessBoardMessageDetail(messageDetail); } }