Minimax.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. #include "Minimax.h"
  2. #include "ChessGame.h"
  3. #include <limits>
  4. using namespace chessy;
  5. template MiniMax::BestMove MiniMax::minimax<WHITE_SIDE>(int);
  6. template MiniMax::BestMove MiniMax::minimax<BLACK_SIDE>(int);
  7. #include <iostream>
  8. Move MiniMax::calculateBest(int depth)
  9. {
  10. if (game.getTurn() == WHITE_SIDE) {
  11. BestMove bm = minimax<WHITE_SIDE>(depth);
  12. return bm.move;
  13. }
  14. else
  15. return minimax<BLACK_SIDE>(depth).move;
  16. }
  17. template<Side side>
  18. float MiniMax::evaluate(void) const
  19. {
  20. int piecePoints = 0;
  21. Board& bd = game.getBoard();
  22. Bitboard p = bd.getPawns<side>();
  23. Bitboard n = bd.getKnights<side>();
  24. Bitboard b = bd.getBishops<side>();
  25. Bitboard r = bd.getRooks<side>();
  26. Bitboard q = bd.getQueens<side>();
  27. Bitboard k = bd.getKing<side>();
  28. piecePoints += 1 * p.popcount();
  29. piecePoints += 3 * n.popcount();
  30. piecePoints += 3 * b.popcount();
  31. piecePoints += 4 * r.popcount();
  32. piecePoints += 6 * q.popcount();
  33. if (k == Bitboard(0ULL))
  34. piecePoints -= 100000;
  35. const Side other = otherSide(side);
  36. p = bd.getPawns<other>();
  37. n = bd.getKnights<other>();
  38. b = bd.getBishops<other>();
  39. r = bd.getRooks<other>();
  40. q = bd.getQueens<other>();
  41. k = bd.getKing<other>();
  42. piecePoints -= 1 * p.popcount();
  43. piecePoints -= 3 * n.popcount();
  44. piecePoints -= 3 * b.popcount();
  45. piecePoints -= 4 * r.popcount();
  46. piecePoints -= 6 * q.popcount();
  47. if (k == Bitboard(0ULL))
  48. piecePoints += 100000;
  49. return piecePoints;
  50. }
  51. template<Side side>
  52. MiniMax::BestMove MiniMax::minimax(int depth)
  53. {
  54. if (depth == 0) {
  55. return { {0, 0}, -evaluate<side>() };
  56. }
  57. BestMove bestMove = { {0, 0}, -std::numeric_limits<float>::infinity() };
  58. Board& board = game.getBoard();
  59. Bitboard friends;
  60. Bitboard enemies;
  61. if (side == WHITE_SIDE) {
  62. friends = board.getWhites();
  63. enemies = board.getBlacks();
  64. }
  65. else {
  66. friends = board.getBlacks();
  67. enemies = board.getWhites();
  68. }
  69. const Board temp = board;
  70. PawnPushGenerator<side> mg{ game };
  71. for (Move push : mg) {
  72. Bitboard& pawns = board.getPawns<side>();
  73. Bitboard pTemp = pawns;
  74. pawns.applyMove(push);
  75. BestMove m = minimax<otherSide(side)>(depth - 1);
  76. m.move = push;
  77. bestMove.overwriteIfBetter(m);
  78. pawns = pTemp;
  79. }
  80. PawnDoublePushGenerator<side> dp{ game };
  81. for (Move push : dp) {
  82. Bitboard& pawns = board.getPawns<side>();
  83. Bitboard pTemp = pawns;
  84. pawns.applyMove(push);
  85. BestMove m = minimax<otherSide(side)>(depth - 1);
  86. m.move = push;
  87. bestMove.overwriteIfBetter(m);
  88. pawns = pTemp;
  89. }
  90. PawnCaptureGenerator<side, LEFT> pl{ game };
  91. for (Move capture : pl) {
  92. Bitboard& pawns = board.getPawns<side>();
  93. board.removeAt(capture.destination);
  94. pawns.applyMove(capture);
  95. BestMove m = minimax<otherSide(side)>(depth - 1);
  96. m.move = capture;
  97. bestMove.overwriteIfBetter(m);
  98. board = temp;
  99. }
  100. PawnCaptureGenerator<side, RIGHT> pr{ game };
  101. for (Move capture : pr) {
  102. Bitboard& pawns = board.getPawns<side>();
  103. board.removeAt(capture.destination);
  104. pawns.applyMove(capture);
  105. BestMove m = minimax<otherSide(side)>(depth - 1);
  106. m.move = capture;
  107. bestMove.overwriteIfBetter(m);
  108. board = temp;
  109. }
  110. PromotionGenerator<side> pg{ game };
  111. for (Move promotion : pg) {
  112. Bitboard& pawns = board.getPawns<side>();
  113. board.removeAt(promotion.destination);
  114. pawns.applyMove(promotion);
  115. BestMove m = minimax<otherSide(side)>(depth - 1);
  116. m.move = promotion;
  117. bestMove.overwriteIfBetter(m);
  118. board = temp;
  119. }
  120. Bitboard& ns = board.getKnights<side>();
  121. PositionSet knights { ns };
  122. for (auto knight : knights) {
  123. for (auto pos : KnightMoveGenerator{ knight, friends }) {
  124. Move move = { knight, pos };
  125. board.removeAt(move.destination);
  126. ns.applyMove(move);
  127. BestMove m = minimax<otherSide(side)>(depth - 1);
  128. m.move = move;
  129. bestMove.overwriteIfBetter(m);
  130. board = temp;
  131. }
  132. }
  133. Bitboard& bs = board.getBishops<side>();
  134. PositionSet bishops { bs };
  135. for (auto bishop : bishops) {
  136. for (auto pos : PrimitiveBishopMoveGenerator{ bishop, enemies, friends }) {
  137. Move move = { bishop, pos };
  138. board.removeAt(move.destination);
  139. bs.applyMove(move);
  140. BestMove m = minimax<otherSide(side)>(depth - 1);
  141. m.move = move;
  142. bestMove.overwriteIfBetter(m);
  143. board = temp;
  144. }
  145. }
  146. Bitboard& rs = board.getRooks<side>();
  147. PositionSet rooks { rs };
  148. for (auto rook : rooks) {
  149. for (auto pos : PrimitiveRookMoveGenerator{ rook, enemies, friends }) {
  150. Move move = { rook, pos };
  151. board.removeAt(move.destination);
  152. rs.applyMove(move);
  153. BestMove m = minimax<otherSide(side)>(depth - 1);
  154. m.move = move;
  155. bestMove.overwriteIfBetter(m);
  156. board = temp;
  157. }
  158. }
  159. Bitboard& qs = board.getQueens<side>();
  160. PositionSet queens { qs };
  161. for (auto queen : queens) {
  162. for (auto pos : PrimitiveQueenMoveGenerator{ queen, enemies, friends }) {
  163. Move move = { queen, pos };
  164. board.removeAt(move.destination);
  165. qs.applyMove(move);
  166. BestMove m = minimax<otherSide(side)>(depth - 1);
  167. m.move = move;
  168. bestMove.overwriteIfBetter(m);
  169. board = temp;
  170. }
  171. }
  172. Bitboard& king = board.getKing<side>();
  173. Index kingIndex = king.getLeastSignificantBit();
  174. for (auto pos : KingMoveGenerator{ king, friends }) {
  175. Move move = { kingIndex, pos };
  176. board.removeAt(pos);
  177. king.applyMove(move);
  178. BestMove m = minimax<otherSide(side)>(depth - 1);
  179. m.move = move;
  180. //if (depth >= 3)
  181. // std::cout << m.move.asString() << " " << bestMove.value << " -> " << m.value << std::endl;
  182. bestMove.overwriteIfBetter(m);
  183. board = temp;
  184. }
  185. for (auto pos : CastlingGenerator<side>{ game }) {
  186. Move move = { kingIndex, pos };
  187. king.applyMove(move);
  188. BestMove m = minimax<otherSide(side)>(depth - 1);
  189. m.move = move;
  190. //if (depth >= 3)
  191. // std::cout << m.move.asString() << " " << bestMove.value << " -> " << m.value << std::endl;
  192. bestMove.overwriteIfBetter(m);
  193. board = temp;
  194. }
  195. float v = evaluate<side>();
  196. bestMove.value *= 0.9f;
  197. bestMove.value += v * 0.2f;
  198. return -bestMove;
  199. }