Skip to content

Commit

Permalink
Refactor Errors types
Browse files Browse the repository at this point in the history
Closes #40
  • Loading branch information
veloce committed Aug 1, 2024
1 parent 8577e98 commit 949408b
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 134 deletions.
10 changes: 6 additions & 4 deletions lib/src/board.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Board {

/// Parse the board part of a FEN string and returns a Board.
///
/// Throws a [FenError] if the provided FEN string is not valid.
/// Throws a [FenException] if the provided FEN string is not valid.
factory Board.parseFen(String boardFen) {
Board board = Board.empty;
int rank = 7;
Expand All @@ -123,18 +123,20 @@ class Board {
if (code < 57) {
file += code - 48;
} else {
if (file >= 8 || rank < 0) throw const FenError('ERR_BOARD');
if (file >= 8 || rank < 0) {
throw const FenException(IllegalFenCause.board);
}
final square = Square(file + rank * 8);
final promoted = i + 1 < boardFen.length && boardFen[i + 1] == '~';
final piece = _charToPiece(c, promoted);
if (piece == null) throw const FenError('ERR_BOARD');
if (piece == null) throw const FenException(IllegalFenCause.board);
if (promoted) i++;
board = board.setPieceAt(square, piece);
file++;
}
}
}
if (rank != 0 || file != 8) throw const FenError('ERR_BOARD');
if (rank != 0 || file != 8) throw const FenException(IllegalFenCause.board);
return board;
}

Expand Down
102 changes: 100 additions & 2 deletions lib/src/models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -630,10 +630,108 @@ class DropMove extends Move {
int get hashCode => Object.hash(to, role);
}

/// An enumeration of the possible causes of an illegal FEN string.
enum IllegalFenCause {
/// The FEN string is not in the correct format.
format,

/// The board part of the FEN string is invalid.
board,

/// The turn part of the FEN string is invalid.
turn,

/// The castling part of the FEN string is invalid.
castling,

/// The en passant part of the FEN string is invalid.
enPassant,

/// The halfmove clock part of the FEN string is invalid.
halfmoveClock,

/// The fullmove number part of the FEN string is invalid.
fullmoveNumber,

/// The remaining checks part of the FEN string is invalid.
remainingChecks,

/// The pockets part of the FEN string is invalid.
pockets,
}

/// An exception thrown when trying to parse an invalid FEN string.
@immutable
class FenException implements Exception {
/// Constructs a [FenException] with a [cause].
const FenException(this.cause);

/// The cause of the exception.
final IllegalFenCause cause;

@override
String toString() => 'FenException: ${cause.name}';
}

/// Exception thrown when trying to play an illegal move.
@immutable
class FenError implements Exception {
class PlayException implements Exception {
/// Constructs a [PlayException] with a [message].
const PlayException(this.message);

/// The exception message.
final String message;
const FenError(this.message);

@override
String toString() => 'PlayException: $message';
}

/// Enumeration of the possible causes of an illegal setup.
enum IllegalSetupCause {
/// There are no pieces on the board.
empty,

/// The player not to move is in check.
oppositeCheck,

/// There are impossibly many checkers, two sliding checkers are
/// aligned, or check is not possible because the last move was a
/// double pawn push.
///
/// Such a position cannot be reached by any sequence of legal moves.
impossibleCheck,

/// There are pawns on the backrank.
pawnsOnBackrank,

/// A king is missing, or there are too many kings.
kings,

/// A variant specific rule is violated.
variant,
}

/// Exception thrown when trying to create a [Position] from an illegal [Setup].
@immutable
class PositionSetupException implements Exception {
/// Constructs a [PositionSetupException] with a [cause].
const PositionSetupException(this.cause);

/// The cause of the exception.
final IllegalSetupCause cause;

static const empty = PositionSetupException(IllegalSetupCause.empty);
static const oppositeCheck =
PositionSetupException(IllegalSetupCause.oppositeCheck);
static const impossibleCheck =
PositionSetupException(IllegalSetupCause.impossibleCheck);
static const pawnsOnBackrank =
PositionSetupException(IllegalSetupCause.pawnsOnBackrank);
static const kings = PositionSetupException(IllegalSetupCause.kings);
static const variant = PositionSetupException(IllegalSetupCause.variant);

@override
String toString() => 'PositionSetupException: ${cause.name}';
}

/// Represents the different possible rules of chess and its variants
Expand Down
4 changes: 2 additions & 2 deletions lib/src/pgn.dart
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,11 @@ class PgnGame<T extends PgnNodeData> {
///
/// Headers can include an optional 'Variant' and 'Fen' key.
///
/// Throws a [PositionError] if it does not meet basic validity requirements.
/// Throws a [PositionSetupException] if it does not meet basic validity requirements.
static Position startingPosition(PgnHeaders headers,
{bool? ignoreImpossibleCheck}) {
final rule = Rule.fromPgn(headers['Variant']);
if (rule == null) throw PositionError.variant;
if (rule == null) throw PositionSetupException.variant;
if (!headers.containsKey('FEN')) {
return Position.initialPosition(rule);
}
Expand Down
Loading

0 comments on commit 949408b

Please sign in to comment.