我正在尝试用Java编写一个实现miniMax算法的小型AI算法。
基于此的游戏是双人游戏,其中两个玩家每回合进行一次移动,并且每个棋盘位置导致每个玩家得分。通过从玩家X的该位置的得分中减去对手的得分来评估玩家X的位置的“质量”。每个移动由一个整数表示(即,通过输入1移动一个,通过输入2移动两个等)
我知道应该使用递归来实现miniMax。目前我有:
一个evaluate()
方法,它将一个表示板状态的对象作为参数(即“BoardState”对象和一个名为“max”的布尔值(签名将是 evaluate(BoardState myBoard,boolean max) )。
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;
这听起来像是合理的实施吗?有什么建议? :)
谢谢!
答案 0 :(得分:3)
不会工作。
详细信息:
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 :(得分: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