【问题标题】:Implementing the minimax实现极小极大
【发布时间】:2015-07-20 21:47:17
【问题描述】:

有人可以帮我解决这个问题吗?我正在尝试为我的井字游戏编写人工智能,所有相关搜索都将我带到了极小极大算法。从我阅读和观看的所有内容中,我对算法背后的理论有了基本的了解。我遇到的问题是它在我的游戏中的实际应用。我知道这个算法本质上应该根据棋盘的状态来完成每一步并返回一个分数。如何让它每次播放不同的组合?我如何确保获得每个组合?在它找到获胜状态后,我如何从中返回正确的移动?我应该将每个状态存储在一个数组中吗?对于所有的问题,我只是想巩固我的理解并确保我可以真正将我正在阅读的内容付诸实践。我正在为游戏提供我的 javascript 代码,希望有人可以在这里为我指明正确的方向。谢谢。

$(document).ready(function() {

    var x = 'X';
    var o = 'O';
    var newgame = function() {
        turn = x;
        sqrData = '';
        xMoves = [false,false,false,false,false,false,false,false,false,false,false,false];
        oMoves = [false,false,false,false,false,false,false,false,false,false,false,false];
        squareFree = [false,true,true,true,true,true,true,true,true,true];
        moveCount = 0;
        compPlayer = false;
        playboard = [false,[false,true,true,true],[false,true,true,true],[false,true,true,true]]
        $('div').html('');
        $('#reset').html('Reset Game');

     };
    newgame();

    $('#fir').click(function() {
       turnchange(1,1,1,$(this));
    });
    $('#sec').click(function() {
        turnchange(2,1,2,$(this));
    });
    $('#thir').click(function() {
       turnchange(3,1,3,$(this));
    });
    $('#four').click(function() {
        turnchange(4,2,1,$(this));
    });
    $('#fiv').click(function() {
       turnchange(5,2,2,$(this));
    });
    $('#six').click(function() {
        turnchange(6,2,3,$(this));
    });
    $('#sev').click(function() {
        turnchange(7,3,1,$(this));
    });
    $('#eight').click(function() {
      turnchange(8,3,2,$(this));
    });
    $('#nine').click(function() {
       turnchange(9,3,3,$(this));
    });
    var turnchange = function(playerSquare,playRow,playCol,sqrData) {
        playboard[playRow][playCol] = turn;
        console.log(playboard);
        if (squareFree[playerSquare] == true) {
            $(sqrData).html(turn);
            if (turn == x) {
                xMoves[playerSquare] = true;
                turn = o;
            }
            else if (turn == o) {
                oMoves[playerSquare] = true;
                turn = x;
            }

            squareFree[playerSquare] = false;
            moveCount++;
            checkwin($(this));
        }
    };

    var checkwin = function() {
          if ((xMoves[1] && xMoves[2] && xMoves[3]) || (xMoves[1] && xMoves[4] && xMoves[7]) ||
            (xMoves[1] && xMoves[5] && xMoves[9]) || (xMoves[2] && xMoves[5] && xMoves[8]) ||
            (xMoves[3] && xMoves[6] && xMoves[9]) || (xMoves[4] && xMoves[5] && xMoves[6]) || (xMoves[7] && xMoves[8] && xMoves[9]) ||
            (xMoves[3] && xMoves[5] && xMoves[7])) {
            $('#game').html('Game Over - X Wins');
            deactivateSquares();
        }
        else if ((oMoves[1] && oMoves[2] && oMoves[3]) || (oMoves[1] && oMoves[4] && oMoves[7]) ||
            (oMoves[1] && oMoves[5] && oMoves[9]) || (oMoves[2] && oMoves[5] && oMoves[8]) ||
            (oMoves[3] && oMoves[6] && oMoves[9]) || (oMoves[4] && oMoves[5] && oMoves[6]) || (oMoves[7] && oMoves[8] && oMoves[9]) ||
            (oMoves[3] && oMoves[5] && oMoves[7])) {
            $('#game').html('Game Over - O Wins');
            deactivateSquares();
        }
        else if (moveCount == 9) {
            $('#game').html('Its a Draw');
        }

    };
    var deactivateSquares = function() {
        for (var e in squareFree) {
            squareFree[e]= false;
        }

    };


    $('#reset').click(function(){
        newgame();
        });

});

【问题讨论】:

  • 我曾经也写过其中的一个,虽然现在看起来有点谜 - alhambra.x10.bz/tic-tac-toe(源代码中的mx 是极小极大函数)。

标签: javascript algorithm tic-tac-toe minimax


【解决方案1】:

首先你需要一个score :: Configuration -> N 函数。配置是板子的当前状态。

我们可以绘制所有可能配置的树。叶子包含棋盘的分数。 MAX是你,MIN是你的对手:

Configuration      Player
        A           MAX
    /       \
   B         C      MIN
 /   \     /   \
D,1  E,3  F,2  G,1  MAX

minmax 是遍历这棵树的递归算法。它计算给定配置和播放器的最佳选择(基于您的score 函数)。注意MAX的目标是最大化scoreMIN的目标是最小化它。

minMax(c, player)
  if c is leaf:
    return score(c)

  if player == MAX:
    bestScore = -inf
    moves = generateAllMoves(c)
    for each move m in moves:
      c = makeMove(c, m)
      currScore = minMax(c, MIN)
      if currScore > bestScore
        bestScore = currScore
      c = undoMove(c, m)
    return bestScore

  if player == MIN:
    bestScore = +inf
    moves = generateAllMoves(c)
    for each move m in moves:
      c = makeMove(c, m)
      bestScore = minMax(c, MAX)
      if currScore < bestScore
        score = currScore
      c = undoMove(c, m)
    return bestScore

getBestMove(c):
  bestScore = -inf
  bestMove = null
  for each move m in c:
    c = makeMove(c, m)
    currScore = minMax(c, MIN)
    if currScore > bestScore
      bestScore = currScore
      bestMove = m
    c = undoMove(c, m)
  return bestMove 

minMax(c, MAX) 返回MIN 玩家可以强制你达到的最高分数,即它保证无论你的对手采取什么策略,你总能达到至少minMax(c, MAX) 分数。

  1. 如何让它每次播放不同的组合?

您的评分函数可以是随机的。例如:score(c) = deterministic_score(c) + rand() * 0.0001

  1. 如何确保获得所有组合?

您必须正确实施移动生成算法。

  1. 在它找到获胜状态后,我如何从中返回正确的移动?

如果您的score 函数返回+inf 表示获胜状态,并且您始终选择getBestMove 返回的移动,那么您将始终处于获胜状态(前提是您的对手没有反制策略对于它,搜索的深度是无限的)。

  1. 我应该将每个状态存储在一个数组中吗?

您可以生成所有动作并即时修改棋盘。

【讨论】:

  • 感谢您仓促而深思熟虑的回复。非常有用。
猜你喜欢
  • 2019-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 2016-10-02
相关资源
最近更新 更多