#include "bot.hpp" #include "board.hpp" #include "moves.hpp" #include #include #include int PAWN_VALUE = 100; int KNIGHT_VALUE = 200; int BISHOP_VALUE = 300; int ROOK_VALUE = 400; int QUEEN_VALUE = 900; int MATE = 10000; const int SEARCH_DEPTH = 3; Move EngineGetBestMove(Game *b) { auto moves = GetLegalMoves(b); if (moves.size() == 0) { assert(false && "Unhanled error zero legal moves for bot"); } Move bestMove = moves[0]; float BestEval = (b->turn ? -INFINITY : INFINITY); for (Move move : moves) { Game TestBoard = *b; PlayMove(move, &TestBoard); float alpha = -INFINITY; float beta = INFINITY; float eval = minimax(SEARCH_DEPTH - 1, &TestBoard, alpha, beta); if (b->turn) { if (eval > BestEval) { BestEval = eval; bestMove = move; } } else { if (eval < BestEval) { BestEval = eval; bestMove = move; } } } return bestMove; } float minimax(int depth, Game *b, float alpha, float beta) { if (depth == 0) { return EvaluateBoardForWhite(b); } auto moves = GetLegalMoves(b); if (moves.size() == 0) { return EvaluateBoardForWhite(b); } if (b->turn) { float bestEval = -INFINITY; for (Move move : moves) { Game next = *b; PlayMove(move, &next); float eval = minimax(depth - 1, &next, alpha, beta); bestEval = std::max(bestEval, eval); alpha = std::max(alpha, bestEval); if (alpha >= beta) { break; } } return bestEval; } else { float BestEval = INFINITY; for (Move move : moves) { Game next = *b; PlayMove(move, &next); float eval = minimax(depth - 1, &next, alpha, beta); BestEval = std::min(BestEval, eval); beta = std::min(beta, BestEval); if (alpha >= beta) { break; // *snips* } } return BestEval; } } float EvaluateBoardForWhite(Game *b) { float score = 0; bool isStaleMate = false; GetLegalMoves(b); if (b->state == WHITE_WON) { return MATE; } if (b->state == BLACK_WON) { return -MATE; } if (b->state == STALEMATE || b->state == DRAW) { isStaleMate = true; } for (Piece piece : b->pieces) { if (piece.type == NONE) continue; int value = 0; switch (piece.type) { case PAWN: value = PAWN_VALUE; break; case KNIGHT: value = KNIGHT_VALUE; break; case BISHOP: value = BISHOP_VALUE; break; case ROOK: value = ROOK_VALUE; break; case QUEEN: value = QUEEN_VALUE; break; default: break; } if (piece.color) score += value; else score -= value; } if (isStaleMate) { return 0; } return score; }