Connect4 minimax算法使愚蠢的举动

时间:2018-09-23 09:50:46

标签: java algorithm artificial-intelligence minimax

我正在尝试实现一种算法,该算法将为Connect 4的游戏选择最佳的下一步。由于我只想确保基本的 minimax 正常工作,所以我实际上正在测试就像4x4字段上的Connect 3。这样,我就不需要进行alpha-beta修剪,并且当算法做出愚蠢的举动时,这一点更加明显。

问题在于算法始终总是以最左手的动作开始游戏,而且在游戏过程中它也非常愚蠢。它看不到最好的动作。

我已经彻底测试了方法makeMove()undoMove()getAvailableColumns()isWinningMove()isLastSpot(),因此,我绝对确保问题不在那里。

这是我的算法。

NextMove.java

private static class NextMove {
    final int evaluation;
    final int moveIndex;

    public NextMove(int eval, int moveIndex) {
        this.evaluation = eval;
        this.moveIndex = moveIndex;
    }

    int getEvaluation() {
        return evaluation;
    }

    public int getMoveIndex() {
        return moveIndex;
    }
}

算法

private static NextMove max(C4Field field, int movePlayed) {
    // moveIndex previously validated

    // 1) check if moveIndex is a final move to make on a given field
    field.undoMove(movePlayed);

    // check
    if (field.isWinningMove(movePlayed, C4Symbol.BLUE)) {
        field.playMove(movePlayed, C4Symbol.RED);
        return new NextMove(BLUE_WIN, movePlayed);
    }
    if (field.isWinningMove(movePlayed, C4Symbol.RED)) {
        field.playMove(movePlayed, C4Symbol.RED);
        return new NextMove(RED_WIN, movePlayed);
    }
    if (field.isLastSpot()) {
        field.playMove(movePlayed, C4Symbol.RED);
        return new NextMove(DRAW, movePlayed);
    }

    field.playMove(movePlayed, C4Symbol.RED);

    // 2) moveIndex is not a final move
    // --> try all possible next moves
    final List<Integer> possibleMoves = field.getAvailableColumns();
    int bestEval = Integer.MIN_VALUE;
    int bestMove = 0;
    for (int moveIndex : possibleMoves) {           
        field.playMove(moveIndex, C4Symbol.BLUE);

        final int currentEval = min(field, moveIndex).getEvaluation();
        if (currentEval > bestEval) {
            bestEval = currentEval;
            bestMove = moveIndex;
        }

        field.undoMove(moveIndex);
    }

    return new NextMove(bestEval, bestMove);
}

private static NextMove min(C4Field field, int movePlayed) {
    // moveIndex previously validated

    // 1) check if moveIndex is a final move to make on a given field
    field.undoMove(movePlayed);

    // check
    if (field.isWinningMove(movePlayed, C4Symbol.BLUE)) {
        field.playMove(movePlayed, C4Symbol.BLUE);
        return new NextMove(BLUE_WIN, movePlayed);
    }
    if (field.isWinningMove(movePlayed, C4Symbol.RED)) {
        field.playMove(movePlayed, C4Symbol.BLUE);
        return new NextMove(RED_WIN, movePlayed);
    }
    if (field.isLastSpot()) {
        field.playMove(movePlayed, C4Symbol.BLUE);
        return new NextMove(DRAW, movePlayed);
    }

    field.playMove(movePlayed, C4Symbol.BLUE);

    // 2) moveIndex is not a final move
    // --> try all other moves
    final List<Integer> possibleMoves = field.getAvailableColumns();
    int bestEval = Integer.MAX_VALUE;
    int bestMove = 0;
    for (int moveIndex : possibleMoves) {
        field.playMove(moveIndex, C4Symbol.RED);

        final int currentEval = max(field, moveIndex).getEvaluation();
        if (currentEval < bestEval) {
            bestEval = currentEval;
            bestMove = moveIndex;
        }

        field.undoMove(moveIndex);
    }

    return new NextMove(bestEval, bestMove);
}

这个想法是该算法接受currentFieldlastPlayedMove的参数。然后,它检查最后一步是否以某种方式结束了游戏。如果是的话,我只会退还该举动,否则我将对后续举动进行深入研究。

蓝色玩家为MAX,红色玩家为MIN。

在每个步骤中,我首先撤消最后一个动作,因为检查“下一个”动作是否会完成游戏比检查当前字段是否完成要容易(这需要分析游戏中所有可能的获胜选项)领域)。检查之后,我只是重做移动。

由于某种原因,这不起作用。我坚持了好几天!我不知道出了什么问题...非常感谢您的帮助!

0 个答案:

没有答案