part of "../legal_moves.dart"; class _LegalMovesWhite { _LegalMovesWhite._(); static Iterable<(String, Position)> _getLegalMoves(Position position) => _getValidOrCheckedMoves(position).where(((String, Position) move) => !_isWhiteChecked(move.$2)); static Iterable<(String, Position)> _getValidOrCheckedMoves(Position position) sync* { for (int i = 0; i < 64; i++) { switch (position.board[i]) { case Piece.emptySquare: case Piece.blackPawn: case Piece.blackKnight: case Piece.blackBishop: case Piece.blackRook: case Piece.blackQueen: case Piece.blackKing: break; case Piece.whitePawn: yield* _getWhitePawnMoves(position, i); break; case Piece.whiteKnight: yield* _getWhiteKnightMoves(position, i); break; case Piece.whiteBishop: yield* _getWhiteBishopMoves(position, i); break; case Piece.whiteRook: yield* _getWhiteRookMoves(position, i); break; case Piece.whiteQueen: yield* _getWhiteBishopMoves(position, i); yield* _getWhiteRookMoves(position, i); break; case Piece.whiteKing: yield* _getWhiteKingMoves(position, i); break; } } } static Iterable<(String, Position)> _getWhitePawnMoves(Position position, int i) sync* { int j = i-8; if (Piece.emptySquare == position.board[j]) { // pawn forward if (i < 16) { 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 > 47 && Piece.emptySquare == position.board[j]) { // pawn more forward yield ("$squareFrom${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } } j = i-9; if (i % 8 > 0 && (j == position.enPassantTargetSquare || Piece.isBlack(position.board[j]))) { // pawn takes left if (i < 16) { 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-7; if (i % 8 < 7 && (j == position.enPassantTargetSquare || Piece.isBlack(position.board[j]))) { // pawn takes right if (i < 16) { 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 Iterable<(String, Position)> _getWhiteKnightMoves(Position position, int i) sync* { 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.isWhite(position.board[i-10])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-10)}", Position.from(position)..playMoveIndices(i, i-10)); } if (canGoRight2 && !Piece.isWhite(position.board[i-6])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-6)}", Position.from(position)..playMoveIndices(i, i-6)); } if (canGoUp2) { if (canGoLeft1 && !Piece.isWhite(position.board[i-17])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-17)}", Position.from(position)..playMoveIndices(i, i-17)); } if (canGoRight1 && !Piece.isWhite(position.board[i-15])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i-15)}", Position.from(position)..playMoveIndices(i, i-15)); } } } if (canGoDown1) { if (canGoLeft2 && !Piece.isWhite(position.board[i+6])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+6)}", Position.from(position)..playMoveIndices(i, i+6)); } if (canGoRight2 && !Piece.isWhite(position.board[i+10])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+10)}", Position.from(position)..playMoveIndices(i, i+10)); } if (canGoDown2) { if (canGoLeft1 && !Piece.isWhite(position.board[i+15])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+15)}", Position.from(position)..playMoveIndices(i, i+15)); } if (canGoRight1 && !Piece.isWhite(position.board[i+17])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(i+17)}", Position.from(position)..playMoveIndices(i, i+17)); } } } } static Iterable<(String, Position)> _getWhiteBishopMoves(Position position, int i) sync* { 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.isBlack(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.isBlack(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.isBlack(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.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } k++; j+=9; } } static Iterable<(String, Position)> _getWhiteRookMoves(Position position, int i) sync* { 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.isBlack(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.isBlack(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.isBlack(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.isBlack(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } j+=1; k+=1; } } static Iterable<(String, Position)> _getWhiteKingMoves(Position position, int i) sync* { int j = i-8; if (j >= 0 && !Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+8; if (j < 64 && !Piece.isWhite(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.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i-9; if (j >= 0 && !Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+7; if (j < 64 && !Piece.isWhite(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.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i-7; if (j >= 0 && !Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+9; if (j < 64 && !Piece.isWhite(position.board[j])) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } if(!_isBlackAttacking(position, i)) { j = i-2; if ( position.canWhiteCastleQueenside && Piece.emptySquare == position.board[i-1] && Piece.emptySquare == position.board[i-2] && !_isBlackAttacking(position, i-1) ) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } j = i+2; if ( position.canWhiteCastleKingside && Piece.emptySquare == position.board[i+1] && Piece.emptySquare == position.board[i+2] && !_isBlackAttacking(position, i+1) ) { yield ("${Position.squareIndexToString(i)}${Position.squareIndexToString(j)}", Position.from(position)..playMoveIndices(i, j)); } } } static int _getWhiteKingSquare(Position position) { for (int i = 0; i < 64; i++) { if (position.board[i] == Piece.whiteKing) { return i; } } throw KingNotFoundException(); } static bool _isWhiteChecked(Position position) => _isBlackAttacking(position, _getWhiteKingSquare(position)); static bool _isBlackAttacking(Position position, int square) { if (_isBlackPawnAttacking(position, square)) { return true; } if (_isBlackKnightAttacking(position, square)) { return true; } if (_isBlackBishopOrQueenAttacking(position, square)) { return true; } if (_isBlackRookOrQueenAttacking(position, square)) { return true; } if (_isBlackKingAttacking(position, square)) { return true; } return false; } static bool _isBlackPawnAttacking(Position position, int square) { if (square < 16) { return false; } final int column = square % 8; if (column > 0 && Piece.blackPawn == position.board[square - 9]) { return true; } if (column < 7 && Piece.blackPawn == position.board[square - 7]) { return true; } return false; } static bool _isBlackKnightAttacking(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.blackKnight == position.board[square-10]) { return true; } if (canGoRight2 && Piece.blackKnight == position.board[square-6]) { return true; } if (canGoUp2) { if (canGoLeft1 && Piece.blackKnight == position.board[square-17]) { return true; } if (canGoRight1 && Piece.blackKnight == position.board[square-15]) { return true; } } } if (canGoDown1) { if (canGoLeft2 && Piece.blackKnight == position.board[square+6]) { return true; } if (canGoRight2 && Piece.blackKnight == position.board[square+10]) { return true; } if (canGoDown2) { if (canGoLeft1 && Piece.blackKnight == position.board[square+15]) { return true; } if (canGoRight1 && Piece.blackKnight == position.board[square+17]) { return true; } } } return false; } static bool _isBlackBishopOrQueenAttacking(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.blackBishop || Piece.blackQueen) { 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.blackBishop || Piece.blackQueen) { 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.blackBishop || Piece.blackQueen) { 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.blackBishop || Piece.blackQueen) { return true; } } k++; j+=9; } return false; } static bool _isBlackRookOrQueenAttacking(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.blackRook || Piece.blackQueen) { 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.blackRook || Piece.blackQueen) { 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.blackRook || Piece.blackQueen) { 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.blackRook || Piece.blackQueen) { return true; } } j++; k++; } return false; } static bool _isBlackKingAttacking(Position position, int square) { if (square > 7 && Piece.blackKing == position.board[square - 8]) { return true; } if (square < 56 && Piece.blackKing == position.board[square + 8]) { return true; } if (square % 8 > 0) { if (Piece.blackKing == position.board[square - 1]) { return true; } if (square > 7 && Piece.blackKing == position.board[square - 9]) { return true; } if (square < 56 && Piece.blackKing == position.board[square + 7]) { return true; } } if (square % 8 < 7) { if (Piece.blackKing == position.board[square + 1]) { return true; } if (square > 7 && Piece.blackKing == position.board[square - 7]) { return true; } if (square < 56 && Piece.blackKing == position.board[square + 9]) { return true; } } return false; } }