python-3.x 井字游戏中的极小极大算法不起作用

y0u0uwnf  于 2023-08-08  发布在  Python
关注(0)|答案(1)|浏览(83)

我最近了解了minimax,我正在努力制作一个无与伦比的AI井字游戏。我不知道为什么我的极小极大函数不起作用,我的电脑有时发挥非最佳行动。
这是我的完整代码:

from random import randint
import os

def play_again():
    print()
    t=True
    while t:
        p=input("Do you want to play again? Y or N  ").upper()
        if p=='Y' or p=='YES':
            t=False
            return True
        elif p=='N' or p=='NO':
            t=False
            print("Thank You!!")
            return False
        else:
            print('Enter a valid input!')
            
    
        
while True:

    board1=['1','2','3','4','5','6','7','8','9']
    print('    |   |')
    print(' ',board1[0],'|',board1[1],'|',board1[2])
    print('____|___|____')
    print('    |   |')
    print(' ',board1[3],'|',board1[4],'|',board1[5])
    print('____|___|____')
    print('    |   |')
    print(' ',board1[6],'|',board1[7],'|',board1[8])
    print('    |   |')

    
    board=[' ',' ',' ',' ',' ',' ',' ',' ',' ']
    def print_board():
        
        print('    |   |')
        print(' ',board[0],'|',board[1],'|',board[2])
        print('____|___|____')
        print('    |   |')
        print(' ',board[3],'|',board[4],'|',board[5])
        print('____|___|____')
        print('    |   |')
        print(' ',board[6],'|',board[7],'|',board[8])
        print('    |   |')

    if randint(0,1)==0:
        player='Player 1'
    else:
        player='Player 2'

    a='a'
    while a not in ['X','O']:
        a=input("Player 1: Do you want to be X or O: ").upper()
            
        if a not in ['X','O']:
            print("Enter valid output X or O")

    if a=='X':
        c='O'
    else:
        c='X'

    def first():
        if player=='Player 1':
            print()
            print('Player 1 will go first')
            
        else:
            print()
            print('Player 2 will go first')
            
    first()

    def position_check():
        return board[b-1] not in ['X','O']

    def board_full():
        for i in board:
            if i not in ['X','O']:
                return True
        return False

    def win_check(m):
        return ((board[0]==m and board[1]==m and board[2]==m) or
                (board[3]==m and board[4]==m and board[5]==m) or
                (board[6]==m and board[7]==m and board[8]==m) or
                (board[0]==m and board[3]==m and board[6]==m) or
                (board[1]==m and board[4]==m and board[7]==m) or
                (board[2]==m and board[5]==m and board[8]==m) or
                (board[0]==m and board[4]==m and board[8]==m) or
                (board[2]==m and board[4]==m and board[6]==m))

    def minimax(board,depth,ismax):
        
        if win_check(c):
            return 1

        elif win_check(a):
            return -1

        elif not board_full:
            return 0

        if ismax:
            bestscore = -1000

            for i in range(len(board)):
                
                if board[i]==' ':
                    board[i]=c
                    score= minimax(board,depth+1,False)
                    
                    board[i]=' '

                    if score > bestscore:
                        bestscore = score

            return bestscore

        else:
            bestscore = 1000

            for i in range(len(board)):
                if board[i]==' ':
                    
                    board[i]=a

                    score= minimax(board,depth+1,True)
                    
                    board[i]=' '

                    if score < bestscore:
                        bestscore = score

            return bestscore
            
        
    while board_full():
        
        if player=='Player 1':
            b='a'
            within_range=False
            while b.isdigit()==False or within_range==False:
                b=input("Enter your next move (1-9) :")

                if b.isdigit()==False:
                    print('\n'*100)
                    print('Enter a choice between 1-9')

                if b.isdigit()==True:
                    if int(b) in range(1,10):
                        within_range=True
                    else:
                        print('Enter a choice between 1-9')

            b=int(b)

            if position_check():
                board[b-1]=a
                print_board()
                if win_check(a):
                    print('Congratulations Player 1 wins!!')
                    break
                else:
                    player='Player 2'

            else:
                print('Position already occupied')

        if player=='Player 2':

            bestscore = -1000

            for i in range(len(board)):
                if board[i]==' ':
                    board[i]=c

                    score= minimax(board,0,False)
                    
                    board[i]=' '

                    if score > bestscore:
                        bestscore = score
                        bestmove=i
                        b=bestmove

            if position_check:
                
                board[b]=c
                
                print_board()
                
                if win_check(c):
                    print('Congratulations Player 2 wins!!')
                    break
                else:
                    player='Player 1'
                    
                

    else:
        print('Its a DRAW!!')

    if not play_again():
        break

