因此,我正在编写一个非常简单的TicTacToe程序,该程序使用alpha-beta修剪来搜索针对玩家的下一步行动,但在任何时候我想运行它时都会遇到问题。我尝试过任何想解决它的方法,甚至制作了一个Java逐行等效的逻辑,该逻辑运行完美,但python逻辑不起作用。
这是我的代码:
#encoding: UTF-8
#Andres de Lago Gomez
#A01371779
from random import randint
from utils import *
def getEnemy(who):
return 1 if who==2 else 2
def 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循环来做同样的事情