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

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
根因排查
  1. 核心bug:输入校验条件写法错误
    校验行写的是player_defend_pos not in [possible_positions],这里给本身就是列表的possible_positions额外套了一层方括号,实际生成的是二维列表[['high', 'middle', 'low']]——这个列表里唯一的元素是整个站位列表,不是单个站位字符串。玩家输入的high/middle/low都是字符串,永远不可能匹配这个二维列表里的元素,所以无论输入什么站位,都会被判定为非法输入,卡在循环里反复要求重输。
  2. 隐藏逻辑bug:NPC攻击站位随机位置错误
    attack_pos = random.choice(possible_positions)写在了外层while循环内部,只要玩家输入错误触发重输,NPC的攻击站位就会重新随机一次,单次回合内攻击位置不固定,不符合正常战斗逻辑。
  3. 冗余问题:不同分支下的攻击提示、血量打印逻辑完全重复,代码冗余度极高,后续修改逻辑很容易出现漏改;另外护甲名打印时额外套了列表,会输出带方括号的异常格式。
修复方案
  1. 修正输入校验条件:把[possible_positions]外层的方括号去掉,直接判断输入是否在站位列表或功能操作列表里。
  2. 把NPC攻击站位的随机逻辑移到玩家输入之前,保证单次战斗回合内NPC的攻击位置固定,不会随玩家重输变化。
  3. 抽离重复的打印逻辑,精简代码结构,修复护甲名打印的格式问题。

修复后的完整代码参考:

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:45:39