为什么我的 minimax 算法没有做出完美的移动 - 一维国际象棋?
Why my minimax algorithm doesn't make the perfect move - 1D Chess?
我正在尝试开发一种极小极大算法来下一维国际象棋,我正在考虑以下内容:8 个对齐的方格、1 个国王、1 个马和 1 个车。国王和车以通常的方式移动,而马一次移动 2 个方格。另外,如果相持或无法将死(只有2个国王或2个国王和一个额外的马)或8步没有减少棋子数量,则为平局。
这些是游戏本身的功能
from copy import deepcopy
# Board -> [list of pieces and non pieces, turn, plays without chagnge number of pieces]
# Piece -> 'K0', 'N1', 'R0', ...
def new_board():
return [['K0','N0','R0','--','--','R1','N1','K1'], 0, 0]
# Return True if there is any piece on the position index and False otherwise
def pieceQ(board, index):
return board[0][index][0] in ['K','N','R']
def available_piece(board, piece):
return piece in board[0]
# Return position of the piece
def piece_index(board, piece):
if piece in board[0]:
return board[0].index(piece)
else:
return -1
# Return the piece on position index
def index_piece(board, index):
if pieceQ(board, index):
return board[0][index]
else:
return '--'
def print_board(board, code = -1):
if code == -1:
print(board[0])
else:
second_board = deepcopy(board[0])
second_board[code] = '*'+second_board[code]+'*'
print(second_board)
def available_pieces(board):
a_pieces = []
for x in board[0]:
if x[1]==str(board[1]):
a_pieces += [x]
return a_pieces
# Returns the position of the pieces before and after the rook
def min_max_rook(board):
rook_index = board[0].index('R'+str(board[1]))
minim = 0
for i in range(len(board[0][:rook_index])):
if pieceQ(board, i):
minim = i
if index_piece(board, i)[1]==str(board[1]):
minim+=1
maxim = 7
for i in range(7, rook_index, -1):
if pieceQ(board, i):
maxim = i
if index_piece(board,i)[1]==str(board[1]):
maxim-=1
return (minim, maxim)
def available_moves(board):
pieces = available_pieces(board)
moves = []
for piece in pieces:
piece_ind = piece_index(board, piece)
# Move King
if piece[0]=='K':
# Move forward
if piece_ind<7:
second_board = deepcopy(board)
if index_piece(board, piece_ind+1)[1]!=str(board[1]) and index_piece(board, piece_ind+1)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind+1, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind+1)]
# Move backwards
if piece_ind>0:
second_board = deepcopy(board)
if index_piece(board, piece_ind-1)[1]!=str(board[1]) and index_piece(board, piece_ind-1)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind-1, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind-1)]
# Move Knight
elif piece[0]=='N':
# Move forward
if piece_ind<6:
second_board = deepcopy(board)
if index_piece(board, piece_ind+2)[1]!=str(board[1]) and index_piece(board, piece_ind+2)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind+2, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind+2)]
# Move backwards
if piece_ind>1:
second_board = deepcopy(board)
if index_piece(board, piece_ind-2)[1]!=str(board[1]) and index_piece(board, piece_ind-2)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind-2, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind-2)]
# Move Rook
elif piece[0]=='R':
minim, maxim = min_max_rook(board)
for i in range(minim, maxim+1):
second_board = deepcopy(board)
if i!=piece_ind and index_piece(board, i)[0]!='K':
second_board_2 = move(second_board, piece[0], i, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], i)]
return moves
def move(board, piece, position, free=False):
if not free and (piece, position) not in available_moves(board):
print('It is impossible to move '+piece+' to',position)
raise # IMPOSSIBLE MOVE
elif not available_piece(board, piece+str(board[1])):
raise #PIECE NOT AVAILABLE
else:
n_pieces_old = len([i for i in range(len(board[0])) if pieceQ(board,i)])
old_position = piece_index(board, piece+str(board[1]))
board[0][old_position] = '--'
board[0][position] = piece+str(board[1])
board[1] = (board[1]+1)%2
n_pieces_new = len([i for i in range(len(board[0])) if pieceQ(board,i)])
if n_pieces_old==n_pieces_new:
board[2] += 1
return [board[0],board[1],board[2]+1]
else:
board[2] = 0
return [board[0],board[1],0]
# Returns True if board is in a check position for player board[1]
def check(board):
king_index = piece_index(board, 'K'+str(board[1]))
if king_index+2 <= 7 and index_piece(board, king_index+2) == 'N'+str((board[1]+1)%2):
return True
elif king_index-2 >= 0 and index_piece(board, king_index-2) == 'N'+str((board[1]+1)%2):
return True
else:
# Check with Rook
rook_index = piece_index(board,'R'+str((board[1]+1)%2))
if rook_index != -1:
if abs(king_index-rook_index)==1:
return True
found = False
for i in range(min(king_index, rook_index)+1, max(king_index, rook_index)):
found = found or (pieceQ(board, i))
if not found:
return True
# Check with king
king_index_2 = piece_index(board, 'K'+str((board[1]+1)%2))
if abs(king_index-king_index_2)==1:
return True
else:
return False
def stalemate(board):
return (not check(board) and len(available_moves(board))==0) or len([board[0][i] for i in range(len(board[0])) if pieceQ(board, i)])==2 or (len([x for x in board[0] if x[0] in ['K', 'N']])==3 and len([i for i in range(len(board[0])) if pieceQ(board,i)])==3) or board[2]==8
def checkmate(board):
return check(board) and len(available_moves(board))==0
def game_over(board):
return checkmate(board) or stalemate(board)
def evaluate_board(board):
if not board[1]:
# Defeat
if checkmate(board):
return -1
# Victory
elif checkmate([board[0], (board[1]+1)%2]):
return 1
else:
return 0
else:
# Defeat
if checkmate(board):
return 1
# Victory
elif checkmate([board[0], (board[1]+1)%2]):
return -1
else:
return 0
这是我在 Codecademy tic tac toe 算法中启发的 minimax 算法。在这里,我保证将死棋总会发生。
def minimax(input_board, is_maximizing, max_depth=8):
depth = max_depth-1
# Base case - the game is over, so we return the value of the board
if game_over(input_board):
return [evaluate_board(input_board), ('','')]
# The maximizing player
elif is_maximizing:
# The best value starts at the lowest possible value
best_value = -float("Inf")
best_move = ('','')
av_moves = available_moves(input_board)
if len(av_moves)==1:
return [best_value, av_moves[0]]
else:
for m in av_moves:
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
if checkmate(new_board):
return [best_value, m]
# Loop through all the available moves
for m in av_moves:
# Make a copy of the board and apply the move to it
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
# Recursively find your opponent's best move
if depth >= 0:
hypothetical_value = minimax(new_board, False, depth)[0]
else:
return [(best_value if best_move != ('','') else 0), (best_move if best_move != ('','') else m)]
# Update best value if you found a better hypothetical value
if hypothetical_value > best_value:
best_value = hypothetical_value
best_move = m
return [best_value, (best_move if best_move != ('','') else m)]
# The minimizing player
else:
# The best value starts at the highest possible value
best_value = float("Inf")
best_move = ('','')
av_moves = available_moves(input_board)
if len(av_moves)==1:
return [best_value, av_moves[0]]
else:
for m in av_moves:
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
if checkmate(new_board):
return [best_value, m]
# Testing all potential moves
for m in av_moves:
# Copying the board and making the move
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
# Passing the new board back to the maximizing player
if depth >= 0:
hypothetical_value = minimax(new_board, True, depth)[0]
else:
return [(best_value if best_move != ('','') else 0), (best_move if best_move != ('','') else m)]
# Keeping track of the best value seen so far
if hypothetical_value < best_value:
best_value = hypothetical_value
best_move = m
return [best_value, (best_move if best_move != ('','') else m)]
(我考虑了从 0 到 7 的方块的棋盘)
玩家 0 是第一个上场的玩家。问题是我可以作为玩家 0 击败算法,我的移动是 - N3,N5,R3,K1,N7 - 但我可以作为玩家 1 移动 - N4,K6,N2,K5。这是我作为玩家 1 绘制的游戏。
['K0', 'N0', 'R0', '--', '--', 'R1', 'N1', 'K1']
['K0', '--', 'R0', 'N0', '--', 'R1', 'N1', 'K1']
件,位置:n4
['K0', '--', 'R0', 'N0', 'N1', 'R1', '--', 'K1']
['K0', '--', 'R0', '--', 'N1', 'N0', '- -', 'K1']
棋子,位置:k6
['K0', '--', 'R0', '--', 'N1', 'N0', 'K1', ' --']
['--', 'K0', 'R0', '--', 'N1', 'N0', 'K1', '--']
件,位置:n2
['--', 'K0', 'N1', '--', '--', 'N0', 'K1', '- -']
['--', '--', 'K0', '--', '--', 'N0', 'K1', '--']
我认为在我的 k6 之后它应该与车一起前进而不是与国王一起前进。
这样他最终可以平局而不是输球。
希望你能帮助我。
谢谢!
问题是我使用深度的方式不起作用。它应该在开头(在基本情况下)。我想问题已经解决了。
我正在尝试开发一种极小极大算法来下一维国际象棋,我正在考虑以下内容:8 个对齐的方格、1 个国王、1 个马和 1 个车。国王和车以通常的方式移动,而马一次移动 2 个方格。另外,如果相持或无法将死(只有2个国王或2个国王和一个额外的马)或8步没有减少棋子数量,则为平局。
这些是游戏本身的功能
from copy import deepcopy
# Board -> [list of pieces and non pieces, turn, plays without chagnge number of pieces]
# Piece -> 'K0', 'N1', 'R0', ...
def new_board():
return [['K0','N0','R0','--','--','R1','N1','K1'], 0, 0]
# Return True if there is any piece on the position index and False otherwise
def pieceQ(board, index):
return board[0][index][0] in ['K','N','R']
def available_piece(board, piece):
return piece in board[0]
# Return position of the piece
def piece_index(board, piece):
if piece in board[0]:
return board[0].index(piece)
else:
return -1
# Return the piece on position index
def index_piece(board, index):
if pieceQ(board, index):
return board[0][index]
else:
return '--'
def print_board(board, code = -1):
if code == -1:
print(board[0])
else:
second_board = deepcopy(board[0])
second_board[code] = '*'+second_board[code]+'*'
print(second_board)
def available_pieces(board):
a_pieces = []
for x in board[0]:
if x[1]==str(board[1]):
a_pieces += [x]
return a_pieces
# Returns the position of the pieces before and after the rook
def min_max_rook(board):
rook_index = board[0].index('R'+str(board[1]))
minim = 0
for i in range(len(board[0][:rook_index])):
if pieceQ(board, i):
minim = i
if index_piece(board, i)[1]==str(board[1]):
minim+=1
maxim = 7
for i in range(7, rook_index, -1):
if pieceQ(board, i):
maxim = i
if index_piece(board,i)[1]==str(board[1]):
maxim-=1
return (minim, maxim)
def available_moves(board):
pieces = available_pieces(board)
moves = []
for piece in pieces:
piece_ind = piece_index(board, piece)
# Move King
if piece[0]=='K':
# Move forward
if piece_ind<7:
second_board = deepcopy(board)
if index_piece(board, piece_ind+1)[1]!=str(board[1]) and index_piece(board, piece_ind+1)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind+1, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind+1)]
# Move backwards
if piece_ind>0:
second_board = deepcopy(board)
if index_piece(board, piece_ind-1)[1]!=str(board[1]) and index_piece(board, piece_ind-1)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind-1, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind-1)]
# Move Knight
elif piece[0]=='N':
# Move forward
if piece_ind<6:
second_board = deepcopy(board)
if index_piece(board, piece_ind+2)[1]!=str(board[1]) and index_piece(board, piece_ind+2)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind+2, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind+2)]
# Move backwards
if piece_ind>1:
second_board = deepcopy(board)
if index_piece(board, piece_ind-2)[1]!=str(board[1]) and index_piece(board, piece_ind-2)[0]!='K':
second_board_2 = move(second_board, piece[0], piece_ind-2, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], piece_ind-2)]
# Move Rook
elif piece[0]=='R':
minim, maxim = min_max_rook(board)
for i in range(minim, maxim+1):
second_board = deepcopy(board)
if i!=piece_ind and index_piece(board, i)[0]!='K':
second_board_2 = move(second_board, piece[0], i, free=True)
if not check((second_board_2[0],(second_board_2[1]+1)%2)):
moves += [(piece[0], i)]
return moves
def move(board, piece, position, free=False):
if not free and (piece, position) not in available_moves(board):
print('It is impossible to move '+piece+' to',position)
raise # IMPOSSIBLE MOVE
elif not available_piece(board, piece+str(board[1])):
raise #PIECE NOT AVAILABLE
else:
n_pieces_old = len([i for i in range(len(board[0])) if pieceQ(board,i)])
old_position = piece_index(board, piece+str(board[1]))
board[0][old_position] = '--'
board[0][position] = piece+str(board[1])
board[1] = (board[1]+1)%2
n_pieces_new = len([i for i in range(len(board[0])) if pieceQ(board,i)])
if n_pieces_old==n_pieces_new:
board[2] += 1
return [board[0],board[1],board[2]+1]
else:
board[2] = 0
return [board[0],board[1],0]
# Returns True if board is in a check position for player board[1]
def check(board):
king_index = piece_index(board, 'K'+str(board[1]))
if king_index+2 <= 7 and index_piece(board, king_index+2) == 'N'+str((board[1]+1)%2):
return True
elif king_index-2 >= 0 and index_piece(board, king_index-2) == 'N'+str((board[1]+1)%2):
return True
else:
# Check with Rook
rook_index = piece_index(board,'R'+str((board[1]+1)%2))
if rook_index != -1:
if abs(king_index-rook_index)==1:
return True
found = False
for i in range(min(king_index, rook_index)+1, max(king_index, rook_index)):
found = found or (pieceQ(board, i))
if not found:
return True
# Check with king
king_index_2 = piece_index(board, 'K'+str((board[1]+1)%2))
if abs(king_index-king_index_2)==1:
return True
else:
return False
def stalemate(board):
return (not check(board) and len(available_moves(board))==0) or len([board[0][i] for i in range(len(board[0])) if pieceQ(board, i)])==2 or (len([x for x in board[0] if x[0] in ['K', 'N']])==3 and len([i for i in range(len(board[0])) if pieceQ(board,i)])==3) or board[2]==8
def checkmate(board):
return check(board) and len(available_moves(board))==0
def game_over(board):
return checkmate(board) or stalemate(board)
def evaluate_board(board):
if not board[1]:
# Defeat
if checkmate(board):
return -1
# Victory
elif checkmate([board[0], (board[1]+1)%2]):
return 1
else:
return 0
else:
# Defeat
if checkmate(board):
return 1
# Victory
elif checkmate([board[0], (board[1]+1)%2]):
return -1
else:
return 0
这是我在 Codecademy tic tac toe 算法中启发的 minimax 算法。在这里,我保证将死棋总会发生。
def minimax(input_board, is_maximizing, max_depth=8):
depth = max_depth-1
# Base case - the game is over, so we return the value of the board
if game_over(input_board):
return [evaluate_board(input_board), ('','')]
# The maximizing player
elif is_maximizing:
# The best value starts at the lowest possible value
best_value = -float("Inf")
best_move = ('','')
av_moves = available_moves(input_board)
if len(av_moves)==1:
return [best_value, av_moves[0]]
else:
for m in av_moves:
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
if checkmate(new_board):
return [best_value, m]
# Loop through all the available moves
for m in av_moves:
# Make a copy of the board and apply the move to it
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
# Recursively find your opponent's best move
if depth >= 0:
hypothetical_value = minimax(new_board, False, depth)[0]
else:
return [(best_value if best_move != ('','') else 0), (best_move if best_move != ('','') else m)]
# Update best value if you found a better hypothetical value
if hypothetical_value > best_value:
best_value = hypothetical_value
best_move = m
return [best_value, (best_move if best_move != ('','') else m)]
# The minimizing player
else:
# The best value starts at the highest possible value
best_value = float("Inf")
best_move = ('','')
av_moves = available_moves(input_board)
if len(av_moves)==1:
return [best_value, av_moves[0]]
else:
for m in av_moves:
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
if checkmate(new_board):
return [best_value, m]
# Testing all potential moves
for m in av_moves:
# Copying the board and making the move
new_board = deepcopy(input_board)
move(new_board, m[0], m[1])
# Passing the new board back to the maximizing player
if depth >= 0:
hypothetical_value = minimax(new_board, True, depth)[0]
else:
return [(best_value if best_move != ('','') else 0), (best_move if best_move != ('','') else m)]
# Keeping track of the best value seen so far
if hypothetical_value < best_value:
best_value = hypothetical_value
best_move = m
return [best_value, (best_move if best_move != ('','') else m)]
(我考虑了从 0 到 7 的方块的棋盘)
玩家 0 是第一个上场的玩家。问题是我可以作为玩家 0 击败算法,我的移动是 - N3,N5,R3,K1,N7 - 但我可以作为玩家 1 移动 - N4,K6,N2,K5。这是我作为玩家 1 绘制的游戏。
['K0', 'N0', 'R0', '--', '--', 'R1', 'N1', 'K1']
['K0', '--', 'R0', 'N0', '--', 'R1', 'N1', 'K1']
件,位置:n4 ['K0', '--', 'R0', 'N0', 'N1', 'R1', '--', 'K1']
['K0', '--', 'R0', '--', 'N1', 'N0', '- -', 'K1']
棋子,位置:k6 ['K0', '--', 'R0', '--', 'N1', 'N0', 'K1', ' --']
['--', 'K0', 'R0', '--', 'N1', 'N0', 'K1', '--']
件,位置:n2 ['--', 'K0', 'N1', '--', '--', 'N0', 'K1', '- -']
['--', '--', 'K0', '--', '--', 'N0', 'K1', '--']
我认为在我的 k6 之后它应该与车一起前进而不是与国王一起前进。
这样他最终可以平局而不是输球。 希望你能帮助我。
谢谢!
问题是我使用深度的方式不起作用。它应该在开头(在基本情况下)。我想问题已经解决了。