#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 CHECK = 300; int MATE = 10000; int KNIGHT_TABLE[64] = {-50, -40, -30, -30, -30, -30, -40, -50, -40, -20, 0, 0, 0, 0, -20, -40, -30, 0, 10, 15, 15, 10, 0, -30, -30, 5, 15, 20, 20, 15, 5, -30, -30, 0, 15, 20, 20, 15, 0, -30, -30, 5, 10, 15, 15, 10, 5, -30, -40, -20, 0, 5, 5, 0, -20, -40, -50, -40, -30, -30, -30, -30, -40, -50}; 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 (int i = 0; i < 64; i++) { Piece piece = b->pieces[i]; if (piece.type == NONE) continue; int value = 0; switch (piece.type) { case PAWN: value = PAWN_VALUE; break; case KNIGHT: value = KNIGHT_VALUE; value += KNIGHT_TABLE[i]; 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; } bool isCheck = IsPieceTypeAttacked(b, KING, 1); if (isCheck) { score += CHECK; } if (isStaleMate) { return 0; } return score; }