You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Minimax算法井字棋游戏报错:NoneType is not subscriptable

井字棋Minimax算法报错:NoneType is not subscriptable

开发了一款采用Minimax(极小化极大)算法的井字棋游戏,Tkinter界面及人类玩家操作功能正常,但轮到电脑玩家行动时,程序抛出错误:NoneType is not subscriptable。

主程序代码

from tkinter import *
import customtkinter
import random
import minimax

customtkinter.set_appearance_mode("Dark")
# 创建CTk应用窗口
root = customtkinter.CTk()

# 设置窗口宽高
root.geometry('500x300')


# 创建标题标签
label = customtkinter.CTkLabel(master=root,
                               text="Tic Tac Toe",
                               width=120,
                               height=50,
                               font=("normal", 20),
                               corner_radius=8)
label.place(relx=0.25, rely=0.8, anchor=CENTER)

# 处理点击事件
DEPTH=8
def clickbutton(r, c):
    buttons[r][c]["text"]="X"
    board[r][c]="X"
    buttons[r][c]['state']=DISABLED

    label = customtkinter.CTkLabel(master=root,
                               text=checkwin(board),
                               width=120,
                               height=25,
                               corner_radius=8)
    label.place(relx=0.25, rely=0.9, anchor=CENTER)


    computerplay()
    DEPTH=DEPTH-1
    

# 按钮矩阵
buttons = [
     [0,0,0],
     [0,0,0],
     [0,0,0]]
 
# 棋盘状态矩阵(记录按钮是否已被点击)
board=[[0,0,0],[0,0,0],[0,0,0]]
 
for i in range(3):
    for j in range(3):                                  
        buttons[i][j] = Button(height = 3, width = 6, font = ("Normal", 20),
                        command = lambda r = i, c = j : clickbutton(r,c))
        buttons[i][j].grid(row = i, column = j)



def computerplay():
    bestmove=minimax.minimax(board, DEPTH, 1)
    buttons[bestmove[0]][bestmove[1]]['text']="O"
    buttons[bestmove[0]][bestmove[1]]['state']=DISABLED
    board[bestmove[0]][bestmove[1]]="O"

def checkwin(b):
    score=minimax.evaluate(b)
    if score==10:
        return 'Computer won!'
    elif score==-10:
        return 'You won!'
    else:
        return 'Player vs. Computer'
    

root.mainloop()

minimax模块代码

import math

def change_board(board):
    # 将棋盘转换为-1(X)、0(空)、1(O)的格式
    new_board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]

    for i in range(3):
        for j in range(3):
            if board[i][j]=='X':
                new_board[i][j]==-1
            elif board[i][j]=='O':
                new_board[i][j]==1

    return new_board

def empty_cells(board):
    cells=[]
    for i in range(3):
        for j in range(3):
            if board[i][j]==0:
                cells.append([i, j])
                
    return False

def game_over(board):
    # 通过evaluate判断是否有胜负
    if evaluate(board)==10 or evaluate(board)==-10:
        return True
    
    # 判断棋盘是否已满
    if (not empty_cells(board)):
        return True

    return False
    

def evaluate(board):
    # 判断得分
    if board[0][0]==board[1][1] and board[1][1]==board[2][2]:
        if board[0][0]==-1:
            return -10
        elif board[0][0]==1:
            return 10
    
    if board[0][2]==board[1][1] and board[1][1]==board[2][0]:
        if board[0][2]==-1:
            return -10
        elif board[0][2]==1:
            return 10
    
    for row in range(3):
        if board[row][0]==board[row][1] and board[row][1]==board[row][2]:
            if board[row][0]==-1:
                return -10
            elif board[row][0]==1:
                return 10

    for col in range(3):
        if board[0][col]==board[1][col] and board[1][col]==board[2][col]:
            if board[0][col]==-1:
                return -10
            elif board[0][col]==1:
                return 10
    



def minimax(board, depth, player):
    if player==1:
        # 1代表电脑玩家,-1代表人类玩家
        best=[-1, -1, -math.inf]
    else:
        best=[-1, -1, math.inf]

    if depth==0 or game_over(board):
        score=evaluate(board)
        return score

    # 遍历所有有效移动并计算得分
    for cell in empty_cells(board):
        x, y = cell[0], cell[1]
        board[x][y] = player
        score = minimax(board, depth - 1, -player)
        board[x][y] = 0
        score[0], score[1] = x, y

        if player == 1:
            if score[2] > best[2]:
                best = score
        else:
            if score[2] < best[2]:
                best = score

    return best

错误原因及修复方案

1. empty_cells函数返回值错误

原函数最后返回False,导致遍历空单元格的循环无法执行,Minimax算法无法找到有效移动。修复为返回收集到的空单元格列表:

def empty_cells(board):
    cells=[]
    for i in range(3):
        for j in range(3):
            if board[i][j]==0:
                cells.append([i, j])
    return cells  # 替换原return False

2. evaluate函数缺少默认返回值

当没有胜负时,函数未返回任何值,默认返回None,导致递归时无法对None进行下标访问。添加默认返回值0:

def evaluate(board):
    # 保留原有判断逻辑
    # ...
    # 添加默认返回值
    return 0

3. change_board函数赋值错误且未被调用

  • 函数内使用==进行赋值,改为=:
def change_board(board):
    new_board = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    for i in range(3):
        for j in range(3):
            if board[i][j]=='X':
                new_board[i][j] = -1  # 替换==为=
            elif board[i][j]=='O':
                new_board[i][j] = 1  # 替换==为=
    return new_board
  • 在computerplay中调用该函数,将X/O格式的棋盘转换为Minimax算法需要的-1/1/0格式:
def computerplay():
    converted_board = minimax.change_board(board)
    bestmove = minimax.minimax(converted_board, DEPTH, 1)
    buttons[bestmove[0]][bestmove[1]]['text']="O"
    buttons[bestmove[0]][bestmove[1]]['state']=DISABLED
    board[bestmove[0]][bestmove[1]]="O"

4. 全局变量DEPTH修改错误

在clickbutton中修改全局变量需声明global,否则会被当作局部变量处理:

def clickbutton(r, c):
    global DEPTH  # 添加该行
    buttons[r][c]["text"]="X"
    board[r][c]="X"
    buttons[r][c]['state']=DISABLED
    # 保留后续逻辑

5. Minimax函数递归返回值不统一

终止条件返回的是单独的分数值,而上层函数期望的是包含坐标和分数的列表,导致递归时无法下标访问。修改终止条件的返回值:

def minimax(board, depth, player):
    # 保留原有初始化逻辑
    if depth==0 or game_over(board):
        score=evaluate(board)
        return [-1, -1, score]  # 返回列表而非单独数值
    # 保留后续逻辑

内容的提问来源于stack exchange,提问作者Blythe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 22:15:36