Python文字冒险游戏合法输入仍重复询问问题排查
问题背景
- 开发场景:基于Python开发文字冒险游戏,自定义
NPC类管理非玩家角色,在类的attack()方法中实现战斗交互:NPC发起攻击后,玩家可选择攻击/防御,战斗采用high/middle/low三站位判定机制。 - 异常表现:防御逻辑存在可复现bug,玩家攻击NPC的模块存在完全相同的问题——即便玩家输入high/middle/low这类合法站位值,程序仍会反复弹出输入提示要求重新输入,无法进入后续战斗判定流程。
问题复现代码
turn = True while turn: player_defend_pos = input('Where would you like to defend the attack? High, middle or low. ').lower() possible_positions = ['high', 'middle', 'low'] attack_pos = random.choice(possible_positions) # 核心bug就在下面这行的判断条件 while player_defend_pos not in [possible_positions] and player_defend_pos not in possible_actions: player_defend_pos = input('Where would you like to defend the attack? High, middle or low. ').lower() if player_defend_pos == 'm': use_medkit() elif player_defend_pos == 'help': help() elif player_defend_pos == 's': shop() elif player_defend_pos != attack_pos: if equipped_armour == False: print(f'You don\'t have any armour equipped so the {self.name} will do {self.damage} damage to you.') player['health'] -= self.damage if attack_pos == 'high': print(f'The {self.name} attacked you up high') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break elif attack_pos == 'middle': print(f'The {self.name} attacked you in the middle') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break else: print(f'The {self.name} attacked you down low') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break elif equipped_armour == True and shop_items[1][player['armours'][0] + ' protection'] > self.damage: print(f'Since you have {[player["armours"][0]]} equipped it will not do anything.') if attack_pos == 'high': print(f'The {self.name} attacked you up high') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break elif attack_pos == 'middle': print(f'The {self.name} attacked you in the middle') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break else: print(f'The {self.name} attacked you down low') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break elif equipped_armour == True and shop_items[1][player['armours'][0] + ' protection'] < self.damage: player['health'] -= self.damage - shop_items[1][player['armours'][0] + ' protection'] if attack_pos == 'high': print(f'The {self.name} attacked you up high') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break elif attack_pos == 'middle': print(f'The {self.name} attacked you in the middle') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break else: print(f'The {self.name} attacked you down low') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False break else: print('You have successfully defended the attack') turn = False break
根因排查
- 核心bug:输入校验条件写法错误
校验行写的是player_defend_pos not in [possible_positions],这里给本身就是列表的possible_positions额外套了一层方括号,实际生成的是二维列表[['high', 'middle', 'low']]——这个列表里唯一的元素是整个站位列表,不是单个站位字符串。玩家输入的high/middle/low都是字符串,永远不可能匹配这个二维列表里的元素,所以无论输入什么站位,都会被判定为非法输入,卡在循环里反复要求重输。 - 隐藏逻辑bug:NPC攻击站位随机位置错误
attack_pos = random.choice(possible_positions)写在了外层while循环内部,只要玩家输入错误触发重输,NPC的攻击站位就会重新随机一次,单次回合内攻击位置不固定,不符合正常战斗逻辑。 - 冗余问题:不同分支下的攻击提示、血量打印逻辑完全重复,代码冗余度极高,后续修改逻辑很容易出现漏改;另外护甲名打印时额外套了列表,会输出带方括号的异常格式。
修复方案
- 修正输入校验条件:把
[possible_positions]外层的方括号去掉,直接判断输入是否在站位列表或功能操作列表里。 - 把NPC攻击站位的随机逻辑移到玩家输入之前,保证单次战斗回合内NPC的攻击位置固定,不会随玩家重输变化。
- 抽离重复的打印逻辑,精简代码结构,修复护甲名打印的格式问题。
修复后的完整代码参考:
turn = True possible_positions = ['high', 'middle', 'low'] # 回合开始就固定NPC攻击位置,不要放在循环里重复随机 attack_pos = random.choice(possible_positions) # 提前定义所有合法输入:3个站位 + 3个功能指令 valid_inputs = possible_positions + ['m', 'help', 's'] while turn: player_defend_pos = input('Where would you like to defend the attack? High, middle or low. ').lower() # 修正校验条件,直接判断是否在合法输入列表里 while player_defend_pos not in valid_inputs: player_defend_pos = input('Invalid input! Please choose high, middle, low, or input m/help/s for other actions. ').lower() if player_defend_pos == 'm': use_medkit() elif player_defend_pos == 'help': help() elif player_defend_pos == 's': shop() elif player_defend_pos != attack_pos: # 先统一计算伤害 if not equipped_armour: print(f'You don\'t have any armour equipped so the {self.name} will do {self.damage} damage to you.') player['health'] -= self.damage else: armour_protect = shop_items[1][player['armours'][0] + ' protection'] if armour_protect > self.damage: print(f'Since you have {player["armours"][0]} equipped it will not do anything.') else: damage_taken = self.damage - armour_protect player['health'] -= damage_taken # 统一打印攻击提示和血量,不用每个分支重复写 pos_tip = { 'high': 'up high', 'middle': 'in the middle', 'low': 'down low' }[attack_pos] print(f'The {self.name} attacked you {pos_tip}') print(f'Your health: {player["health"]}') print(f'{self.name}\'s health: {self.health}') turn = False else: print('You have successfully defended the attack') turn = False
玩家攻击NPC的模块只要找到相同的[possible_positions]写法,按同样逻辑修正即可。
内容的提问来源于stack exchange,提问作者PrOgRaMmE
相关产品推荐
相关产品推荐

