|
@@ -0,0 +1,185 @@
|
|
|
+#ifndef CHESSY_SEARCH_H
|
|
|
+#define CHESSY_SEARCH_H
|
|
|
+
|
|
|
+#include "ChessGame.h"
|
|
|
+
|
|
|
+namespace chessy
|
|
|
+{
|
|
|
+ template<typename T>
|
|
|
+ class Search;
|
|
|
+
|
|
|
+ class MinimaxN;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+template<typename T>
|
|
|
+class chessy::Search
|
|
|
+{
|
|
|
+ T& handler;
|
|
|
+ ChessGame& game;
|
|
|
+public:
|
|
|
+ inline Search(T& handler, ChessGame& game) :
|
|
|
+ game{ game }, handler{ handler } {}
|
|
|
+
|
|
|
+
|
|
|
+ template<typename... Args>
|
|
|
+ inline void iterateAll(Args&&... args);
|
|
|
+private:
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+class chessy::MinimaxN
|
|
|
+{
|
|
|
+public:
|
|
|
+ bool operator () (int a, int b) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+inline void aga() {
|
|
|
+ chessy::ChessGame cg;
|
|
|
+ chessy::MinimaxN mm;
|
|
|
+ chessy::Search<chessy::MinimaxN> search = { mm, cg };
|
|
|
+ search.iterateAll(5, 8ULL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+template<typename... Args>
|
|
|
+inline void chessy::Search::iterateAll(Args&&... args)
|
|
|
+{
|
|
|
+ Board& board = game.getBoard();
|
|
|
+ Bitboard friends;
|
|
|
+ Bitboard enemies;
|
|
|
+ if (side == WHITE_SIDE) {
|
|
|
+ friends = board.getWhites();
|
|
|
+ enemies = board.getBlacks();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ friends = board.getBlacks();
|
|
|
+ enemies = board.getWhites();
|
|
|
+ }
|
|
|
+
|
|
|
+ const Board temp = board;
|
|
|
+ PawnPushGenerator<side> mg{ game };
|
|
|
+ for (Move push : mg) {
|
|
|
+ Bitboard& pawns = board.getPawns<side>();
|
|
|
+ Bitboard pTemp = pawns;
|
|
|
+ pawns.applyMove(push);
|
|
|
+ BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
+ m.move = push;
|
|
|
+ bestMove.overwriteIfBetter(m);
|
|
|
+ pawns = pTemp;
|
|
|
+ }
|
|
|
+
|
|
|
+ PawnDoublePushGenerator<side> dp{ game };
|
|
|
+ for (Move push : dp) {
|
|
|
+ Bitboard& pawns = board.getPawns<side>();
|
|
|
+ Bitboard pTemp = pawns;
|
|
|
+ pawns.applyMove(push);
|
|
|
+ BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
+ m.move = push;
|
|
|
+ bestMove.overwriteIfBetter(m);
|
|
|
+ pawns = pTemp;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Bitboard& ns = board.getKnights<side>();
|
|
|
+ PositionSet knights { ns };
|
|
|
+ for (auto knight : knights) {
|
|
|
+ for (auto pos : KnightMoveGenerator{ knight, friends }) {
|
|
|
+ Move move = { knight, pos };
|
|
|
+ board.removeAt(move.destination);
|
|
|
+ ns.applyMove(move);
|
|
|
+ BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
+ m.move = move;
|
|
|
+ bestMove.overwriteIfBetter(m);
|
|
|
+ board = temp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Bitboard& bs = board.getBishops<side>();
|
|
|
+ PositionSet bishops { bs };
|
|
|
+ for (auto bishop : bishops) {
|
|
|
+ for (auto pos : PrimitiveBishopMoveGenerator{ bishop, enemies, friends }) {
|
|
|
+ Move move = { bishop, pos };
|
|
|
+ board.removeAt(move.destination);
|
|
|
+ bs.applyMove(move);
|
|
|
+ BestMove m = minimax<otherSide(side)>(depth - 1);
|
|
|
+ m.move = move;
|
|
|
+ bestMove.overwriteIfBetter(m);
|
|
|
+ board = temp;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ float v = evaluate<side>();
|
|
|
+ bestMove.value *= 0.9f;
|
|
|
+ bestMove.value += v * 0.2f;
|
|
|
+ return -bestMove;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+#endif // CHESSY_SEARCH_H
|