字符串
当我玩位置1时,comp应该玩位置5,但它没有,但它总是玩位置2,最终失去了我的代码中的错误在哪里我刚刚学习了minimax,我不想使用深度概念:

|   |
  1 | 2 | 3
____|___|____
    |   |
  4 | 5 | 6
____|___|____
    |   |
  7 | 8 | 9
    |   |
Player 1: Do you want to be X or O: x

Player 1 will go first
Enter your next move (1-9) :1
    |   |
  X |   |  
____|___|____
    |   |
    |   |  
____|___|____
    |   |
    |   |  
    |   |
    |   |
  X | O |  
____|___|____
    |   |
    |   |  
____|___|____
    |   |
    |   |  
    |   |

rur96b6h

rur96b6h1#

存在以下几个问题:

  • minimax这个语句中:
elif not board_full:

字符串
这个条件永远不会满足,因为您评估的是函式对象,而不是 * 呼叫 * 函式的结果。
这应该是:

elif not board_full():


我应该说这个函数的名称是误导性的。当棋盘满时,board_full返回True(真),尽管它的名称是空的。你最好换个说法,比如:board_has_moves的值。

  • 在主循环的后半部分也有类似的问题,其中有:
if position_check:


这个条件总是成立的,即使当游戏结束,所以计算机得到发挥他们的最后一个迭代的举动(即。9)--用无效移动覆盖该单元。
它应该有括号。

  • 函数position_check显然期望b的值是从1开始的,因为它与b-1一起工作,但是计算机移动被存储在b中作为从0开始的值。因此position_check将无法与之正常工作。我建议您始终使用从0开始的b值,并调整position_check以使用b,而不是b-1。人类玩家的走法可以通过b=int(b) - 1来正确设置
  • 如果人类玩家已经走完了最后一步,那么仍然会进入第二个if区块 ,而不会首先检查游戏是否结束!.如果已经实现了上述所有修复程序,这仍然可以正常工作,但最好将if player=='Player 2':语句设置为else:语句。这样,主循环将只执行两个块中的一个,而不会在同一个迭代中同时执行两个块。

不成问题,但是:

  • 选个好名字。像abc这样的名称是没有意义的,并且会使代码更难阅读。如果您将它们命名为player_1_symbolmoveplayer_2_symbol,则会更清楚
  • play_again中,不需要名称t。就做一个while True:
  • 令人不安的是,您在循环体中定义了函数!不要这样做。将它们移到循环之外。这意味着,对于position_check和其他函数,应该将一些值作为函数参数传递--无论如何,这都是一种很好的做法。
  • 我将把move-loop放在一个单独的函数中,该函数可以有本地函数:实际上,我只会将minimax定义为局部函数,因此,对于这个递归函数,参数的数量可以保持很小。
  • 避免使用全局变量,也可以将主逻辑放在一个函数中,如main()。这会使全局名称变为本地名称,并强制您传递参数--这是一个很好的实践。

当然还有很多需要改进的地方,但是上面的更改(以及其他一些更改)导致了您的代码的以下版本:

from random import randint

def play_again():
    print()
    while True:
        p=input("Do you want to play again? Y or N  ").upper()
        if p=='Y' or p=='YES':
            return True
        elif p=='N' or p=='NO':
            print("Thank You!!")
            return False
        else:
            print('Enter a valid input!')

def print_board(board):  # parameter list
    print('    |   |')
    print(' ',board[0],'|',board[1],'|',board[2])
    print('____|___|____')
    print('    |   |')
    print(' ',board[3],'|',board[4],'|',board[5])
    print('____|___|____')
    print('    |   |')
    print(' ',board[6],'|',board[7],'|',board[8])
    print('    |   |')

def first(player):  # argument list
    print()
    if player=='Player 1':
        print('Player 1 will go first')
    else:
        print('Player 2 will go first')
        
def position_check(board, move):
    return board[move] not in ['X','O']

