【问题标题】:Trouble with minimax algorithm in tic tac toe game with adjustable game size可调节游戏大小的井字游戏中的极小极大算法存在问题
【发布时间】:2021-11-12 00:20:53
【问题描述】:

我正在尝试创建一个具有可调节游戏大小的井字游戏和一台使用 minimax 算法的计算机。游戏大小只能是奇数,以确保对角线获胜总是可能的。游戏运行没有错误,但我知道极小极大算法不能 100% 正确运行,因为我仍然可以击败计算机。我已经广泛查看了我的代码,但找不到算法出错的地方。这是我的代码:

Main.py

import TicTacToe
import Minimax

if (__name__ == "__main__"):
    t = TicTacToe.ttt(3)
    m = Minimax.Minimax(3, t)
    
    while (t.winner == None):
        if (t.turn == 1):
            playerInputI = int(input("Input row: "))
            playerInputJ = int(input("Input column: "))
            bestIndex = (playerInputI, playerInputJ)
        else:
            winner, bestIndex = m.minimax(t.grid, (-1, -1), 15, -1)
            t.winner = None
            t.findWinner(bestIndex, t.grid)
            

        t.updateGameGrid(bestIndex)
        print(t.grid)

    print(t.grid)

Minimax.py

class Minimax:
    def __init__(self, gs, t):
        self.gridSize = gs
        self.ttt = t

    def minimax(self, state, currIndex, depth, turn):
        if (currIndex[0] != -1 and currIndex[1] != -1):
            winner = self.ttt.findWinner(currIndex, state)

            if (winner == -1):
                return winner - depth, currIndex
            elif (winner == -1):
                return winner + depth, currIndex
            elif (winner == 0):
                return 0, currIndex

            if (depth==0 and winner==None):
                return 0, currIndex
        
        evalLimit = -turn * 1000
        bestIndex = None
        for i in range(self.gridSize):
            for j in range(self.gridSize):
                if (state[i][j] == 0):
                    state[i][j] = turn

                    eval, newIndex = self.minimax(state, (i, j), depth-1, -turn)
                    state[i][j] = 0
                    if (turn > 0 and eval > evalLimit):
                        bestIndex = newIndex
                        evalLimit = eval
                    elif (turn < 0 and eval < evalLimit):
                        bestIndex = newIndex
                        evalLimit = eval
        
        return evalLimit, bestIndex

        

Tictactoe.py

from random import randint

class ttt:
    def __init__(self, size):
        self.gridSize = size
        self.grid = self.createGrid()

        # If using minimax algorithm, user is maximizer(1) and computer is minimizer(-1)
        # If single player, then user is 1, computer is -1
        # If multiplayer, user1 is 1, user2 = -1
        self.turn = 1
        self.winner = None

    def createGrid(self):
        grid = []
        for i in range(self.gridSize):
            grid.append([])
            for j in range(self.gridSize):
                grid[i].append(0)


        # grid = [[-1, 1, 0], [0, -1, 0], [0, 0, 0]]

        return grid

    def updateGameGrid(self, index):
        if (self.grid[index[0]][index[1]] != 0):
            return

        self.grid[index[0]][index[1]] = self.turn
        winner = self.findWinner(index, self.grid)  

        self.turn = -self.turn
        
    def randomIndex(self):
        x = randint(0, self.gridSize-1)
        y = randint(0, self.gridSize-1)
        while (self.grid[x][y] != 0):
            x = randint(0, self.gridSize-1)
            y = randint(0, self.gridSize-1)
        return (x, y)

    def findWinner(self, index, grid):
        # Row
        found = True
        for j in range(self.gridSize-1):
            if (grid[index[0]][j] != grid[index[0]][j+1] or grid[index[0]][j] == 0):
                found = False
                break
        if (found):
            self.winner = self.turn
            return self.turn
        
        # Column
        found = True
        for i in range(self.gridSize-1):
            if (grid[i][index[1]] != grid[i+1][index[1]] or grid[i][index[1]] == 0):
                found = False
                break
        if (found):
            self.winner = self.turn
            return self.turn
        
        # Top Left to Bottom Right Diagonal
        if (index[0] == index[1]):
            found = True
            for i in range(self.gridSize-1):
                if (grid[i][i] != grid[i+1][i+1] or grid[i][i] == 0):
                    found = False
                    break
            if (found):
                self.winner = self.turn
                return self.turn

        # Top Right to Bottom Left Diagonal
        if (index[0] + index[1] == self.gridSize-1):
            found = True
            for i in range(self.gridSize-1):
                if (grid[self.gridSize-i-1][i] != grid[self.gridSize-i-2][i+1] or grid[self.gridSize-i-1][i] == 0):
                    found = False
                    break
            if (found):
                self.winner = self.turn
                return self.turn
            
        
        tie = True
        for i in range(self.gridSize):
            for j in range(self.gridSize):
                if (grid[i][j] == 0):
                    tie = False
        
        if (tie):
            self.winner = 0
            return 0

        return None
        

网格表示为 2d 数组,每个元素为 -1 表示 O,1 表示 X,0 表示无。播放器为 1,计算机为 -1。轮到谁用 -1 或 1 表示,对应于 O 或 X。如果有人能够找到我的代码中的错误所在,那就太好了。

【问题讨论】:

  • 我认为您的 Minimax.py 代码丢失了。

标签: python minimax


【解决方案1】:

我看到了两个问题:

a) 以下两个条件在极小极大中是一样的

    if (winner == -1):
       return winner - depth, currIndex
    elif (winner == -1):
       return winner + depth, currIndex

b) 当您返回bestIndex 时,您实际上返回了获胜的移动,即在博弈树的一个叶子上完成一条线或一行或一条对角线的移动。你真正想要的是下一个动作。在条件if eval &gt; evalLimit 中改写bestIndex = (i, j)

我没有检查所有内容,但这是一个好的开始。在 depth=1 或 2 处运行您的代码,并在 minimax 函数中使用许多 printf,并查看不同的动作以及相应的分数,看看它们是否正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-09
    • 1970-01-01
    相关资源
    最近更新 更多