为什么minimax在这种情况下不选择最优解
why minimax don't choose the optimal solution in this situation
我正在为 cs50 课程做 tictactoe 项目
当我使用 minimax 时,我发现 minimax 在某些情况下找不到最优解
这是我的代码:
"""
Tic Tac Toe Player
"""
import copy
import math
X = "X"
O = "O"
EMPTY = None
def initial_state():
"""
Returns starting state of the board.
"""
return [[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY]]
board = initial_state()
def player(board):
"""
Returns player who has the next turn on a board.
"""
numO = 0
numX = 0
FirstPlayer = None
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == O:
numO += 1
elif board[i][j] == X:
numX += 1
return X if numO == numX else O
def actions(board):
"""
Returns set of all possible actions (i, j) available on the board.
"""
possact = set()
for i in range(len(board)):
for j in range(len(board[i])):
if board [i][j] == EMPTY:
possact.add((i, j))
return possact
def result(board, action):
"""
Returns the board that results from making move (i, j) on the board.
"""
boardcopy = copy.deepcopy(board)
boardcopy[action[0]][action[1]] = player(board)
return boardcopy
def winner(board):
"""
Returns the winner of the game, if there is one.
"""
for i in range(3):
wonO = True
wonX = True
for j in range(3):
if board[i][j] == O or board[i][j] == EMPTY:
wonX = False
if board[i][j] == X or board[i][j] == EMPTY:
wonO = False
if wonX:
return X
if wonO:
return O
for j in range(3):
wonO = True
wonX = True
for i in range(3):
if board[i][j] == X or board[i][j] == EMPTY:
wonO = False
if board[i][j] == O or board[i][j] == EMPTY:
wonX = False
if wonX:
return X
if wonO:
return O
diag1 = ''
diag2 = ''
j = 2
for i in range(3):
diag1 += str(board[i][i])
diag2 += str(board[i][j])
j -= 1
if diag1 == 'XXX' or diag2 == 'XXX':
return X
elif diag1 == 'OOO' or diag2 == 'OOO':
return O
def terminal(board):
"""
Returns True if game is over, False otherwise.
"""
if winner(board) == X:
return True
elif winner(board) == O:
return True
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == EMPTY:
return False
return True
def utility(board):
"""
Returns 1 if X has won the game, -1 if O has won, 0 otherwise.
"""
resB = winner(board)
if resB == X:
return 1
elif resB == O:
return -1
else:
return 0
def minimax(board):
"""
Returns the optimal action for the current player on the board.
"""
if terminal(board):
return None
Max = float("-inf")
Min = float("inf")
if player(board) == X:
return Max_Value(board, Max, Min)[1]
else:
return Min_Value(board, Max, Min)[1]
def Max_Value(board, Max, Min):
move = None
if terminal(board):
return [utility(board), None]
v = float('-inf')
for action in actions(board):
test = Min_Value(result(board, action), Max, Min)[0]
Max = max(Max, test)
if test > v:
v = test
move = action
if Max >= Min:
break
return [v, move]
def Min_Value(board, Max, Min):
move = None
if terminal(board):
return [utility(board), None]
v = float('inf')
for action in actions(board):
test = Max_Value(result(board, action), Max, Min)[0]
Min = min(Min, test)
if test < v:
v = test
move = action
if Max >= Min:
break
return [v, move]
情况如下(电脑玩O):
picture of 5th move
最佳解决方案是中间单元格的底部
但它选择了这个:picture of 6th move
计算机最终获胜但不是最佳方式
为什么minimax不选择最优解?
我该如何解决?
我没有查看您的代码是否正确实现了 minimax,但我可以解释为什么会出现这样的结果。
游戏树中可能有几条路径通向具有相同效用值的节点。 minimax算法不区分快赢和慢赢;它采取任何能保证获胜的路径。
解决这个问题的一种常见方法是为较慢的胜利分配较低的效用。例如,将胜利的效用设置为 1000 - depth
。相反,损失的效用应设置为 -1000 + depth
,以使算法更愿意尽可能长时间地提取不可避免的损失。 (如果您想使用 negamax,保持评估函数对称也很好。)
我正在为 cs50 课程做 tictactoe 项目
当我使用 minimax 时,我发现 minimax 在某些情况下找不到最优解
这是我的代码:
"""
Tic Tac Toe Player
"""
import copy
import math
X = "X"
O = "O"
EMPTY = None
def initial_state():
"""
Returns starting state of the board.
"""
return [[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY],
[EMPTY, EMPTY, EMPTY]]
board = initial_state()
def player(board):
"""
Returns player who has the next turn on a board.
"""
numO = 0
numX = 0
FirstPlayer = None
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == O:
numO += 1
elif board[i][j] == X:
numX += 1
return X if numO == numX else O
def actions(board):
"""
Returns set of all possible actions (i, j) available on the board.
"""
possact = set()
for i in range(len(board)):
for j in range(len(board[i])):
if board [i][j] == EMPTY:
possact.add((i, j))
return possact
def result(board, action):
"""
Returns the board that results from making move (i, j) on the board.
"""
boardcopy = copy.deepcopy(board)
boardcopy[action[0]][action[1]] = player(board)
return boardcopy
def winner(board):
"""
Returns the winner of the game, if there is one.
"""
for i in range(3):
wonO = True
wonX = True
for j in range(3):
if board[i][j] == O or board[i][j] == EMPTY:
wonX = False
if board[i][j] == X or board[i][j] == EMPTY:
wonO = False
if wonX:
return X
if wonO:
return O
for j in range(3):
wonO = True
wonX = True
for i in range(3):
if board[i][j] == X or board[i][j] == EMPTY:
wonO = False
if board[i][j] == O or board[i][j] == EMPTY:
wonX = False
if wonX:
return X
if wonO:
return O
diag1 = ''
diag2 = ''
j = 2
for i in range(3):
diag1 += str(board[i][i])
diag2 += str(board[i][j])
j -= 1
if diag1 == 'XXX' or diag2 == 'XXX':
return X
elif diag1 == 'OOO' or diag2 == 'OOO':
return O
def terminal(board):
"""
Returns True if game is over, False otherwise.
"""
if winner(board) == X:
return True
elif winner(board) == O:
return True
for i in range(len(board)):
for j in range(len(board[i])):
if board[i][j] == EMPTY:
return False
return True
def utility(board):
"""
Returns 1 if X has won the game, -1 if O has won, 0 otherwise.
"""
resB = winner(board)
if resB == X:
return 1
elif resB == O:
return -1
else:
return 0
def minimax(board):
"""
Returns the optimal action for the current player on the board.
"""
if terminal(board):
return None
Max = float("-inf")
Min = float("inf")
if player(board) == X:
return Max_Value(board, Max, Min)[1]
else:
return Min_Value(board, Max, Min)[1]
def Max_Value(board, Max, Min):
move = None
if terminal(board):
return [utility(board), None]
v = float('-inf')
for action in actions(board):
test = Min_Value(result(board, action), Max, Min)[0]
Max = max(Max, test)
if test > v:
v = test
move = action
if Max >= Min:
break
return [v, move]
def Min_Value(board, Max, Min):
move = None
if terminal(board):
return [utility(board), None]
v = float('inf')
for action in actions(board):
test = Max_Value(result(board, action), Max, Min)[0]
Min = min(Min, test)
if test < v:
v = test
move = action
if Max >= Min:
break
return [v, move]
情况如下(电脑玩O):
picture of 5th move
最佳解决方案是中间单元格的底部
但它选择了这个:picture of 6th move
计算机最终获胜但不是最佳方式
为什么minimax不选择最优解?
我该如何解决?
我没有查看您的代码是否正确实现了 minimax,但我可以解释为什么会出现这样的结果。
游戏树中可能有几条路径通向具有相同效用值的节点。 minimax算法不区分快赢和慢赢;它采取任何能保证获胜的路径。
解决这个问题的一种常见方法是为较慢的胜利分配较低的效用。例如,将胜利的效用设置为 1000 - depth
。相反,损失的效用应设置为 -1000 + depth
,以使算法更愿意尽可能长时间地提取不可避免的损失。 (如果您想使用 negamax,保持评估函数对称也很好。)