def board_has_moves(board):
    for i in board:
        if i not in ['X','O']:
            return True
    return False

def win_check(board, m):
    return ((board[0]==m and board[1]==m and board[2]==m) or
            (board[3]==m and board[4]==m and board[5]==m) or
            (board[6]==m and board[7]==m and board[8]==m) or
            (board[0]==m and board[3]==m and board[6]==m) or
            (board[1]==m and board[4]==m and board[7]==m) or
            (board[2]==m and board[5]==m and board[8]==m) or
            (board[0]==m and board[4]==m and board[8]==m) or
            (board[2]==m and board[4]==m and board[6]==m))

# A function to deal with one game
def playgame(board, player, player_1_symbol, player_2_symbol):
    def minimax(depth, ismax):  # removed board parameter, as already in scope
        if win_check(board, player_2_symbol):  # pass board also
            return 1
        elif win_check(board, player_1_symbol):
            return -1
        elif not board_has_moves(board):  # call it, rename it
            return 0
        if ismax:
            bestscore = -1000
            for i in range(len(board)):
                if board[i]==' ':
                    board[i]=player_2_symbol
                    score= minimax(depth+1,False)
                    board[i]=' '
                    if score > bestscore:
                        bestscore = score
            return bestscore
        else:
            bestscore = 1000
            for i in range(len(board)):
                if board[i]==' ':
                    board[i]=player_1_symbol
                    score= minimax(depth+1,True)
                    board[i]=' '
                    if score < bestscore:
                        bestscore = score
            return bestscore
    
    while board_has_moves(board):  # better name; pass argument
        if player=='Player 1':
            move='a'  # better name
            within_range=False
            while not move.isdigit() or not within_range:
                move=input("Enter your next move (1-9) :")
                if not move.isdigit():
                    print('\n'*100)
                    print('Enter a choice between 1-9')
                if move.isdigit():
                    if int(move) in range(1,10):
                        within_range=True
                    else:
                        print('Enter a choice between 1-9')
            move=int(move)-1  # reduce to make it 0-based
            if position_check(board, move):  # pass the arguments
                board[move]=player_1_symbol   # b is zero based now
                print_board(board)  # pass argument
                if win_check(board, player_1_symbol):  # pass arguments
                    print('Congratulations Player 1 wins!!')
                    break
                else:
                    player='Player 2'
            else:
                print('Position already occupied')
        else:  # changed to avoid code falling thru from the previous block
            bestscore = -1000
            bestmove = 10  # better initialise before loop
            for i in range(len(board)):
                if board[i]==' ':
                    board[i]=player_2_symbol
                    score= minimax(0,False)
                    board[i]=' '
                    if score > bestscore:
                        bestscore = score
                        bestmove=i
            if position_check(board, bestmove):  # add the parentheses to call it
                board[bestmove]=player_2_symbol
                print_board(board)  # pass argument
                if win_check(board, player_2_symbol):
                    print('Congratulations Player 2 wins!!')
                    break
                else:
                    player='Player 1'
    else:
        print('Its a DRAW!!')

# Main program
def main():  # avoid global variables, and put main logic in a function
    while True:
        board1=['1','2','3','4','5','6','7','8','9']
        print('    |   |')
        print(' ',board1[0],'|',board1[1],'|',board1[2])
        print('____|___|____')
        print('    |   |')
        print(' ',board1[3],'|',board1[4],'|',board1[5])
        print('____|___|____')
        print('    |   |')
        print(' ',board1[6],'|',board1[7],'|',board1[8])
        print('    |   |')
        board=[' ',' ',' ',' ',' ',' ',' ',' ',' ']
    
        # simplified:
        player = ('Player 1', 'Player 2')[randint(0,1)]
        player_1_symbol ='a'  # better name
        while player_1_symbol not in ['X','O']:
            player_1_symbol=input("Player 1: Do you want to be X or O: ").upper()
            if player_1_symbol not in ['X','O']:
                print("Enter valid output X or O")
        # use ternary operator, and use better name
        player_2_symbol = 'O' if player_1_symbol=='X' else 'X'
        first(player)  # pass argument
        # move the move-loop logic into another function:
        playgame(board, player, player_1_symbol, player_2_symbol)
        if not play_again():
            break
    
main()

相关问题