井字游戏Alpha-Beta剪枝运行时错误:Python中最大递归深度超出,结合Pygame

所以,我正在编写一个非常简单的井字游戏程序,使用Alpha-Beta剪枝来搜索对抗玩家的下一步,但每次我想运行它时都会遇到问题。我尝试了所有能想到的方法来解决它,甚至还制作了一个Java版本的逐行等效逻辑,运行得非常完美,但Python版本就是不工作。

这是我的代码:

#encoding: UTF-8#Andres de Lago Gomez#A01371779from random import randintfrom utils import *def getEnemy(who):    return 1 if who==2 else 2def getLetter(who):    return "X" if who==1 else "O"class TicTacToe:    winningCombos =[[0, 1, 2], [3, 4, 5],                    [6, 7, 8], [0, 3, 6],                    [1, 4, 7], [2, 5, 8],                    [0, 4, 8], [2, 4, 6]]    board = [0 for i in range(9)]    player = 1    cpu = 2    def __init__(self):        pass    def makeMove(self, who, pos):        self.board[pos] = who    def setCpu(self, who):        self.player = who        self.cpu = getEnemy(who)    def availableMoves(self):        return [i for i in range(9) if self.board[i]==0]    def isOver(self):        if 0 not in self.board:            return True        if self.Winner():            return True        return False    def Winner(self):        for i in [1,2]:            positions = self.getSquares(i)            for combo in self.winningCombos:                win = True                for pos in combo:                    if pos not in positions:                        win = False                if win:                    return i        return False    def getSquares(self, player):        return [i for i in range(9) if self.board[i]==player]    def alphaBeta(self, player, alpha, beta):        if self.isOver():            return self.evaluateNode()        for move in self.availableMoves():            self.makeMove(move, player)            value = self.alphaBeta(getEnemy(player),alpha,beta)            self.makeMove(move, 0)            if player == self.cpu:                if alpha < value:                    alpha = value                if alpha >=beta:                    return beta            else:                if beta > value:                    beta = value                if beta <= alpha:                    return alpha        return alpha if player==self.cpu else beta    def evaluateNode(self):        tmp = self.Winner()        if tmp==self.cpu:            return 1        elif tmp==self.player:            return -1        else:            return 0    def getNextMove(self, player):        test = -5        possibleMoves = []        for move in self.availableMoves():            self.makeMove(player, move)            value = self.alphaBeta(getEnemy(player), -5, 5)            self.makeMove(0, move)            if value>test:                test = value                possibleMoves = [move]            elif value == test:                possibleMoves.append(move)        return possibleMoves[randint(0, len(possibleMoves)-1)]class Tile(pygame.sprite.Sprite):    def __init__(self, rect, screen, player="X"):        pygame.sprite.Sprite.__init__(self)        self.rect = rect        self.images = [load_png(get_path()+"\\data\\TicTacToe\\"+player+"Tile\\{0:0>2d}.png".format(x)) for x in range(21)]        clock = pygame.time.Clock()        for i in range(21):            self.image = self.images[i]            screen.blit(self.image, self.rect)            pygame.display.update(self.rect)            clock.tick(80)class GUI:    def __init__(self):        pygame.init()        self.screen = pygame.display.set_mode([100,100])        self.dir = get_path()        #get background        self.background = pygame.image.load(self.dir+"\\data\\TicTacToe\\Background.png")        self.background.convert()        self.tiles = pygame.sprite.Group()        #blit to screen        self.screen = pygame.display.set_mode(self.background.get_size())        self.screen.blit(self.background,(0,0))        pygame.display.update()        #create tiles        self.places = [pygame.Rect((15+165*x, 110+165*y), (150,150) )for x in range(3) for y in range (3)]        #create game        self.board = TicTacToe()        done = False        goFirstI = load_png(get_path()+"\\data\\TicTacToe\\GoFirst.png")        goFirstR = pygame.Rect((0,0), (400,200))        goFirstR.center = self.places[4].center        self.screen.blit(goFirstI,goFirstR)        pygame.display.update(goFirstR)        yesR = pygame.Rect((97,382),(115,45))        noR = pygame.Rect((297,382),(115,45))        while not done:            for event in pygame.event.get():                if event.type == pygame.MOUSEBUTTONUP:                    if event.button == 1:                        if yesR.collidepoint(event.pos):                            done = True                            self.board.setCpu(1)                        elif noR.collidepoint(event.pos):                            done = True                            self.board.setCpu(2)        self.screen.blit(self.background,(0,0))        pygame.display.update(goFirstR)        #start clock        clock = pygame.time.Clock()        done = False        turn = 1        bdown = 0        while not done:            for event in pygame.event.get():                if event.type == pygame.QUIT:                    done = True                elif event.type == pygame.KEYDOWN:                    if event.key == pygame.K_ESCAPE:                        pass    #pause menu?                elif event.type == pygame.MOUSEBUTTONUP:                    if event.button == 1:                        bdown = event            if turn == self.board.player:                if bdown != 0:                    index = 0                    for rect in self.places:                        if rect.collidepoint(bdown.pos):                            moves = self.board.availableMoves()                            if index in moves:                                self.board.makeMove(turn, index)                                self.tiles.add(Tile(rect, self.screen, getLetter(self.board.player)))                                turn = getEnemy(turn)                        index += 1            else:                pos = self.board.getNextMove(self.board.cpu)                self.board.makeMove(turn, pos)                self.tiles.add(Tile(self.tiles[pos], self.screen, getLetter(self.board.cpu)))            clock.tick(60)a = GUI()

我得到的错误是: RuntimeError: maximum recursion depth exceeded

我非常希望能了解是什么导致了这个错误。


回答:

Python和Java处理递归的方式不同。Python的堆栈框架较大,因此对递归次数有严格的限制,即你的代码可以调用自身的次数,在崩溃并抛出该错误之前。在你的代码中,这是你的 def alphaBeta(self, player, alpha, beta) 方法,它本身调用了: value = self.alphaBeta(getEnemy(player),alpha,beta)

在Java中,情况略有不同,因为Java进行了更多的优化。这意味着在得到Java堆栈溢出错误之前,你可以有更多的递归调用。

你最好的选择是将你的代码从递归函数改为迭代函数。即,修改你的alphaBeta方法,使其不调用自身,而是使用for或while循环来完成相同的事情

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注