Альфа-бета-порядок перемещения

У меня есть базовая реализация обрезки альфа-бета, но я понятия не имею, как улучшить порядок перемещения. Я прочитал, что это можно сделать с помощью неглубокого поиска, итеративного углубления или сохранения таблицы лучших путей для перехода.

Любые предложения по реализации одного из этих усовершенствований в этом алгоритме?

 public double alphaBetaPruning(Board board, int depth, double alpha, double beta, int player) {
    if (depth == 0) {
        return board.evaluateBoard();
    }

    Collection<Move> children = board.generatePossibleMoves(player);
    if (player == 0) {
        for (Move move : children) {
            Board tempBoard = new Board(board);
            tempBoard.makeMove(move);
            int nextPlayer = next(player);
            double result = alphaBetaPruning(tempBoard, depth - 1, alpha,beta,nextPlayer);
            if ((result > alpha)) {
                alpha = result;
                if (depth == this.origDepth) {
                    this.bestMove = move;
                }
            }
            if (alpha >= beta) {
                break;
            }
        }
        return alpha;
    } else {
        for (Move move : children) {
            Board tempBoard = new Board(board);
            tempBoard.makeMove(move);
            int nextPlayer = next(player);
            double result = alphaBetaPruning(tempBoard, depth - 1, alpha,beta,nextPlayer);
            if ((result < beta)) {
                beta = result;
                if (depth == this.origDepth) {
                    this.bestMove = move;
                }
            }
            if (beta <= alpha) {
                break;
            }
        }
        return beta;
    }
}

public int next(int player) {
    if (player == 0) {
        return 4;
    } else {
        return 0;
    }
}

Ответ 1

  • Node переупорядочение с мелким поиском тривиально: вычислить эвристическое значение для каждого дочернего элемента состояния до рекурсивного проверяя их. Затем отсортируйте значения этих состояний [по убыванию для максимальной вершины и возрастания для минимальной вершины] и рекурсивно вызывать алгоритм в отсортированном списке. Идея заключается в том, что если государство хорошо неглубокой глубины, он, скорее всего, будет хорош и в глубоком состоянии, и если это правда, вы получите больше пренебрежений.

    Сортировка должна быть сделана до этой [в предложениях if и else]

    for (Move move : children) {

  • Сохранение ходов также тривиально - многие состояния вычисляются дважды, когда вы закончите вычисление любого состояния, сохраните его [с глубиной расчет! он неэффективен!] в HashMap. Первое, что вы делаете когда вы начинаете вычисление по вершине - это проверка, если она уже вычисляется - и если это так, возвращается кешированное значение. Идея это то, что многие состояния достижимы с разных путей, так что это путь - вы можете исключить избыточные вычисления.

    Изменения должны быть сделаны как в первой строке метода [что-то вроде if (cache.contains((new State(board,depth,player)) return cache.get(new State(board,depth,player))] [извините, из-за отсутствия элегантности и эффективности, просто объясняя идею здесь]. Вы также должны добавить cache.put(...) перед каждым оператором return.

Ответ 2

Прежде всего, нужно разобраться в рассуждениях по поводу упорядочения движения в алгоритме обрезки альфа-бета. Альфа-бета дает тот же результат, что и минимакс, но во многих случаях может делать это быстрее, потому что он не выполняет поиск по нерелевантным ветвям.

Это не всегда быстрее, потому что это не гарантирует обрезание, если в худшем случае он вообще не будет обрезать и искать абсолютно то же дерево, что и минимакс, и будет медленнее из-за сохранения значений в /b, В лучшем случае (максимальная обрезка) он позволяет одновременно искать дерево в 2 раза глубину. Для случайного дерева он может искать в 4/3 раза глубже в одно и то же время.

Порядок перемещения может быть реализован несколькими способами:

  • У вас есть эксперт по домену, который дает вам представление о том, какие шаги лучше. Например, при продвижении в шахматы пешки, захват предметов с высокой стоимостью с более низкой стоимостью, в среднем хорошие ходы. В шашки лучше убить больше шашек в ходу, чем меньше шашки, и лучше создать королеву. Таким образом, ваша функция генерации движений возвращает лучшие ходы перед
  • вы получаете эвристику о том, насколько хорош переход от оценки положения на 1 уровне глубины меньше (ваш мелкий поиск/итеративное углубление). Вы рассчитали оценку на глубине n-1, отсортировали движения и затем оценили на глубине n.

Второй подход, о котором вы говорили, не имеет никакого отношения к упорядочению перемещения. Это связано с тем, что оценочная функция может быть дорогостоящей, и многие позиции оцениваются много раз. Чтобы обойти это, вы можете сохранить значения позиции в хеше, как только вы ее вычислили, и повторно использовать позже.