|
@@ -15,23 +15,36 @@ namespace chessy
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+/*!
|
|
|
|
+ * This structure holds additional information about a move.
|
|
|
|
+ */
|
|
struct chessy::MoveInfo
|
|
struct chessy::MoveInfo
|
|
{
|
|
{
|
|
|
|
+ //! the move itself
|
|
Move move;
|
|
Move move;
|
|
|
|
+
|
|
|
|
+ //! the type of the piece that was moved
|
|
PieceType movedPiece;
|
|
PieceType movedPiece;
|
|
|
|
+
|
|
|
|
+ //! if the move is an en-passant move, this field holds the square of
|
|
|
|
+ //! the pawn, that was captured. Otherwise this index should be zero.
|
|
|
|
+ Index enPassantTarget;
|
|
|
|
+
|
|
|
|
+ inline MoveInfo(void) :
|
|
|
|
+ enPassantTarget{ 0 } {}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename T>
|
|
template<typename T>
|
|
class chessy::Search
|
|
class chessy::Search
|
|
{
|
|
{
|
|
- T& handler;
|
|
|
|
|
|
+ T handler;
|
|
ChessGame& game;
|
|
ChessGame& game;
|
|
Board& board;
|
|
Board& board;
|
|
Bitboard whites;
|
|
Bitboard whites;
|
|
Bitboard blacks;
|
|
Bitboard blacks;
|
|
public:
|
|
public:
|
|
- inline Search(T& handler, ChessGame& game) :
|
|
|
|
|
|
+ inline Search(T&& handler, ChessGame& game) :
|
|
handler{ handler }, game{ game }, board{ game.getBoard() },
|
|
handler{ handler }, game{ game }, board{ game.getBoard() },
|
|
whites{ board.getWhites() }, blacks{ board.getBlacks() } {}
|
|
whites{ board.getWhites() }, blacks{ board.getBlacks() } {}
|
|
|
|
|
|
@@ -71,6 +84,9 @@ public:
|
|
|
|
|
|
template<Side side, typename... Args>
|
|
template<Side side, typename... Args>
|
|
inline void iteratePromotions(Args&&... args);
|
|
inline void iteratePromotions(Args&&... args);
|
|
|
|
+
|
|
|
|
+ template<Side side, typename... Args>
|
|
|
|
+ inline void iterateEnPassant(Args&&... args);
|
|
private:
|
|
private:
|
|
|
|
|
|
template<Side side>
|
|
template<Side side>
|
|
@@ -115,68 +131,6 @@ inline void chessy::Search<T>::iterateAll(Args&&... args)
|
|
iterateQueens<side, Args...>(std::forward<Args>(args)...);
|
|
iterateQueens<side, Args...>(std::forward<Args>(args)...);
|
|
iterateKing<side, Args...>(std::forward<Args>(args)...);
|
|
iterateKing<side, Args...>(std::forward<Args>(args)...);
|
|
iterateCastling<side, Args...>(std::forward<Args>(args)...);
|
|
iterateCastling<side, Args...>(std::forward<Args>(args)...);
|
|
-
|
|
|
|
- /*
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- Bitboard& rs = board.getRooks<side>();
|
|
|
|
- PositionSet rooks { rs };
|
|
|
|
- for (auto rook : rooks) {
|
|
|
|
- for (auto pos : PrimitiveRookMoveGenerator{ rook, enemies, friends }) {
|
|
|
|
- Move move = { rook, pos };
|
|
|
|
- board.removeAt(move.destination);
|
|
|
|
- rs.applyMove(move);
|
|
|
|
- //BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = move;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Bitboard& qs = board.getQueens<side>();
|
|
|
|
- PositionSet queens { qs };
|
|
|
|
- for (auto queen : queens) {
|
|
|
|
- for (auto pos : PrimitiveQueenMoveGenerator{ queen, enemies, friends }) {
|
|
|
|
- Move move = { queen, pos };
|
|
|
|
- board.removeAt(move.destination);
|
|
|
|
- qs.applyMove(move);
|
|
|
|
- //BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = move;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Bitboard& king = board.getKing<side>();
|
|
|
|
- Index kingIndex = king.getLeastSignificantBit();
|
|
|
|
- for (auto pos : KingMoveGenerator{ king, friends }) {
|
|
|
|
- Move move = { kingIndex, pos };
|
|
|
|
- board.removeAt(pos);
|
|
|
|
- king.applyMove(move);
|
|
|
|
- BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = move;
|
|
|
|
- //if (depth >= 3)
|
|
|
|
- // std::cout << m.move.asString() << " " << bestMove.value << " -> " << m.value << std::endl;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (side == WHITE_SIDE) {
|
|
|
|
- if (game.getCanCastleKingSide(side)) {
|
|
|
|
- if((friends.bits & 0x6) == 0) {
|
|
|
|
- Move kingMove = {3, 1};
|
|
|
|
- Move rookMove = {0, 2};
|
|
|
|
- king.applyMove(kingMove);
|
|
|
|
- rs.applyMove(rookMove);
|
|
|
|
- board = temp;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- float v = evaluate<side>();
|
|
|
|
- bestMove.value *= 0.9f;
|
|
|
|
- bestMove.value += v * 0.2f;
|
|
|
|
- return -bestMove;*/
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -268,18 +222,31 @@ template<typename T>
|
|
template<chessy::Side side, typename... Args>
|
|
template<chessy::Side side, typename... Args>
|
|
inline void chessy::Search<T>::iterateCastling(Args&&... args)
|
|
inline void chessy::Search<T>::iterateCastling(Args&&... args)
|
|
{
|
|
{
|
|
|
|
+ Bitboard king = board.getKing<side>();
|
|
|
|
+ Bitboard allOccupied = whites | blacks;
|
|
MoveInfo moveInfo;
|
|
MoveInfo moveInfo;
|
|
moveInfo.movedPiece = PieceType::KING;
|
|
moveInfo.movedPiece = PieceType::KING;
|
|
if (game.getCanCastleKingSide(side)) {
|
|
if (game.getCanCastleKingSide(side)) {
|
|
- Bitboard king = board.getKing<side>();
|
|
|
|
Bitboard target = king.bits >> 2; // move king to the right
|
|
Bitboard target = king.bits >> 2; // move king to the right
|
|
- Bitboard rook = king.bits >> 3;
|
|
|
|
|
|
+ Bitboard rook = king.bits << 3;
|
|
Bitboard rookTarget = king.bits >> 1;
|
|
Bitboard rookTarget = king.bits >> 1;
|
|
- if (!(target | friends<WHITE_SIDE>() | friends<BLACK_SIDE>()) &&
|
|
|
|
- !(rookTarget | friends<WHITE_SIDE>() | friends<BLACK_SIDE>())) {
|
|
|
|
-
|
|
|
|
|
|
+ if (!(target & allOccupied) &&
|
|
|
|
+ !(rookTarget & allOccupied)) {
|
|
|
|
+ moveInfo.move = Move{ king.getLeastSignificantBit(),
|
|
|
|
+ target.getLeastSignificantBit(), true };
|
|
|
|
+ handler(moveInfo, std::forward<Args>(args)...);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if (game.getCanCastleQueenSide(side)) {
|
|
|
|
+ Bitboard target = king.bits << 2; // move king to the left
|
|
|
|
+ Bitboard rook = king.bits >> 3;
|
|
|
|
+ Bitboard rookTarget = king.bits << 1;
|
|
|
|
+ if (!(target & allOccupied) &&
|
|
|
|
+ !(rookTarget & allOccupied)) {
|
|
|
|
+ moveInfo.move = Move{ king.getLeastSignificantBit(),
|
|
|
|
+ target.getLeastSignificantBit(), true };
|
|
|
|
+ handler(moveInfo, std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
- moveInfo.move = Move{ king, target, true };
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
@@ -347,45 +314,43 @@ inline void chessy::Search<T>::iteratePromotions(Args&&... args)
|
|
|
|
|
|
template<typename T>
|
|
template<typename T>
|
|
template<chessy::Side side, typename... Args>
|
|
template<chessy::Side side, typename... Args>
|
|
-inline void chessy::Search<T>::iteratePawns(Args&&... args)
|
|
|
|
|
|
+inline void chessy::Search<T>::iterateEnPassant(Args&&... args)
|
|
{
|
|
{
|
|
- iterateSinglePawnPushes<side, Args...>(std::forward(args)...);
|
|
|
|
- iterateDoublePawnPushes<side, Args...>(std::forward(args)...);
|
|
|
|
- iteratePawnCaptures<side, Args...>(std::forward(args)...);
|
|
|
|
- iteratePromotions<side, Args...>(std::forward(args)...);
|
|
|
|
- /*
|
|
|
|
- PawnCaptureGenerator<side, LEFT> pl{ game };
|
|
|
|
- for (Move capture : pl) {
|
|
|
|
- Bitboard& pawns = board.getPawns<side>();
|
|
|
|
- board.removeAt(capture.destination);
|
|
|
|
- pawns.applyMove(capture);
|
|
|
|
- BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = capture;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
|
|
+ MoveInfo moveInfo;
|
|
|
|
+ moveInfo.movedPiece = PieceType::PAWN;
|
|
|
|
+ Index enPassant = game.getEnPassantIndex();
|
|
|
|
+ if (enPassant.index != -1) {
|
|
|
|
+ Bitboard pawns = board.getPawns<side>();
|
|
|
|
+ int rowIndex = side == WHITE_SIDE ? 4 : 3;
|
|
|
|
+ int targetRowIndex = side == WHITE_SIDE ? 5 : 2;
|
|
|
|
+ int columnIndex = enPassant.index;
|
|
|
|
+ Bitboard pawnColumns = 0;
|
|
|
|
+ if (columnIndex > 0)
|
|
|
|
+ pawnColumns |= Bitboard::getColumn(columnIndex - 1);
|
|
|
|
+ if (columnIndex < 7)
|
|
|
|
+ pawnColumns |= Bitboard::getColumn(columnIndex + 1);
|
|
|
|
+ pawns &= rowIndex & pawnColumns;
|
|
|
|
+
|
|
|
|
+ moveInfo.enPassantTarget = Index{ enPassant.index, rowIndex };
|
|
|
|
+ Index target{ enPassant.index, targetRowIndex };
|
|
|
|
+ PositionSet sources = pawns;
|
|
|
|
+ for (auto source : sources) {
|
|
|
|
+ moveInfo.move = Move{ source, target };
|
|
|
|
+ handler(moveInfo, std::forward<Args>(args)...);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+}
|
|
|
|
|
|
- PawnCaptureGenerator<side, RIGHT> pr{ game };
|
|
|
|
- for (Move capture : pr) {
|
|
|
|
- Bitboard& pawns = board.getPawns<side>();
|
|
|
|
- board.removeAt(capture.destination);
|
|
|
|
- pawns.applyMove(capture);
|
|
|
|
- BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = capture;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
- }
|
|
|
|
|
|
|
|
- PromotionGenerator<side> pg{ game };
|
|
|
|
- for (Move promotion : pg) {
|
|
|
|
- Bitboard& pawns = board.getPawns<side>();
|
|
|
|
- board.removeAt(promotion.destination);
|
|
|
|
- pawns.applyMove(promotion);
|
|
|
|
- BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
|
- m.move = promotion;
|
|
|
|
- bestMove.overwriteIfBetter(m);
|
|
|
|
- board = temp;
|
|
|
|
- }*/
|
|
|
|
|
|
+template<typename T>
|
|
|
|
+template<chessy::Side side, typename... Args>
|
|
|
|
+inline void chessy::Search<T>::iteratePawns(Args&&... args)
|
|
|
|
+{
|
|
|
|
+ iterateSinglePawnPushes<side, Args...>(std::forward<Args>(args)...);
|
|
|
|
+ iterateDoublePawnPushes<side, Args...>(std::forward<Args>(args)...);
|
|
|
|
+ iteratePawnCaptures<side, Args...>(std::forward<Args>(args)...);
|
|
|
|
+ iteratePromotions<side, Args...>(std::forward<Args>(args)...);
|
|
|
|
+ iterateEnPassant<side, Args...>(std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|