Python实现井字棋时获胜条件变量未生效问题排查
井字棋程序循环无法退出问题排查
初始可正常运行版本
纯编程初学者基于《Automate the Boring Stuff》习题编写文本版井字棋程序时,最初版本可正常运行,代码如下:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): #function to print board print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) print(''' Hi! This is my tic-tac-toe text based game. To make your move, write where you want to play: top-L top-M top-R mid-L mid-M mid-R low-L low-M low-R ''') turn= 'X' #starting while True: printBoard(theBoard) print(f'Turn for {turn}. Where will you play?') try: move = input() if theBoard[move] == ' ': theBoard[move] = turn if turn == 'X': turn = 'O' else: turn = 'X' else: print('That move is not possible!') continue except KeyError: print('''Wrong input. To make your move, write where you want to play: top-L top-M top-R mid-L mid-M mid-R low-L low-M low-R ''') continue if ((theBoard['top-L']==theBoard['top-M']==theBoard['top-R']) and theBoard['top-L']!=' ')\ or ((theBoard['mid-L']==theBoard['mid-M']==theBoard['mid-R']) and theBoard['mid-R']!=' ')\ or ((theBoard['low-L']==theBoard['low-M']==theBoard['low-R']) and theBoard['low-L']!=' ')\ or ((theBoard['top-L']==theBoard['mid-M']==theBoard['low-R']) and theBoard['top-L']!=' ')\ or ((theBoard['low-L']==theBoard['mid-M']==theBoard['top-R']) and theBoard['low-L']!=' ')\ or ((theBoard['top-L']==theBoard['mid-L']==theBoard['low-L']) and theBoard['top-L']!=' ')\ or ((theBoard['top-M']==theBoard['mid-M']==theBoard['low-M']) and theBoard['top-M']!=' ')\ or ((theBoard['top-R']==theBoard['mid-R']==theBoard['low-R']) and theBoard['top-R']!=' '): break if turn == 'X': turn = 'O' else: turn = 'X' print(f'Good Job {turn}, you won!')
优化后出现的问题
初始版本运行正常,后续参考代码评审建议做优化:了解到代码中直接书写'X'、'O'属于魔术字符串,会降低代码整洁度,因此将其提取为单独变量;随后尝试把所有获胜判定逻辑存入名为conditions的变量中,但修改后玩家达成获胜落子时,程序无法跳出游戏循环。修改后的代码如下:
theBoard = {'top-L': ' ', 'top-M': ' ', 'top-R': ' ', 'mid-L': ' ', 'mid-M': ' ', 'mid-R': ' ', 'low-L': ' ', 'low-M': ' ', 'low-R': ' '} def printBoard(board): print(board['top-L'] + '|' + board['top-M'] + '|' + board['top-R']) print('-+-+-') print(board['mid-L'] + '|' + board['mid-M'] + '|' + board['mid-R']) print('-+-+-') print(board['low-L'] + '|' + board['low-M'] + '|' + board['low-R']) conditions = (((theBoard['top-L'] == theBoard['top-M'] == theBoard['top-R']) and theBoard['top-L'] != ' ') \ or ((theBoard['mid-L'] == theBoard['mid-M'] == theBoard['mid-R']) and theBoard['mid-R'] != ' ') \ or ((theBoard['low-L'] == theBoard['low-M'] == theBoard['low-R']) and theBoard['low-L'] != ' ') \ or ((theBoard['top-L'] == theBoard['mid-M'] == theBoard['low-R']) and theBoard['top-L'] != ' ') \ or ((theBoard['low-L'] == theBoard['mid-M'] == theBoard['top-R']) and theBoard['low-L'] != ' ') \ or ((theBoard['top-L'] == theBoard['mid-L'] == theBoard['low-L']) and theBoard['top-L'] != ' ') \ or ((theBoard['top-M'] == theBoard['mid-M'] == theBoard['low-M']) and theBoard['top-M'] != ' ') \ or ((theBoard['top-R'] == theBoard['mid-R'] == theBoard['low-R']) and theBoard['top-R'] != ' ')) print(''' Hi! This is my tic-tac-toe text based game. To make your move, write where you want to play: top-L top-M top-R mid-L mid-M mid-R low-L low-M low-R ''') playerX = 'X' playerO = 'O' turn= playerX while True: printBoard(theBoard) print(f'Turn for {turn}. Where will you play?') try: move = input() if theBoard[move] == ' ': theBoard[move] = turn if turn == playerX: turn = player0 else: turn = playerX else: print('That move is not possible!') continue except KeyError: print('''Wrong input. To make your move, write where you want to play: top-L top-M top-R mid-L mid-M mid-R low-L low-M low-R ''') continue if conditions == True: printBoard(theBoard) break if turn == playerX: turn = player0 else: turn = playerX print(f'Good Job {turn}, you won!')
问题原因
修改后的代码存在两个核心bug:
- 获胜条件计算时机错误:
conditions变量是在游戏循环启动前赋值的,这行代码运行时棋盘所有位置都是空格,因此conditions从初始化开始就固定为布尔值False。后续落子更新棋盘时,这个变量不会自动重新计算结果,循环中判断if conditions == True永远不成立,自然无法触发break退出循环。 - 变量名拼写错误:定义玩家标识时写的是
playerO(末尾是大写字母O),但切换回合、判定获胜者的代码里全部写成了player0(末尾是数字0),拼写不一致会触发NameError,即便修复获胜逻辑,程序跑到切换O玩家回合时也会直接崩溃。
修复方案
- 不要提前把获胜判定的计算结果存为固定变量,将获胜逻辑封装为独立函数,每次落子后调用函数,实时读取当前棋盘状态计算是否满足获胜条件:
def check_win(board): return ( ((board['top-L']==board['top-M']==board['top-R']) and board['top-L']!=' ') or ((board['mid-L']==board['mid-M']==board['mid-R']) and board['mid-R']!=' ') or ((board['low-L']==board['low-M']==board['low-R']) and board['low-L']!=' ') or ((board['top-L']==board['mid-M']==board['low-R']) and board['top-L']!=' ') or ((board['low-L']==board['mid-M']==board['top-R']) and board['low-L']!=' ') or ((board['top-L']==board['mid-L']==board['low-L']) and board['top-L']!=' ') or ((board['top-M']==board['mid-M']==board['low-M']) and board['top-M']!=' ') or ((board['top-R']==board['mid-R']==board['low-R']) and board['top-R']!=' ') )
循环内的获胜判断直接替换为if check_win(theBoard):即可。
2. 全局查找替换所有写错的player0为playerO,保证变量名前后一致。
内容的提问来源于stack exchange,提问作者Miguel Rodrigues
相关产品推荐
相关产品推荐

