井字游戏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

使用LSTM在Python中预测未来值

这段代码可以预测指定股票的当前日期之前的值,但不能预测…

如何在gensim的word2vec模型中查找双词组的相似性

我有一个word2vec模型,假设我使用的是googl…

dask_xgboost.predict 可以工作但无法显示 – 数据必须是一维的

我试图使用 XGBoost 创建模型。 看起来我成功地…

ML Tuning – Cross Validation in Spark

我在https://spark.apache.org/…

如何在React JS中使用fetch从REST API获取预测

我正在开发一个应用程序,其中Flask REST AP…

如何分析ML.NET中多类分类预测得分数组?

我在ML.NET中创建了一个多类分类项目。该项目可以对…

发表回复

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