四子棋中等难度CPU代码出现TypeError:int与NoneType无法比较
我开发的四子棋代码中,drop_piece函数用于检查列是否已满,其他辅助函数负责检测获胜条件,cpu_player_easy实现随机落子,draw_checker检测平局。运行测试用例时持续报错:TypeError: '<=' not supported between instances of 'int' and 'NoneType',代码如下:
import random def drop_piece(board, player, column): #(start, stop, end) for row in range(5, -1, -1): #iterates and starts at 5 and makes it's way up the row by taking away 1 till it gets to the top and which would have a -1 if board[row][column - 1] == 0: #makes sure that the column directly below does not have a token on it board[row][column - 1] = player return True else: return False def cpu_player_easy(board, player): while True: column = random.randint(1,7) if drop_piece(board, player, column): ## calls on this function and says if that's true then return the columns return column def vertical_Win(): for row in range(0,3): for column in range(0,7): if board[row][column] == board[row + 1][column] == board[row + 2][column] == board[row + 3][column] and board[row][column] != 0: if board[row][column] == 1: return column def horizontal_Win(): for row in range(6): for column in range(1, 4): if board[row][column] == board[row][column + 1] == board[row][column + 2] == board[row][column + 3] and board[row][column] != 0: if board[row][column] == 1: return column else: return None def diagonal_Win_TL_To_BR(): for row in range(3): for column in range(1 , 4): if board[row][column - 1] == board[row + 1][column - 0] == board[row + 2][column + 1] == board[row + 3][column + 2] and board[row][column - 1] != 0: if board[row][column - 1] == 1: return column else: return None def diagonal_Win_Tr_To_BL(): for row in range(0,3): ## from top to bottom for column in range(3, 7): ## from left to right if board[row][column] == board[row + 1][column - 1] == board[row + 2][column - 2] == board[row + 3][column - 3] and board[row][column] != 0: if board[row][column] == 1: return column else: return None def draw_checker(board): for row in range(0,6): for column in range(0,7): if board[row][column] == 0: return None def create_board(): number_of_rows = 6 number_of_columns = 7 arr_2d =[] ##this is the 2d array which we will store the zeroes in. for x in range(number_of_rows):## responsible for the rows column_elements = [] ## empty list that will hold the elements of the current row for y in range(number_of_columns):## responsible for the columns column_elements.append(0) arr_2d.append(column_elements)## appends the column_elements list to the "arr_2d" list representing a new row in the 2d array return arr_2d def cpu_player_medium(board, player): """ Executes a move for the CPU on medium difficulty. It first checks for an immediate win and plays that move if possible. If no immediate win is possible, it checks for an immediate win for the opponent and blocks that move. If neither of these are possible, it plays a random move. :param board: The game board, 2D list of 6x7 dimensions. :param player: The player whose turn it is, integer value of 1 or 2. :return: Column that the piece was dropped into, int. """ while draw_checker(board) == False: if vertical_Win() or horizontal_Win() or diagonal_Win_TL_To_BR() or diagonal_Win_Tr_To_BL(): return column else: cpu_player_easy(board, player)
错误根源分析
获胜检测函数未接收board参数
所有vertical_Win、horizontal_Win等函数都未将board作为参数传入,而是依赖全局变量。如果测试环境中没有定义全局board,或者变量未正确赋值,会导致函数内部的board为None,后续数组索引和值比较操作就会触发类型错误。draw_checker返回逻辑错误
该函数找到空位时返回None,全满时无明确返回值(默认返回None)。但cpu_player_medium中用draw_checker(board) == False判断,None == False结果为False,导致循环逻辑失效,后续代码处理None值时引发错误。cpu_player_medium函数逻辑漏洞
- 调用获胜检测函数时未传入
board参数; - 直接返回未定义的
column变量,会引发NameError; - 调用
cpu_player_easy后未返回其结果,导致函数可能返回None,后续若将该返回值与整数比较就会触发TypeError。
- 调用获胜检测函数时未传入
获胜检测函数返回值不一致
部分函数在非玩家1获胜时返回None,无获胜情况时也默认返回None,导致后续判断时拿到None值,与整数比较时触发类型错误。
修复方案
1. 修正获胜检测函数,传入board参数并统一返回逻辑
将所有获胜检测函数添加board参数,统一无获胜时返回None,获胜时返回用户视角的列号(1-7):
def vertical_Win(board): for row in range(0,3): for column in range(0,7): if board[row][column] == board[row + 1][column] == board[row + 2][column] == board[row + 3][column] and board[row][column] != 0: return column + 1 # 转换为1-7的列号 return None def horizontal_Win(board): for row in range(6): for column in range(0, 4): # 修正列范围,避免索引越界 if board[row][column] == board[row][column + 1] == board[row][column + 2] == board[row][column + 3] and board[row][column] != 0: return column + 1 return None def diagonal_Win_TL_To_BR(board): for row in range(3): for column in range(0, 4): if board[row][column] == board[row + 1][column + 1] == board[row + 2][column + 2] == board[row + 3][column + 3] and board[row][column] != 0: return column + 1 return None def diagonal_Win_Tr_To_BL(board): for row in range(3): for column in range(3, 7): if board[row][column] == board[row + 1][column - 1] == board[row + 2][column - 2] == board[row + 3][column - 3] and board[row][column] != 0: return column + 1 return None
2. 修复draw_checker的返回逻辑
明确返回布尔值,True表示平局,False表示还有空位:
def draw_checker(board): for row in range(6): for column in range(7): if board[row][column] == 0: return False # 存在空位,不是平局 return True # 棋盘全满,平局
3. 重构cpu_player_medium函数逻辑
实现“先找自己的获胜点,再堵对手的获胜点,最后随机落子”的逻辑,同时修复参数传递和返回值问题:
def cpu_player_medium(board, player): opponent = 2 if player == 1 else 1 # 检查自身是否有立即获胜的落子 for col in range(1, 8): # 创建棋盘副本模拟落子 temp_board = [row.copy() for row in board] if drop_piece(temp_board, player, col): # 检测模拟落子后是否获胜 if vertical_Win(temp_board) or horizontal_Win(temp_board) or diagonal_Win_TL_To_BR(temp_board) or diagonal_Win_Tr_To_BL(temp_board): drop_piece(board, player, col) return col # 检查对手是否有立即获胜的落子,进行阻挡 for col in range(1, 8): temp_board = [row.copy() for row in board] if drop_piece(temp_board, opponent, col): if vertical_Win(temp_board) or horizontal_Win(temp_board) or diagonal_Win_TL_To_BR(temp_board) or diagonal_Win_Tr_To_BL(temp_board): drop_piece(board, player, col) return col # 无获胜或阻挡机会,执行随机落子 return cpu_player_easy(board, player)
内容的提问来源于stack exchange,提问作者j1400

