MiniMax实施

时间:2013-04-25 18:06:24

标签: java minimax

我正在尝试用Java编写一个实现miniMax算法的小型AI算法。

基于此的游戏是双人游戏,其中两个玩家每回合进行一次移动,并且每个棋盘位置导致每个玩家得分。通过从玩家X的该位置的得分中减去对手的得分来评估玩家X的位置的“质量”。每个移动由一个整数表示(即,通过输入1移动一个,通过输入2移动两个等)

我知道应该使用递归来实现miniMax。目前我有:

一个evaluate()方法,它将一个表示板状态的对象作为参数(即“BoardState”对象和一个名为“max”的布尔值(签名将是 evaluate(BoardState myBoard,boolean max) )。

当玩家X轮到时,

max为真。给定一个棋盘位置,它将评估所有可能的移动并返回对玩家X最有利的那些。如果是对手的回合,则max将为false并且该方法将返回对玩家X最不利的移动(即:最有利于玩家y)

但是,我在编写实际的miniMax方法时遇到了困难。我的一般结构如下:

public int miniMax(GameState myGameState, int depth)

我提交了最初的gameState和我想要查看的“深度”。

我会有类似的东西:

int finalMove = 0;
while(currentDepth < depth) {
    GameState tmp = myGameState.copy();
    int finalMove = evaluate(tmp, true or false);
    iniMax(tmp.makeMove(finalMove));

}
return finalMove;

这听起来像是合理的实施吗?有什么建议? :)

谢谢!

2 个答案:

答案 0 :(得分:3)

不会工作。

详细信息:

  1. 会导致无限循环。 currentdepth永远不会增加
  2. 您对评估的定义似乎与大多数人不同。通常,评估函数将返回游戏状态的预测值。您对evaluate函数的定义是否与minimax函数的定义相同?
  3. miniMax和MiniMax有什么不同?因为如果你的意思是递归,那么你需要在调用下一个miniMax时传递depth-1
  4. minimax的想法是深度优先搜索。并且评估叶子节点(具有最大深度的节点或节点是胜利或平局)并且如果当前玩家是最大化的那个则选择一个最大值并且如果当前玩家是最小化则选择最小值一。

    这就是我实施它的方式:

    function miniMax(node, depth)
        if(depth == 0) then --leaf node     
            local ret = evaluate(node.state)
            return ret
        else -- winning node
            local winner = whoWin(node.state)       
            if(winner == 1) then -- P1      
                return math.huge
            elseif(winner == -1) then -- P2         
                return math.huge*-1
            end 
        end
    
        local num_of_moves = getNumberOfMoves(node.state)   
        local v_t = nil
        local best_move_index = nil 
        if(getTurn(node.state) == 1) then -- maximizing player      
        local v = -math.huge 
            for i=0, num_of_moves-1 do                      
                local child_node = simulate(node.state, i)) -- simulate move number i
                v_t = miniMax(child_node, depth-1)
                if(v_t > v) then 
                    v = v_t 
                    best_move_index = i             
                end
            end             
            if(best_move_index == nil) then best_move_index = random(0, num_of_moves-1) end 
            return v, best_move_index
        else -- minimizing player
        local v = math.huge
            for i=0, num_of_moves-1 do          
                local child_node = simulate(node.state, i)
                v_t = miniMax(child_node, depth-1)
                if(v_t < v) then                
                    v = v_t             
                    best_move_index = i             
                end
            end
            if(best_move_index == nil) then best_move_index = random(0, num_of_moves-1) end
            return v, best_move_index                               
        end 
    end
    

    注意:

    • return v,best_move_index表示返回v和best_move_index的两个值(上面的代码在lua和lua中可以返回多个值)

    • 评估函数为两个玩家返回相同的分数(即,在视点P1中的游戏状态A得分为23,在视点P2中得分为23)

    • 这个算法只有在两个玩家交替运行时才会起作用(没有玩家可以连续跑两个动作),你可以通过给对手一个动作来欺骗这个限制,即移动PASS(跳过他/她的回合)如果其他玩家需要移动两次。

    • 这个极小极大可以进一步优化(从最简单的那个中排序):

      1. alpha-beta修剪
      2. 迭代深化
      3. 移动订购

答案 1 :(得分:0)

我在lua中实现了minimax。我希望它有助于让您了解如何从Java角度处理算法,代码应该与您非常相似。它专为一个井字游戏而设计。

--caller is the player who is using the minimax function
--initial state is the board from which the player must make a move
local function minimax(caller,inital_state)
    local bestState = {}; --we use this to store the game state the the player will create
      --this recurse function is really the 'minimax' algorithim 
    local function recurse(state,depth)
        --childPlayer is the person who will have their turn in the current state's children
        local ChildPlayer = getTurn(state)
        --parentPlayer is the person who is looking at their children
        local ParentPlayer = getPreviousTurn(state)
        --this represents the worst case scenario for a player
        local alpha =  - (ChildPlayer == caller and 1 or -1 );
        --we check for terminal conditions (leaf nodes) and return the appropriate objective value
        if win(state) then
            --return +,- inf depending on who called the 'minimax'
            return ParentPlayer == caller and 1 or -1;
        elseif tie(state) then 
            --if it's a tie then the value is 0 (neither win or loss)
            return  0;
        else
            --this will return a list of child states FROM the current state
            children = getChildrenStates(state,ChildPlayer)
            --enumerate over each child
            for _,child in ipairs(children) do
                --find out the child's objective value
                beta = recurse(child,depth+1);
                if ChildPlayer == caller then 
                    --We want to maximize
                    if beta >= alpha then 
                        alpha = beta
                        --if the depth is 0 then we can add the child state as the bestState (this will because the caller of minimax will always want to choose the GREATEST value on the root node)
                        if depth == 0 then
                            bestState = child;
                        end 
                    end 
                --we want to MINIMIZE
                elseif beta <= alpha then 
                    alpha = beta;
                end 
            end 
        end
         --return a non-terminal nodes value (propagates values up the tree)
        return alpha;           
    end
     --start the 'minimax' function by calling recurse on the initial state
    recurse(inital_state,0);
     --return the best move
    return bestState;
end