#include #include #include "ai_mm.h" static const int mm_depth = 4; // Positive scores for white static int evaluate(const Board &bd, int win) { const int large = 10000; int score = -large; // to counteract the +=large for KING score += 8; // to counteract the imbalance in white/black stones for (int i = 0; i < N * N; i++) { switch (bd.cells[i]) { case EMPTY: break; case WHITE: score += 1; break; case KING: score += large; break; case BLACK: score -= 1; break; } } if (win == 1) score += large; return score; } static int minimaxBlack(const Board &bd, int depth, int alpha, int beta, int win); static int minimaxWhite(const Board &bd, int depth, int alpha, int beta, int win) { if (depth == 0 || win != 0) { return evaluate(bd, win); } int bestValue = INT_MIN; bd.forEachMove(1, [&bd, depth, &alpha, &beta, &bestValue](Move mv) { Board bd2 = bd; int win = bd2.applyCW(mv); int value = minimaxBlack(bd2, depth - 1, alpha, beta, win); // cerr << string(6 - 2 * depth, ' ') << "mmW: " << mv << ": " << value << endl; bestValue = max(bestValue, value); alpha = max(alpha, bestValue); if (beta <= alpha) return true; return false; }); return bestValue; } static int minimaxBlack(const Board &bd, int depth, int alpha, int beta, int win) { if (depth == 0 || win != 0) { return evaluate(bd, win); } int bestValue = INT_MAX; bd.forEachMove(-1, [&bd, depth, &alpha, &beta, &bestValue](Move mv) { Board bd2 = bd; int win = bd2.applyCW(mv); int value = minimaxWhite(bd2, depth - 1, alpha, beta, win); // cerr << string(6 - 2 * depth, ' ') << "mmB: " << mv << ": " << value << endl; bestValue = min(bestValue, value); beta = min(beta, bestValue); if (beta <= alpha) return true; return false; }); return bestValue; } static int minimaxGeneric(const Board &bd, int depth, int alpha, int beta, int win, int player) { if (player == 1) return minimaxWhite(bd, depth, alpha, beta, win); else return minimaxBlack(bd, depth, alpha, beta, win); } Move AI::MM::findMove(const Board &bd, int player) { Move bestMove(-1, -1); int bestScore = INT_MIN; // 'bestScore', and 'score' below, have positive values good for 'player'. // cerr << "MM::findMove(player=" << player << "):" << endl; cerr << '['; bd.forEachMove(player, [&bd, player, &bestScore, &bestMove](Move mv) { Board bd2 = bd; int win = bd2.applyCW(mv); int score = player * minimaxGeneric(bd2, mm_depth, INT_MIN, INT_MAX, win, -player); // cerr << "fM: " << mv << ": " << score << endl; cerr << score << ','; if (score > bestScore) { bestScore = score; bestMove = mv; } return false; }); cerr << ']' << endl; return bestMove; }