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
相关产品推荐
相关产品推荐

