part of "../legal_moves.dart"; class _LegalMovesBlack { _LegalMovesBlack._(); static Stream<(String, Position)> _getLegalMoves(Position position) => _getValidOrCheckedMoves(position).where(((String, Position) move) => !_isBlackChecked(move.$2)); static Stream<(String, Position)> _getValidOrCheckedMoves(Position position) async* { for (int i = 0; i < 64; i++) { switch (position.board[i]) { case Piece.emptySquare: case Piece.whitePawn: case Piece.whiteKnight: case Piece.whiteBishop: case Piece.whiteRook: case Piece.whiteQueen: case Piece.whiteKing: break; case Piece.blackPawn: yield* _getBlackPawnMoves(position, i); break; case Piece.blackKnight: yield* _getBlackKnightMoves(position, i); break; case Piece.blackBishop: yield* _getBlackBishopMoves(position, i); break; case Piece.blackRook: yield* _getBlackRookMoves(position, i); break; case Piece.blackQueen: yield* _getBlackBishopMoves(position, i); yield* _getBlackRookMoves(position, i); break; case Piece.blackKing: yield* _getBlackKingMoves(position, i); break; } } } static Stream<(String, Position)> _getBlackPawnMoves(Position position, int i) async* { int j = i+8; if (Piece.emptySquare == position.board[j]) { // pawn forward if (i > 47) { final String squareFrom = Position.squareIndexToString(i); final String squareTo = Position.squareIndexToString(j); yield ("$squareFrom${squareTo}q", Position.from(position)..playMoveIndices(i, j, "q")); yield ("$squareFrom${squareTo}r", Position.from(position)..playMoveIndices(i, j, "r")); yield ("$squareFrom${squareTo}b", Position.from(position)..playMoveIndices(i, j, "b")); yield ("$squareFrom${squareTo}k", Position.from(position)..playMoveIndices(i, j, "k")); } else { final String squareFrom = Position.squareIndexToString(i); yield ("$squareFrom${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); j = i+16; if (i < 16 && Piece.emptySquare == position.board[j]) { // pawn more forward yield ("$squareFrom${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } } j = i+7; if (i % 8 > 0 && (j == position.enPassantTargetSquare || Piece.isWhite(position.board[j]))) { // pawn takes left if (i > 47) { final String squareFrom = Position.squareIndexToString(i); final String squareTo = Position.squareIndexToString(j); yield ("$squareFrom${squareTo}q", Position.from(position)..playMoveIndices(i, j, "q")); yield ("$squareFrom${squareTo}r", Position.from(position)..playMoveIndices(i, j, "r")); yield ("$squareFrom${squareTo}b", Position.from(position)..playMoveIndices(i, j, "b")); yield ("$squareFrom${squareTo}k", Position.from(position)..playMoveIndices(i, j, "k")); } else { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j = i+9; if (i % 8 < 7 && (j == position.enPassantTargetSquare || Piece.isWhite(position.board[j]))) { // pawn takes right if (i > 47) { final String squareFrom = Position.squareIndexToString(i); final String squareTo = Position.squareIndexToString(j); yield ("$squareFrom${squareTo}q", Position.from(position)..playMoveIndices(i, j, "q")); yield ("$squareFrom${squareTo}r", Position.from(position)..playMoveIndices(i, j, "r")); yield ("$squareFrom${squareTo}b", Position.from(position)..playMoveIndices(i, j, "b")); yield ("$squareFrom${squareTo}k", Position.from(position)..playMoveIndices(i, j, "k")); } else { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } } static Stream<(String, Position)> _getBlackKnightMoves(Position position, int i) async* { final bool canGoUp2 = i > 15; final bool canGoUp1 = i > 7; final bool canGoDown1 = i < 56; final bool canGoDown2 = i < 48; final int column = i % 8; final bool canGoLeft2 = column > 1; final bool canGoLeft1 = column > 0; final bool canGoRight1 = column < 7; final bool canGoRight2 = column < 6; if (canGoUp1) { if (canGoLeft2 && !Piece.isBlack(position.board[i-10])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-10)}", Position.from(position)..playMoveIndices(i, i-10)); } if (canGoRight2 && !Piece.isBlack(position.board[i-6])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-6)}", Position.from(position)..playMoveIndices(i, i-6)); } if (canGoUp2) { if (canGoLeft1 && !Piece.isBlack(position.board[i-17])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-17)}", Position.from(position)..playMoveIndices(i, i-17)); } if (canGoRight1 && !Piece.isBlack(position.board[i-15])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-15)}", Position.from(position)..playMoveIndices(i, i-15)); } } } if (canGoDown1) { if (canGoLeft2 && !Piece.isBlack(position.board[i+6])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+6)}", Position.from(position)..playMoveIndices(i, i+6)); } if (canGoRight2 && !Piece.isBlack(position.board[i+10])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+10)}", Position.from(position)..playMoveIndices(i, i+10)); } if (canGoDown2) { if (canGoLeft1 && !Piece.isBlack(position.board[i+15])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+15)}", Position.from(position)..playMoveIndices(i, i+15)); } if (canGoRight1 && !Piece.isBlack(position.board[i+17])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+17)}", Position.from(position)..playMoveIndices(i, i+17)); } } } } static Stream<(String, Position)> _getBlackBishopMoves(Position position, int i) async* { final int column = i % 8; // up left bool hasEncounteredPiece = false; int k = column-1; int j = i-9; while (!hasEncounteredPiece && k >= 0 && j >= 0) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } k--; j-=9; } // up right hasEncounteredPiece = false; k = column+1; j = i-7; while (!hasEncounteredPiece && k < 8 && j >= 0) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } k++; j-=7; } // down left hasEncounteredPiece = false; k = column-1; j = i+7; while (!hasEncounteredPiece && k >= 0 && j < 64) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } k--; j+=7; } // down right hasEncounteredPiece = false; k = column+1; j = i+9; while (!hasEncounteredPiece && k < 8 && j < 64) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } k++; j+=9; } } static Stream<(String, Position)> _getBlackRookMoves(Position position, int i) async* { final int column = i % 8; // up bool hasEncounteredPiece = false; int j = i-8; while (!hasEncounteredPiece && j > 0) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j-=8; } // down hasEncounteredPiece = false; j = i+8; while (!hasEncounteredPiece && j < 64) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j+=8; } // left hasEncounteredPiece = false; int k = column-1; j = i-1; while (!hasEncounteredPiece && k >= 0) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j-=1; k-=1; } // right hasEncounteredPiece = false; k = column+1; j = i+1; while (!hasEncounteredPiece && k < 8) { if (Piece.emptySquare == position.board[j]) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } else { hasEncounteredPiece = true; if (Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j+=1; k+=1; } } static Stream<(String, Position)> _getBlackKingMoves(Position position, int i) async* { int j = i-8; if (j >= 0 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+8; if (j < 64 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } if (i % 8 > 0) { j = i-1; if (!Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i-9; if (j >= 0 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+7; if (j < 64 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } if (i % 8 < 7) { j = i+1; if (!Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i-7; if (j >= 0 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+9; if (j < 64 && !Piece.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } if(!_isWhiteAttacking(position, i)) { j = i-2; if ( position.canBlackCastleQueenside && Piece.emptySquare == position.board[i-1] && Piece.emptySquare == position.board[i-2] && !_isWhiteAttacking(position, i-1) ) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+2; if ( position.canBlackCastleKingside && Piece.emptySquare == position.board[i+1] && Piece.emptySquare == position.board[i+2] && !_isWhiteAttacking(position, i+1) ) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } } static int _getBlackKingSquare(Position position) { for (int i = 0; i < 64; i++) { if (position.board[i] == Piece.blackKing) { return i; } } throw KingNotFoundException(); } static bool _isBlackChecked(Position position) => _isWhiteAttacking(position, _getBlackKingSquare(position)); static bool _isWhiteAttacking(Position position, int square) { if (_isWhitePawnAttacking(position, square)) { return true; } if (_isWhiteKnightAttacking(position, square)) { return true; } if (_isWhiteBishopOrQueenAttacking(position, square)) { return true; } if (_isWhiteRookOrQueenAttacking(position, square)) { return true; } if (_isWhiteKingAttacking(position, square)) { return true; } return false; } static bool _isWhitePawnAttacking(Position position, int square) { if (square < 8) { return false; } final int column = square % 8; if (column > 0 && Piece.whitePawn == position.board[square + 7]) { return true; } if (column < 7 && Piece.whitePawn == position.board[square + 9]) { return true; } return false; } static bool _isWhiteKnightAttacking(Position position, int square) { final bool canGoUp2 = square > 15; final bool canGoUp1 = square > 7; final bool canGoDown1 = square < 56; final bool canGoDown2 = square < 48; final int column = square % 8; final bool canGoLeft2 = column > 1; final bool canGoLeft1 = column > 0; final bool canGoRight1 = column < 7; final bool canGoRight2 = column < 6; if (canGoUp1) { if (canGoLeft2 && Piece.whiteKnight == position.board[square-10]) { return true; } if (canGoRight2 && Piece.whiteKnight == position.board[square-6]) { return true; } if (canGoUp2) { if (canGoLeft1 && Piece.whiteKnight == position.board[square-17]) { return true; } if (canGoRight1 && Piece.whiteKnight == position.board[square-15]) { return true; } } } if (canGoDown1) { if (canGoLeft2 && Piece.whiteKnight == position.board[square+6]) { return true; } if (canGoRight2 && Piece.whiteKnight == position.board[square+10]) { return true; } if (canGoDown2) { if (canGoLeft1 && Piece.whiteKnight == position.board[square+15]) { return true; } if (canGoRight1 && Piece.whiteKnight == position.board[square+17]) { return true; } } } return false; } static bool _isWhiteBishopOrQueenAttacking(Position position, int square) { final int column = square % 8; // up left bool hasEncounteredPiece = false; int k = column-1; int j = square-9; while (!hasEncounteredPiece && k >= 0 && j >= 0) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteBishop || Piece.whiteQueen) { return true; } } k--; j-=9; } // up right hasEncounteredPiece = false; k = column+1; j = square-7; while (!hasEncounteredPiece && k < 8 && j >= 0) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteBishop || Piece.whiteQueen) { return true; } } k++; j-=7; } // down left hasEncounteredPiece = false; k = column-1; j = square+7; while (!hasEncounteredPiece && k >= 0 && j < 64) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteBishop || Piece.whiteQueen) { return true; } } k--; j+=7; } // down right hasEncounteredPiece = false; k = column+1; j = square+9; while (!hasEncounteredPiece && k < 8 && j < 64) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteBishop || Piece.whiteQueen) { return true; } } k++; j+=9; } return false; } static bool _isWhiteRookOrQueenAttacking(Position position, int square) { final int column = square % 8; // up bool hasEncounteredPiece = false; int j = square-8; while (!hasEncounteredPiece && j > 0) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteRook || Piece.whiteQueen) { return true; } } j-=8; } // down hasEncounteredPiece = false; j = square + 8; while (!hasEncounteredPiece && j < 64) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteRook || Piece.whiteQueen) { return true; } } j+=8; } // left hasEncounteredPiece = false; j = square - 1; int k = column - 1; while (!hasEncounteredPiece && k > 0) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteRook || Piece.whiteQueen) { return true; } } j--; k--; } // right hasEncounteredPiece = false; j = square + 1; k = column + 1; while (!hasEncounteredPiece && k < 8) { final int piece = position.board[j]; if (Piece.emptySquare != piece) { hasEncounteredPiece = true; if (piece case Piece.whiteRook || Piece.whiteQueen) { return true; } } j++; k++; } return false; } static bool _isWhiteKingAttacking(Position position, int square) { if (square > 7 && Piece.whiteKing == position.board[square - 8]) { return true; } if (square < 56 && Piece.whiteKing == position.board[square + 8]) { return true; } if (square % 8 > 0) { if (Piece.whiteKing == position.board[square - 1]) { return true; } if (square > 7 && Piece.whiteKing == position.board[square - 9]) { return true; } if (square < 56 && Piece.whiteKing == position.board[square + 7]) { return true; } } if (square % 8 < 7) { if (Piece.whiteKing == position.board[square + 1]) { return true; } if (square > 7 && Piece.whiteKing == position.board[square - 7]) { return true; } if (square < 56 && Piece.whiteKing == position.board[square + 9]) { return true; } } return false; } }