为什么我的极小极大算法没有做出完美的举动 - 一维国际象棋?

问题描述

我正在尝试开发一种极小极大算法来下一维国际象棋,我正在考虑以下因素:对齐的 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','--','R1','K1'],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_ind-1,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_ind+2,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_ind-2,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,i,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],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 算法中启发的极大极小算法。在这里,我保证将死之举总会发生。

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[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,'') 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,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[1])
                # Passing the new board back to the maximizing player
                if depth >= 0:
                    hypothetical_value = minimax(new_board,True,'') 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,'') else m)]

(我考虑了从 0 到 7 的方格)

玩家 0 是第一个玩的。问题是我可以用我的动作作为玩家 0 击败算法 - N3、N5、R3、K1、N7 - 但我可以像玩家 1 一样移动 - N4、K6、N2、K5。这是我作为玩家 1 绘制的游戏。

['K0','K1']

['K0','N0','K1']

件,位置:n4 ['K0','N1','K1']

件,位置:k6 ['K0','K1','--']

['--','K0','K1','--']

件,位置:n2 ['--','K0','--']>

我认为在我的 k6 之后,它应该与车一起前进,而不是与国王一起前进。

这样他就可以最终平局而不是输掉比赛。 希望你能帮助我。

谢谢!

解决方法

问题是我使用深度的方式不起作用。它应该在开头(在基本情况下)。我想问题已经解决了。