14.2 回合制打怪游戏设计(文字版)
9. 练习


9.1 个人回答
import random
class Game():
# 初始化玩家姓名、HP、敌人HP
def __init__(self, player_name):
self.player_name = player_name
self.player_hp = 100
self.enemy_hp = 80
# 玩家操作攻击/防守
def actions(self):
self.action = input('Attack or Defense (A/D):')
if self.action == 'A':
self.enemy_hp -= random.randint(1, 20)
if self.enemy_hp <=0:
return
self.player_hp -= random.randint(1, 20)
elif self.action == 'D':
self.player_hp -= random.randint(1, 20)/10
else:
print('Invalid action')
# main
player_name = input('请输入玩家姓名:')
player1 = Game(player_name) # 创建实例并完成初始化
while player1.player_hp > 0 and player1.enemy_hp >0:
# 显示玩家和敌人血量
print(f'{player1.player_name} HP: {player1.player_hp:.2f}')
print(f'Enemy HP: {player1.enemy_hp:.2f}')
# 调用操作函数,玩家选择攻击/防守
player1.actions()
if player1.player_hp > 0:
print('You win!')
else:
print('You lose!')
# ---output---
请输入玩家姓名:Ran
Ran HP: 100.00
Enemy HP: 80.00
Attack or Defense (A/D):A
Ran HP: 91.00
Enemy HP: 61.00
Attack or Defense (A/D):A
Ran HP: 79.00
Enemy HP: 48.00
Attack or Defense (A/D):A
Ran HP: 70.00
Enemy HP: 30.00
Attack or Defense (A/D):D
Ran HP: 68.80
Enemy HP: 30.00
Attack or Defense (A/D):D
Ran HP: 68.10
Enemy HP: 30.00
Attack or Defense (A/D):D
Ran HP: 67.60
Enemy HP: 30.00
Attack or Defense (A/D):A
Ran HP: 47.60
Enemy HP: 27.00
Attack or Defense (A/D):A
Ran HP: 40.60
Enemy HP: 26.00
Attack or Defense (A/D):A
Ran HP: 25.60
Enemy HP: 23.00
Attack or Defense (A/D):A
Ran HP: 7.60
Enemy HP: 8.00
Attack or Defense (A/D):D
Ran HP: 7.00
Enemy HP: 8.00
Attack or Defense (A/D):D
Ran HP: 6.60
Enemy HP: 8.00
Attack or Defense (A/D):A
You win!9.2 老师思路
优化:
- 玩家和敌人都可以当做是对象,因此初始化时可以把敌人也当做是类似对象的实例。
import random
class Creature():
def attack(self):
attack_value = random.randint(1, 50)
return attack_value
player = Creature()
enemy = Creature()此处需要考虑类究竟如何使用,玩家和敌人都是类似的对象,因此可以通过类将其实例化出来。
- 游戏继续的条件是玩家和敌人都还活着,因此可以建立一个
while函数,条件就是player.not_dead() and enemy.not_dead(),此处又存在共性,所以可以在类中建立一个函数看玩家和敌人是否都存活。
import random
class Creature():
def attack(self):
attack_value = random.randint(1, 50)
return attack_value
def not_dead(self):
pass
player = Creature()
enemy = Creature()
while player.not_dead() and enemy.not_dead():
pass- 当需要编写
not-dead函数时,我们发现判断是否死亡的标准是血量,但是目前还没有血量这个参数,因此,可以在实例化的时候将血量当做参数传进去,就需要了init函数,此时再编写init函数,并加入需要的参数。
import random
class Creature():
def __init__(self, hp): # 根据需要设置参数,初始化
self.hp = hp
def attack(self):
attack_value = random.randint(1, 50)
return attack_value
def not_dead(self):
pass
player = Creature(100) # 传入参数
enemy = Creature(80)
while player.not_dead() and enemy.not_dead():
pass- 有了 hp 就可以编写 not_dead 这个函数了,即血量>0 为 True。
def not_dead(self):
if self.hp > 0:
return True
else:
return False继续优化:
上述代码是为了当符合某种条件时,返回我们指定的结果,从比较运算符处可知,运行的结果是布尔类型 ,恰好和我们本身希望返回的结果是一致的,因此可以优化成直接返回比较的结果,即 return self.hp > 0 。
def not_dead(self):
if self.hp <= 0:
return False
else:
return True
# 等价 1
# if self.hp <= 0:
# return False
# return True
# 等价 2
# 本身上述的写法,是为了当符合某种条件时,返回我们指定的结果
# 而我们现在需要返回的结果,恰好和我们本身指定的结果是一致的,因此可以优化成如下代码:
# return self.hp > 0- 疑问点:是否需要写 defence?感觉逻辑复杂不通。
自己继续上述思路补充的后续代码如下:
import random
class Game():
# 初始化玩家姓名、HP、敌人HP
def __init__(self, player_name):
self.player_name = player_name
self.player_hp = 100
self.enemy_hp = 80
# 玩家操作攻击/防守
def actions(self):
self.action = input('Attack or Defense (A/D):')
if self.action == 'A':
self.enemy_hp -= random.randint(1, 20)
if self.enemy_hp <=0:
return
self.player_hp -= random.randint(1, 20)
elif self.action == 'D':
self.player_hp -= random.randint(1, 20)/10
else:
print('Invalid action')
# main
player_name = input('请输入玩家姓名:')
player1 = Game(player_name) # 创建实例并完成初始化
while player1.player_hp > 0 and player1.enemy_hp >0:
# 显示玩家和敌人血量
print(f'{player1.player_name} HP: {player1.player_hp:.2f}')
print(f'Enemy HP: {player1.enemy_hp:.2f}')
# 调用操作函数,玩家选择攻击/防守
player1.actions()
if player1.player_hp > 0:
print('You win!')
else:
print('You lose!')以上代码暂时保留,继续老师思路:
- 有hp 值,下一步可以继续实现交互
if user_input == 'A':
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()上述代码有了,我们想到,无论敌人或玩家,都有收到攻击的情节,因此可以继续写一个函 能够实现player.being_attack(enemy_attack_value) 。
def being_attack(self, attack_value):
self.hp -= attack_value因此,主程序处进行攻击和防守就可写成:
if user_input == 'A':
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()
enemy.being_attack(player_attack_value)
player.being_attack(enemy_attack_value)
elif user_input == 'D':
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value * 0.1) # 因为不同软件对除法的处理略有不同,更倾向使用乘法而不是除法- 运行代码后,发现没有血量、不知道游戏进程、不知道游戏何时结束。首先补充血量显示:
显示血量在什么位置呢?A or B or C or D
player = Creature(100)
enemy = Creature(80)
# A
while player.not_dead() and enemy.not_dead():
# B
user_input = input("Attack or Defence (A/D): ") # 操作
# C
if user_input == 'A':
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()
enemy.being_attack(player_attack_value)
player.being_attack(enemy_attack_value)
elif user_input == 'D':
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value * 0.1)
# D选择显示血量的代码位置时,首先需要判断在循环内外,由于血量需要实时更新,因此需要在循环内。
其次,在操作前要根据血量判断执行什么操作,因此放在 user_input 之前。
while player.not_dead() and enemy.not_dead():
# 此处添加血量显示
print()
user_input = input('Attack or Defence (A/D): ') # 操作
if user_input == 'A':
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()
enemy.being_attack(player_attack_value)
player.being_attack(enemy_attack_value)
elif user_input == 'D':
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value * 0.1) # 因为不同软件对除法的处理略有不同,更倾向使用乘法而不是除法- 可以把显示血量写成一个函数
def show_status(self):
print(f'HP: {self.hp}')主程序调用
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
user_input = input('Attack or Defence (A/D): ') # 操作- 显示血量的时候发现不知道哪个是哪个的血量,如何解决?
需要名字这个变量,那就初始化的时候传进去:
def __init__(self, name, hp):
self.name = name
self.hp = hp
def show_status(self):
print(f"{self.name}'s HP: {self.hp}")player = Creature('Ran',100)
enemy = Creature('Monster',80)- 添加判断游戏结果的代码,放在循环结束后:
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose!")疑问:什么时候选择写成函数?
- 需要重复使用,存在共性的东西,比如玩家有多个,不需要写多个
print来显示血量。 - 有封装需求,方便后期统一修改维护。
- 若写在主程序里,修改时可能需要捋前后代码逻辑,输出可能变动,若封装成函数,只要保证 return 不变,主函数的代码出错的概率将会大大减少。
9.3 对自己的代码进行修改
对自己写的代码进行修改:
- 玩家姓名可以当做参数传入类中,在初始化步骤中完成,也可对敌人起名。
class Creature():
# 初始化姓名、HP
def __init__(self, name, hp):
self.name = name
self.hp = hp因此,后续程序中,可以添加 Creature(player_name, 100) 和 Creature(Enemy, 80) 创建玩家和敌人。
player_name = input('请输入玩家姓名:')
player = Creature(player_name, 100) # 创建玩家并完成初始化
enemy = Creature('Monster', 80) # 创建敌人并初始化个人代码修改如下:
import random
# 将玩家和敌人都抽象成一个类
class Creature():
def __init__(self, name, hp): # 与玩家和敌人都相关的基本参数是姓名和血量
self.name = name
self.hp = hp
def show_HP(self): # 显示血量
print(f"{self.name}'s HP: {self.hp}")
def is_alive(self): # 与两者都相关的存亡状态
return self.hp > 0
def defence(self, harm): # 自己防守时,血量只减十分之一
self.hp -= 0.1*harm
def being_attack(self, harm, action): # 被攻击,自己血量变化
if action == "D":
self.defence(harm)
else:
self.hp -= harm
def attack(self, target, action='A'): # 攻击对方,为了区分玩家和敌人,需要有一个攻击对象
harm = random.randint(0, 50)
target.being_attack(harm, action) # 对方被攻击了,对方血量变动,只有被攻击和攻击分开两个函数,才能实现对方血量变动
# 游戏交互阶段开始
class Game():
def __init__(self, player_name): # 玩家给出的姓名作为参数传进去
self.player = Creature(player_name, 100)
self.enemy = Creature('Monster', 80) # 初始化出敌人
def actions(self):
while True:
action = input('Attack or Defence (A/D): ')
if action in ('A', 'D'):
return action
else:
print("输入无效,请重新输入。")
def play(self):
while self.player.is_alive() and self.enemy.is_alive():
self.player.show_HP()
self.enemy.show_HP()
# 玩家开始选择攻击/防守
player_action = self.actions()
if player_action == 'A':
self.player.attack(self.enemy) # 玩家攻击敌人减血,玩家防守时,敌人不减血,因此不需要操作
# 敌方开始反击
if self.enemy.is_alive(): # 看看敌方还有血没,有血再打
self.enemy.attack(self.player, player_action)
# 结算结果
if self.player.is_alive():
print("\n🎉 你赢了!")
else:
print("\n💀 你输了!")
# main
player_name = input("请输入玩家姓名:")
game = Game(player_name)
game.play()优化:
- 函数命名尽量不要用大写,修改如下
def show_hp(self): # 显示血量
print(f"{self.name}'s HP: {self.hp}")- 函数的注释可以直接在函数内第一行加三个双引号,如下:
def being_attack(self, harm, action):
"""
被攻击时的血量变化
:param harm: 伤害值
:param action: "A" 表示攻击;"D" 表示防守
"""
if action == "D":
self.defence(harm)
else:
self.hp -= harm其中,:param 是形参,可以对传入的参数进行注释。
9.4 功能扩展
9.4.1 优化血量的显示效果
def show_status(self):
print(f"{self.name}'s HP → {self.hp}")9.4.2 血量问题:会出现负数的情况
如何验证血量负数情况?
两个方向:扩大减血的范围,将0.1改掉;在输掉的时候显示血量。
You lose! Your HP: -1.800000000000023同理,也可以在结果出输出敌人血量:
You win! Enemy HP: -1此外,也可以修改 while 的条件,只保留玩家不死的条件,玩家一直攻击,敌人很快血量变复数,但是此时循环还未结束,显示血量 show_status() 阶段,会出现负数的敌人血量。
Ran's HP → 100
Monster's HP → 80
Attack or Defence (A/D): A
Ran's HP → 70
Monster's HP → 36
Attack or Defence (A/D): A
Ran's HP → 64
Monster's HP → -6
Attack or Defence (A/D): A
Ran's HP → 36
Monster's HP → -32如何修改血量是负数的情况?
思路:什么时候会出现负数?减血量的时候。
方法一:判断伤害值和剩余血量,伤害值高,血量归零,伤害值低,正常减:
def being_attack(self, attack_value):
if attack_value >= self.hp:
self.hp = 0
else:
self.hp -= attack_value方法二:先进行减血,若减出负数,则进行归零处理:
def being_attack(self, attack_value):
self.hp -= attack_value
if self.hp <= 0:
self.hp = 0方法三:使用 max() 函数
int(self.hp-attack_value) 此处可能是负数,也可能是正数,但是 max() 做到了从两个元素中取最大值,因此该值是负数的时候,总会取到最大值 0 ,因此也可以实现血量的控制。
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))9.4.3 用户输入控制
要对用户输入可能出现的空格和小写控制,并且当输入错误时,可以实现重新输入:
user_input = input('Attack or Defence (A/D): ').strip().upper()
while user_input not in ('A', 'D'):
user_input = input('输入无效,请重新输入 A 或 D').strip().upper()9.4.4 敌人状态随意
敌人是随机状态,有可能是攻击,有可能是防守。如果敌人是防守状态,受到玩家伤害减半。
- 初步实现
enemy_status = random.choice(['A', 'D'])
if enemy_status == 'D':
enemy.being_attack(0.5 * player_attack_value)- 在玩家的操作中实现
玩家攻击时实现如下:
if user_input == 'A':
enemy_status = random.choice(['A', 'D'])
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_value = 0.5*player.attack()
else:
print(f'{enemy.name} chose to attack!')
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
enemy.being_attack(player_attack_value)当玩家防守时,应该如何实现?
import random
class Creature():
# ---snip---
player = Creature('Ran',100)
enemy = Creature('Monster',80)
while player.not_dead() and enemy.not_dead():
# ---snip---
if user_input == 'A':
# ---snip---
elif user_input == 'D':
enemy_status = random.choice(['A', 'D'])
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
print('Both defended, no damage dealt.')
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
# ---snip---目前完整代码:
import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp}")
player = Creature('Ran',100)
enemy = Creature('Monster',80)
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
user_input = input('Attack or Defence (A/D): ').strip().upper()
while user_input not in ('A', 'D'):
user_input = input('输入无效,请重新输入 A 或 D').strip().upper()
if user_input == 'A':
enemy_status = random.choice(['A', 'D'])
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_value = 0.5*player.attack()
else:
print(f'{enemy.name} chose to attack!')
player_attack_value = player.attack()
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
enemy.being_attack(player_attack_value)
elif user_input == 'D':
enemy_status = random.choice(['A', 'D'])
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
print('Both defended, no damage dealt.')
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")9.4.5 改良实现
可优化点一:玩家进行攻击操作时,无论敌人什么状态(攻击or防守),玩家都要攻击,敌人一定会减血。
优化前if user_input == 'A': enemy_status = random.choice(['A', 'D']) if enemy_status == 'D': print(f'{enemy.name} chose to defend!') player_attack_value = 0.5*player.attack() else: print(f'{enemy.name} chose to attack!') player_attack_value = player.attack() enemy_attack_value = enemy.attack() player.being_attack(enemy_attack_value) enemy.being_attack(player_attack_value)优化后if user_input == 'A': enemy_status = random.choice(['A', 'D']) player_attack_coefficient = 1 if enemy_status == 'D': print(f'{enemy.name} chose to defend!') player_attack_coefficient = 0.5 else: print(f'{enemy.name} chose to attack!') enemy_attack_value = enemy.attack() player.being_attack(enemy_attack_value) player_attack_value = player.attack() enemy.being_attack(player_attack_value * player_attack_coefficient)可优化点二:玩家选择攻击后要判断敌人状态,玩家选择防守时也同样要判断敌人状态,都需要生成一个表示敌人状态的变量。
优化前if user_input == 'A': enemy_status = random.choice(['A', 'D']) player_attack_coefficient = 1 if enemy_status == 'D': print(f'{enemy.name} chose to defend!') player_attack_coefficient = 0.5 else: print(f'{enemy.name} chose to attack!') enemy_attack_value = enemy.attack() player.being_attack(enemy_attack_value) player_attack_value = player.attack() enemy.being_attack(player_attack_value * player_attack_coefficient) elif user_input == 'D': enemy_status = random.choice(['A', 'D']) if enemy_status == 'D': print(f'{enemy.name} chose to defend!') print('Both defended, no damage dealt.') else: print(f'{enemy.name} chose to attack!') enemy_attack_value = 0.1*enemy.attack() player.being_attack(enemy_attack_value)优化后# 将涉及敌人状态的代码提出来 enemy_status = random.choice(['A', 'D']) if user_input == 'A': player_attack_coefficient = 1 if enemy_status == 'D': print(f'{enemy.name} chose to defend!') player_attack_coefficient = 0.5 else: print(f'{enemy.name} chose to attack!') enemy_attack_value = enemy.attack() player.being_attack(enemy_attack_value) player_attack_value = player.attack() enemy.being_attack(player_attack_value * player_attack_coefficient) elif user_input == 'D': if enemy_status == 'D': print(f'{enemy.name} chose to defend!') print('Both defended, no damage dealt.') else: print(f'{enemy.name} chose to attack!') enemy_attack_value = 0.1*enemy.attack() player.being_attack(enemy_attack_value)
当我们优化后,发现第一个优化其实意义不大,但是在实际开发中就是如此,你更新了一个新的功能或代码,客户、用户觉得没必要,但是我们也懒得改回去。
目前完整代码:
import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp}")
player = Creature('Ran',100)
enemy = Creature('Monster',80)
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
user_input = input('Attack or Defence (A/D): ').strip().upper()
while user_input not in ('A', 'D'):
user_input = input('输入无效,请重新输入 A 或 D').strip().upper()
enemy_status = random.choice(['A', 'D'])
if user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
print('Both defended, no damage dealt.')
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")9.4.6 游戏策略升级
当前游戏策略并不完备。
因为玩家防守时,敌人必须要攻击,不能两个人都防守。
因此优化为:玩家防守,敌人必攻击!
玩家防守情况中的代码可以还原为前面的版本,里面不再包含判断敌人状态的步骤。
elif user_input == 'D':
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)发现:可能最开始的是最好的。
目前完整代码:
import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp}")
player = Creature('Ran',100)
enemy = Creature('Monster',80)
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
user_input = input('Attack or Defence (A/D): ').strip().upper()
while user_input not in ('A', 'D'):
user_input = input('输入无效,请重新输入 A 或 D').strip().upper()
enemy_status = random.choice(['A', 'D'])
if user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")9.4.7 玩家回血技能
当玩家血量低于50%时,提示玩家可以输入“H”来使用治疗技能,直接回血 100% (满血)。
要求:
- 只能使用一次!
- 无法随时使用回血技能,只有在提示出现时才能够使用。
- 血量低于一般按照初始化传入的参数决定,随其变化。
第一步:增加初始血量值
player = Creature('Ran',100)
enemy = Creature('Monster',80)
player_initial_hp = player.hp # 这里是一个值,成立,若是字典/列表则需要考虑深浅拷贝问题class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
self.max_hp = hp # 增加 max_hp 这个变量第二步:类里增加一个函数
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp第三步:显示血量的函数随之可以优化,显示当前血量/原始血量。
def show_status(self):
print(f"{self.name}'s HP → {self.hp/self.max_hp}")第四步:因为只能提示一次,所以增加一个变量 heal_used 判断是否显示过了。个人修改时纠结的问题在于,在循环内设置了这个变量,那么循环时会被覆盖,重新初始化,解决的方法就是把这个变量放到循环外面。
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False后面具体实现过程如下:
if (player.hp < player.max_hp*0.5) and (not heal_used): # 原本包含2个if ,可以通过 and 的使用进行合并
recover = input('血量低于 50% ,可以输入 H 使用治疗技能,直接恢复满血状态:').strip().upper()
if recover == 'H':
player.heal_full()
heal_used = True# 将回血和攻击/防守进行合并
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False # 限制回血只能用一次
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前血量<初始值50% 并且尚未使用回血功能
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H): '
valid_inputs = {'A', 'D', 'H'}
extra_tip = '(提示:现在可以按 H 回满血,仅此一次)'
print(extra_tip)
else:
prompt = 'Attack or Defence (A/D): '
valid_inputs = {'A', 'D'}
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input('输入无效,请重新输入: ' + prompt).strip().upper()
enemy_status = random.choice(['A', 'D'])
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_used = True
elif user_input == 'A':目前完整代码:
import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
self.max_hp = hp # 记录初始血量
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp/self.max_hp}")
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
user_input = input('Attack or Defence (A/D): ').strip().upper()
while user_input not in ('A', 'D'):
user_input = input('输入无效,请重新输入 A 或 D').strip().upper()
enemy_status = random.choice(['A', 'D'])
if user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
if (player.hp < player.max_hp*0.5) and (not heal_used):
recover = input('血量低于 50% ,可以输入 H 使用治疗技能,直接恢复满血状态:').strip().upper()
if recover == 'H':
player.heal_full()
heal_used = True
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
self.max_hp = hp # 记录初始血量
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp/self.max_hp}")
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False # 限制回血只能用一次
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前血量<初始值50% 并且尚未使用回血功能
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H): '
valid_inputs = {'A', 'D', 'H'}
extra_tip = '(提示:现在可以按 H 回满血,仅此一次)'
print(extra_tip)
else:
prompt = 'Attack or Defence (A/D): '
valid_inputs = {'A', 'D'}
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input('输入无效,请重新输入: ' + prompt).strip().upper()
enemy_status = random.choice(['A', 'D'])
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_used = True
elif user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
print(f'{enemy.name} chose to attack!')
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)
if player.hp > 0:
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")但是上述老师的代码也有个小问题,如果没有选择回血的话,就会一直提示可以使用回血。如果我们希望这个提示和回血的选择只出现一次,就是过这村没这店的情况,就可以将 heal_used = True 从玩家选择 H 的判断中提出来,可以放在提示出现后。
此外,在将回血功能加入时,需要考虑用户输入 H 的情况,那么可以在用户输入的提示语上进行修改,代码如下:
import random
class Creature():
def __init__(self, hp, name):
self.hp = hp
self.max_hp = hp # 记录初始满血
self.name = name
def attack(self):
return random.randint(0, 50)
def not_dead(self):
return self.hp > 0
def being_attack(self, dmg: float):
"""受到伤害(向下取整以避免浮点 HP),并保证 HP 不会掉到负数以下"""
self.hp = max(0, int(self.hp - dmg))
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
def show_status(self):
# print(f"{self.name}'s HP → {self.hp}")
print(f"{self.name}'s HP → {self.hp}/{self.max_hp}")
heal_used = False # 治疗仅限一次
player = Creature(100, "AI悦创")
enemy = Creature(80, "Enemy")
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
prompt = "Attack or Defence (A/D):"
if (player.hp < player.max_hp * 0.5) and (not heal_used):
print("(提示:你现在可以按 H 回满血,仅此一次)")
prompt = "Attack or Defence or Heal (A/D/H):"
user_input = input(prompt).strip().upper()
while user_input not in ("A", "D", "H"):
user_input = input("输入无效,请重新输入 A 或 D:").strip().upper()
enemy_status = ['Attack', 'Defence']
enemy_choice = random.choice(enemy_status)
if user_input == "A":
player_attack_coefficient = 1 # MR 取名
if enemy_choice == "Defence":
print(f"{enemy.name} chose to defend!")
player_attack_coefficient = 0.5
else:
print(f"{enemy.name} chose to attack!")
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == "D":
enemy_attack_value = enemy.attack() * 0.1
player.being_attack(enemy_attack_value)
elif user_input == "H":
player.heal_full()
heal_used = True
print(f"{player.name} healed to full health!")
prompt = "Attack or Defence (A/D):"
if player.not_dead():
print("You Win!")
else:
print("You Lose!")9.4.8 回血技能代价
回血是有代价的,如果玩家使用了回血技能,后续敌人一定会攻击,并且攻击将翻倍。
可以在敌人攻击时,判断回血技能是否使用,如果使用了,那么攻击 乘2。
下述代码是在 heal_used = True 放在输入是 H 下的判断中的情况:
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_used = True
elif user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
if heal_used: # 判断是否回血治疗了
enemy_attack_value = 2 * enemy.attack()
else:
enemy_attack_value = enemy.attack()
player.being_attack(enemy_attack_value)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
print(f'{enemy.name} chose to attack!')
if heal_used: # 判断是否回血治疗了
enemy_attack_value = 2*(0.1*enemy.attack())
else:
enemy_attack_value = 0.1*enemy.attack()
player.being_attack(enemy_attack_value)如果我们想要指定“过这村没这店”的情况,那么像我们上面提到过的 heal_used = True 被提到外面,就需要将“提示过”和“使用回血”区分开,因此需要引入一个新变量 heal_penalty_active ,具体代码如下:
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False # 限制回血只能用一次
heal_penalty_active = False # 回血代价激活状态
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前血量<初始值50% 并且尚未使用回血功能
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H): '
valid_inputs = {'A', 'D', 'H'}
extra_tip = '(提示:现在可以按 H 回满血,仅此一次)'
print(extra_tip)
heal_used = True # 说明回血提示出现了,之后不会再出现
else:
prompt = 'Attack or Defence (A/D): '
valid_inputs = {'A', 'D'}
if heal_penalty_active:
print('【警告】治疗代价生效中,敌人对你的伤害 ×2 !')
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input('输入无效,请重新输入: ' + prompt).strip().upper()
# 敌人选择(若玩家选择 D 或者 H ,敌人都直接攻击)
enemy_status = random.choice(['A', 'D'])
# 当前敌人伤害倍率(是否翻倍)
def enemy_mul():
return 2.0 if heal_penalty_active else 1.0
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_penalty_active = True # 触发治疗代价
# 敌人回合:直接攻击,先治疗再挨打
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f'{enemy.name}攻击了你,造成{int(damage)}点伤害!(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)
elif user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f'{enemy.name}攻击了你,造成{int(damage)}点伤害!(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
# 防御:敌人攻击减伤为 90% ,然后再应用翻倍倍率
print(f'{enemy.name} chose to attack!')
raw_enemy_attack_value = enemy.attack()
damage = (raw_enemy_attack_value*0.1) * enemy_mul()
print(f'{enemy.name}攻击了你(被你防住大部分),造成{int(damage)}点伤害!'
f'(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)目前完整代码如下:
import random
class Creature():
def __init__(self, name, hp):
self.name = name
self.hp = hp
self.max_hp = hp # 记录初始血量
def attack(self):
attack_value = random.randint(0, 50)
return attack_value
def not_dead(self):
return self.hp > 0
def being_attack(self, attack_value):
"""受到伤害(向下取整避免血量显示为浮点数,并且保证了血量不会出现负数"""
self.hp = max(0, int(self.hp-attack_value))
def show_status(self):
print(f"{self.name}'s HP → {self.hp}/{self.max_hp}")
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
player = Creature('Ran',100)
enemy = Creature('Monster',80)
heal_used = False # 限制回血只能用一次
heal_penalty_active = False # 回血代价激活状态
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前血量<初始值50% 并且尚未使用回血功能
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H): '
valid_inputs = {'A', 'D', 'H'}
extra_tip = '(提示:现在可以按 H 回满血,仅此一次)'
print(extra_tip)
heal_used = True # 说明回血提示出现了,之后不会再出现
else:
prompt = 'Attack or Defence (A/D): '
valid_inputs = {'A', 'D'}
if heal_penalty_active:
print('【警告】治疗代价生效中,敌人对你的伤害 ×2 !')
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input('输入无效,请重新输入: ' + prompt).strip().upper()
# 敌人选择(若玩家选择 D 或者 H ,敌人都直接攻击)
enemy_status = random.choice(['A', 'D'])
# 当前敌人伤害倍率(是否翻倍)
def enemy_mul():
return 2.0 if heal_penalty_active else 1.0
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_penalty_active = True # 触发治疗代价
# 敌人回合:直接攻击,先治疗再挨打
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f'{enemy.name}攻击了你,造成{int(damage)}点伤害!(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)
elif user_input == 'A':
player_attack_coefficient = 1
if enemy_status == 'D':
print(f'{enemy.name} chose to defend!')
player_attack_coefficient = 0.5
else:
print(f'{enemy.name} chose to attack!')
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f'{enemy.name}攻击了你,造成{int(damage)}点伤害!(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == 'D':
# 防御:敌人攻击减伤为 90% ,然后再应用翻倍倍率
print(f'{enemy.name} chose to attack!')
raw_enemy_attack_value = enemy.attack()
damage = (raw_enemy_attack_value*0.1) * enemy_mul()
print(f'{enemy.name}攻击了你(被你防住大部分),造成{int(damage)}点伤害!'
f'(原始{int(raw_enemy_attack_value)}×倍率{enemy_mul():.0f})')
player.being_attack(damage)
if player.not_dead():
print(f"You win! Your HP: {player.hp}")
else:
print(f"You lose! ")其他优化:警告只显示一次如何处理?
解决方法:将警告移到 H 里面即可:
if user_input == 'H':
# 只有在 can_heal_now 为 True 时才会进入这里
print('你使用了治疗技能,血量已经回满。')
player.heal_full()
heal_penalty_active = True # 触发治疗代价
print('【警告】治疗代价生效中,敌人对你的伤害 ×2 !')9.4.9 血量进度条
老师示例
完整代码:
import random import sys # ====== 终端颜色与进度条工具 ====== RESET = "\033[0m" FG_RED = "\033[31m" FG_YELLOW = "\033[33m" FG_GREEN = "\033[32m" FG_CYAN = "\033[36m" FG_MAGENTA = "\033[35m" def _supports_color() -> bool: # 基本判断:是交互终端就上色;否则退化为无色 return sys.stdout.isatty() def colorize(s: str, color: str) -> str: if _supports_color(): return f"{color}{s}{RESET}" return s def hp_bar(cur: int, maxv: int, width: int = 30) -> str: cur = max(0, min(cur, maxv)) ratio = cur / maxv if maxv > 0 else 0 filled = int(round(ratio * width)) empty = width - filled # 阈值配色:>50% 绿;20%~50% 黄;<=20% 红 if ratio > 0.5: bar_color = FG_GREEN elif ratio > 0.2: bar_color = FG_YELLOW else: bar_color = FG_RED bar = "█" * filled + "░" * empty percent = f"{int(ratio * 100):3d}%" return f"[{colorize(bar, bar_color)}] {percent} {cur}/{maxv}" # ====== 你的游戏代码(加入进度条显示) ====== class Creature: def __init__(self, hp, name): self.hp = int(hp) self.max_hp = int(hp) # 记录初始满血 self.name = name def attack(self): return random.randint(0, 50) def not_dead(self): return self.hp > 0 def being_attack(self, dmg: float): """受到伤害(向下取整以避免浮点 HP),并保证 HP 不会掉到负数以下""" self.hp = max(0, int(self.hp - dmg)) def heal_full(self): """直接回到初始满血""" self.hp = self.max_hp def show_status(self): # 名称加一点配色区分玩家/敌人 name_str = self.name if self.name == "AI悦创": name_str = colorize(self.name, FG_CYAN) elif self.name.lower().startswith("enemy"): name_str = colorize(self.name, FG_MAGENTA) print(f"{name_str} HP {hp_bar(self.hp, self.max_hp)}") player = Creature(100, "AI悦创") enemy = Creature(80, "Enemy") heal_used = False # 治疗仅限一次 heal_penalty_active = False # 是否已触发“敌人攻击翻倍”的惩罚 while player.not_dead() and enemy.not_dead(): print("\n=== 状态 ===") player.show_status() enemy.show_status() # 是否出现治疗提示:仅当当前 HP < 初始 HP 的 50% 且尚未使用 can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5) if can_heal_now: prompt = 'Attack or Defence or Heal (A/D/H):' valid_inputs = {"A", "D", "H"} print(colorize('(提示:你现在可以按 H 回满血,仅此一次)', FG_YELLOW)) else: prompt = 'Attack or Defence (A/D):' valid_inputs = {"A", "D"} if heal_penalty_active: print(colorize('【警告】治疗代价生效中:敌人对你的伤害 ×2!', FG_RED)) user_input = input(prompt).strip().upper() while user_input not in valid_inputs: user_input = input("输入无效,请重新输入:" + prompt).strip().upper() # 敌人选择(对 A/D 有影响;若玩家选择 H,我们让敌人本回合直接攻击) enemy_status = ['Attack', 'Defence'] enemy_choice = random.choices(enemy_status, weights=[0.7, 0.3], k=1)[0] # 敌人更倾向于攻击 # 当前敌人伤害倍率(是否翻倍) def enemy_mul(): return 2.0 if heal_penalty_active else 1.0 if user_input == "H": # 只有在 can_heal_now 为 True 时才会进入到这里(上面已限制输入选项) print(colorize("你使用了治疗技能!血量已回满。", FG_GREEN)) player.heal_full() heal_used = True # 触发治疗代价:从现在起敌人攻击翻倍(包含本回合的随后的敌人攻击) heal_penalty_active = True # 敌人回合:直接攻击(先治再挨打) raw_enemy_attack_value = enemy.attack() damage = raw_enemy_attack_value * enemy_mul() print(f"{enemy.name} 攻击了你,造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})") player.being_attack(damage) elif user_input == "A": player_attack_coefficient = 1 if enemy_choice == "Defence": print(f"{enemy.name} chose to defend!") player_attack_coefficient = 0.5 else: print(f"{enemy.name} chose to attack!") raw_enemy_attack_value = enemy.attack() damage = raw_enemy_attack_value * enemy_mul() print(f"{enemy.name} 对你造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})") player.being_attack(damage) player_attack_value = player.attack() enemy.being_attack(player_attack_value * player_attack_coefficient) print(f"你对 {enemy.name} 造成 {int(player_attack_value * player_attack_coefficient)} 点伤害。") elif user_input == "D": # 防御:敌人攻击减伤为 90%,然后再应用翻倍倍率 raw_enemy_attack_value = enemy.attack() damage = raw_enemy_attack_value * 0.1 * enemy_mul() print(f"{enemy.name} 攻击了你(被你防住大部分),造成 {int(damage)} 点伤害!" f"(原始{int(raw_enemy_attack_value)} × 减伤0.1 × 倍率{enemy_mul():.0f})") player.being_attack(damage) if player.not_dead(): print(colorize("You Win!", FG_GREEN)) else: print(colorize("You Lose!", FG_RED))注释:
import sys # 用于判断标准输出是否是一个“交互式终端”(TTY),从而决定是否使用颜色 # ====== 终端颜色与进度条工具 ====== RESET = "\033[0m" # ANSI 转义序列:重置所有颜色/样式 FG_RED = "\033[31m" # 前景色:红 FG_YELLOW = "\033[33m"# 前景色:黄 FG_GREEN = "\033[32m" # 前景色:绿 FG_CYAN = "\033[36m" # 前景色:青(给玩家名上色用) FG_MAGENTA = "\033[35m"# 前景色:洋红(给敌人名上色用) def _supports_color() -> bool: """ 判断当前 stdout 是否是一个 TTY(交互式终端)。 - 如果是 TTY,通常可以正确解析 ANSI 颜色转义序列 -> 返回 True。 - 如果不是(比如写入文件、被重定向到日志系统),就不要输出颜色码 -> 返回 False。 这样可以避免在不支持颜色的环境里看到一堆“\x1b[31m”之类的乱码。 """ return sys.stdout.isatty() def colorize(s: str, color: str) -> str: """ 根据 _supports_color() 的结果,有选择地给字符串加颜色。 - 支持颜色:前后包裹 color 与 RESET 转义码。 - 不支持颜色:原样返回,避免污染输出。 """ if _supports_color(): return f"{color}{s}{RESET}" return s def hp_bar(cur: int, maxv: int, width: int = 30) -> str: """ 生成一个文本进度条,形如: [██████████░░░░░░░░░░░░░░] 40% 40/100 参数: - cur: 当前 HP(会被限制在 0..maxv 范围,以避免越界) - maxv: 最大 HP(分母;注意做 0 保护) - width: 进度条宽度(字符数),默认 30 返回: - 包含彩色条形、百分比和“cur/maxv”数值的字符串 """ # 1) 防御式编程:先把 cur 限制在 [0, maxv],避免出现负数/超上限 cur = max(0, min(cur, maxv)) # 2) 计算比例 ratio,注意 maxv=0 的兜底(避免 ZeroDivisionError) ratio = cur / maxv if maxv > 0 else 0 # 3) 根据比例计算“填充块”数量 # - round 而非 floor:让临界值(例如 100%)可以填满整条;否则容易出现 99% 看起来没满的“强迫症”效果 # - 再用 int 转成整数个字符 filled = int(round(ratio * width)) empty = width - filled # 剩余未填充部分 # 4) 阈值配色: # ratio > 0.5 → 绿色(安全) # 0.2 < ratio <= 0.5 → 黄色(警戒) # ratio <= 0.2 → 红色(危险) # 这样在对局中能直观感受到“健康程度” if ratio > 0.5: bar_color = FG_GREEN elif ratio > 0.2: bar_color = FG_YELLOW else: bar_color = FG_RED # 5) 使用全块 '█' 表示已填充,用浅色 '░' 表示未填充(视觉对比明显) # 如果你的终端或字体对这些字符支持不好,可以换成 '#' 和 '-' 等 ASCII 字符。 bar = "█" * filled + "░" * empty # 6) 百分比显示:取整到 0..100 之间,并用 :3d 做宽度对齐(右对齐占 3 格,像 " 40%") percent = f"{int(ratio * 100):3d}%" # 7) 把彩色条形 + 百分比 + “cur/maxv” 组装成最终字符串 return f"[{colorize(bar, bar_color)}] {percent} {cur}/{maxv}"
补充知识:
四舍五入的取整 round()
个人代码:
只对 show_status 这个函数进行修改。
def show_status(self):
max_hp_bar = round(self.max_hp/10)
now_hp_bar = round((self.hp / self.max_hp) * max_hp_bar)
hp_bar = (now_hp_bar * '█')+((max_hp_bar-now_hp_bar) * '░')
print(f"{self.name}'s HP → {hp_bar} {self.hp}/{self.max_hp}")老师代码:
import random
# —— 简单无色进度条(纯 ASCII,跨平台)——
def hp_bar(cur: int, maxv: int, width: int = 20) -> str:
"""返回形如:[##########----------] 50% 50/100 的进度条文本"""
if maxv <= 0:
maxv = 1
cur = max(0, min(cur, maxv))
ratio = cur / maxv
filled = int(ratio * width + 0.5) # 四舍五入,因为 int 的取整是把小数点后的直接锯掉
bar = "#" * filled + "-" * (width - filled)
return f"[{bar}] {int(ratio * 100):3d}% {cur}/{maxv}"
class Creature:
# ---snip---
def show_status(self):
print(f"{self.name}'s HP → {hp_bar(self.hp, self.max_hp)}")import random
# —— 简单无色进度条(纯 ASCII,跨平台)——
def hp_bar(cur: int, maxv: int, width: int = 20) -> str:
"""返回形如:[##########----------] 50% 5g0/100 的进度条文本"""
if maxv <= 0:
maxv = 1
cur = max(0, min(cur, maxv))
ratio = cur / maxv
filled = int(ratio * width + 0.5) # 四舍五入
bar = "#" * filled + "-" * (width - filled)
return f"[{bar}] {int(ratio * 100):3d}% {cur}/{maxv}"
class Creature:
def __init__(self, hp, name):
self.hp = int(hp)
self.max_hp = int(hp) # 记录初始满血
self.name = name
def attack(self):
return random.randint(0, 50)
def not_dead(self):
return self.hp > 0
def being_attack(self, dmg: float):
"""受到伤害(向下取整以避免浮点 HP),并保证 HP 不会掉到负数以下"""
self.hp = max(0, int(self.hp - dmg))
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
def show_status(self):
print(f"{self.name}'s HP → {hp_bar(self.hp, self.max_hp)}")
player = Creature(100, "AI悦创")
enemy = Creature(80, "Enemy")
heal_used = False # 治疗仅限一次
heal_penalty_active = False # 是否已触发“敌人攻击翻倍”的惩罚
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前 HP < 初始 HP 的 50% 且尚未使用
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H):'
valid_inputs = {"A", "D", "H"}
print('(提示:你现在可以按 H 回满血,仅此一次)')
else:
prompt = 'Attack or Defence (A/D):'
valid_inputs = {"A", "D"}
if heal_penalty_active:
print('【警告】治疗代价生效中:敌人对你的伤害 ×2!')
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input("输入无效,请重新输入:" + prompt).strip().upper()
# 敌人选择(对 A/D 有影响;若玩家选择 H,我们让敌人本回合直接攻击)
enemy_status = ['Attack', 'Defence']
enemy_choice = random.choices(enemy_status, weights=[0.7, 0.3], k=1)[0] # 敌人更倾向于攻击
# 当前敌人伤害倍率(是否翻倍)
def enemy_mul():
return 2.0 if heal_penalty_active else 1.0
if user_input == "H":
# 只有在 can_heal_now 为 True 时才会进入到这里
print("你使用了治疗技能!血量已回满。")
player.heal_full()
heal_used = True
# 触发治疗代价:从现在起敌人攻击翻倍(包含本回合的随后的敌人攻击)
heal_penalty_active = True
# 敌人回合:直接攻击(先治再挨打)
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f"{enemy.name} 攻击了你,造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
elif user_input == "A":
player_attack_coefficient = 1
if enemy_choice == "Defence":
print(f"{enemy.name} chose to defend!")
player_attack_coefficient = 0.5
else:
print(f"{enemy.name} chose to attack!")
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f"{enemy.name} 对你造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == "D":
# 防御:敌人攻击减伤为 90%,然后再应用翻倍倍率
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * 0.1 * enemy_mul()
print(f"{enemy.name} 攻击了你(被你防住大部分),造成 {int(damage)} 点伤害!"
f"(原始{int(raw_enemy_attack_value)} × 减伤0.1 × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
if player.not_dead():
print("You Win!")
else:
print("You Lose!")下面把这个无色进度条实现逐行、逐个设计点讲清楚。先放原函数,后面按行解释与举例:
def hp_bar(cur: int, maxv: int, width: int = 20) -> str:
"""返回形如:[##########----------] 50% 50/100 的进度条文本"""
if maxv <= 0:
maxv = 1
cur = max(0, min(cur, maxv))
ratio = cur / maxv
filled = int(ratio * width + 0.5) # 四舍五入
bar = "#" * filled + "-" * (width - filled)
return f"[{bar}] {int(ratio * 100):3d}% {cur}/{maxv}"逐行说明:
def hp_bar(cur: int, maxv: int, width: int = 20) -> str:cur:当前血量(current HP);maxv:最大血量(最大/满血);width:进度条宽度(字符格数),默认 20 格;纯 ASCII,不含颜色和特殊字符,Mac/Windows 任何终端都能显示。
代码:
if maxv <= 0: maxv = 1防御式编程:避免出现
maxv == 0导致后面cur / maxv除零错误。设置为 1 的意义:即便出现异常的“最大血量 ≤ 0”,也能安全渲染一个最小尺度的进度条。
cur = max(0, min(cur, maxv))- 钳制(clamp)当前值到合法范围
[0, maxv]:- 过量伤害导致的负值 → 拉回 0;
- 加成/溢出治疗导致的超上限 → 拉回
maxv。
- 这样可保证后续计算的比例和绘制不会越界。
- 钳制(clamp)当前值到合法范围
ratio = cur / maxv- 计算当前血量占比(0.0 ~ 1.0)。
- 由于上一步已钳制,
ratio一定在合法区间内。
filled = int(ratio * width + 0.5) # 四舍五入- 计算应该填充多少格(
#的数量)。 ratio * width给出“理想填充格数”的小数值;我们希望四舍五入到最近的整数。- 用
int(x + 0.5)而不是round(x)的原因:- Python 的
round是银行家舍入(.5向最近的偶数靠拢),例如round(8.5) == 8; int(x + 0.5)是更直觉的 “.5 及以上进一”:- 例:
8.5 → int(9.0) = 9。
- 例:
- 因为
ratio * width永不为负,此写法简单稳定。
- Python 的
- 计算应该填充多少格(
bar = "#" * filled + "-" * (width - filled)- 构造条形:左边
#表示当前血量,右边-表示未填充部分。 - 字符串乘法快速生成重复字符,O(width) 时间复杂度,足够轻量。
- 构造条形:左边
return f"[{bar}] {int(ratio * 100):3d}% {cur}/{maxv}"- 最终文本包含三部分:
- 方括号包裹的条形:
[##########----------] - 百分比:
{int(ratio * 100):3d}%- 这里用
int()而不是四舍五入:显示上更“保守”(例如 99.6% 显示 99%)。 :3d保证宽度 3 —— “ 5% / 50% / 100%”对齐更整齐。
- 这里用
- 数值形式:
cur/maxv(例:50/100),便于精确查看。
- 方括号包裹的条形:
- 最终文本包含三部分:
14.21.3 小例子(心算即可)
以
width = 20为例:cur=0, maxv=100ratio=0;filled=int(0*20+0.5)=0- 条:
[--------------------] 0% 0/100
cur=73, maxv=100ratio=0.73;filled=int(0.73*20+0.5)=int(14.6+0.5)=15- 条:
[###############-----] 73% 73/100(15 个#,5 个-)
cur=99, maxv=100ratio=0.99;filled=int(19.8+0.5)=20→ 条会满格- 百分比
int(99)=99%→ 可能出现“条已满但显示 99%”的轻微不一致(可接受)
cur=100, maxv=100ratio=1.0;filled=int(20+0.5)=20- 条:
[####################]100% 100/100
- 越界情况:
cur=-5→ 钳成 0;cur=120→ 钳成 100。
为什么它“跨平台稳”
- 只用 ASCII(
#、-、[]),不依赖颜色、宽字符或终端转义序列; - 不需要检测终端是否支持 ANSI 颜色,CMD / PowerShell / macOS 终端都能正常显示;
- 横向对齐通过固定
width和百分比字段宽度:3d达成。
可按需的小改动(可选)
让百分比与条形一致地“四舍五入”(而非取整):
pct = int(ratio * 100 + 0.5) return f"[{bar}] {pct:3d}% {cur}/{maxv}"这样 99.6% 会显示为 100%。
依据条形反推百分比(绝对一致):
pct = int((filled / width) * 100 + 0.5)这样条满一定显示 100%。
此处考虑玩家更依赖 50/100 的血量显示,因此条形和百分比的作用类似,且重要程度相当,所以可以保持一致。
条形反推百分比
pct = int((filled / width) * 100 + 0.5)其实在做一件很朴素的事:先看条形图实际“点亮了几格”(filled),再把它换算成百分比,最后做一个四舍五入。
1. 一句话版
进度条是“离散”的(比如一共 20 格,只能亮 0,1,2,…,20 格)。
既然条形显示是按“亮了几格”来的,那百分比也用亮格数去算,保证两者完全一致。
2. 为什么要“依据条形反推百分比”?
如果用真实比例算百分比,比如:
ratio = cur / maxv pct = int(ratio * 100) # 或 round(ratio * 100)而条形格数却是:
filled = int(ratio * width + 0.5) # 四舍五入到最近的格子这两处独立四舍五入,就可能出现不一致:
例子1(width=20):
cur=49, maxv=100 → ratio=0.49条形格数:
filled = int(0.49*20 + 0.5) = int(9.8 + 0.5) = 10(亮 10/20 格 = 50% 的“视觉”)百分比(真实比例取整):
int(0.49*100) = 49%⇒ 条形看起来是 50%,数字却写 49% —— 违和。
例子2(width=20):
cur=99, maxv=100 → ratio=0.99条形格数:
filled = int(0.99*20 + 0.5) = 20(满格)百分比(真实比例取整):
int(99) = 99%⇒ 满格但写 99% —— 又违和。
所以,用条形→百分比就不会有这种分裂:
filled/width是条形真正表达的占比,乘以 100 就是“条形所代表的百分比”。3. 这行代码逐词解释
pct = int((filled / width) * 100 + 0.5)filled / width:条形实际的占比(比如 10/20 = 0.5)。* 100:把占比变成百分数(0.5 → 50)。+ 0.5再int(...):对非负数实现“四舍五入”。(因为
int(x+0.5)等价于把 x 四舍五入到最近整数。)
这样得到的
pct,一定和你当前显示的格数对应的百分比一致。例如
filled = 10, width = 20 → pct = 50;filled = 20 → pct = 100。4. 何时该用这种写法?
- 你**希望数字和进度条外观“绝对一致”**时,用它!
- 这也意味着百分比只能是
0, 100/width, 2*100/width, ... 100这几档(比如width=20就是每 5% 一档)——和你的条形“档位”完全同步。
5. 放回函数里(示例)
def hp_bar(cur: int, maxv: int, width: int = 20) -> str: if maxv <= 0: maxv = 1 cur = max(0, min(cur, maxv)) ratio = cur / maxv filled = int(ratio * width + 0.5) # 先决定亮几格(条形外观) pct = int((filled / width) * 100 + 0.5) # 再用“亮格比例”算百分比,确保一致 bar = "#" * filled + "-" * (width - filled) return f"[{bar}] {pct:3d}% {cur}/{maxv}"这样,无论
cur/maxv是多少,小数怎么抖动,条形显示和数字都会说同一个“真相”。调整分辨率:
- 提高
width(如 30、40)→ 条形更“细腻”; - 降低
width(如 10)→ 更紧凑。
- 提高
一句话总结
- 钳制保证范围合法;
- 比例决定填充;
- 用
int(x+0.5)四舍五入避免银行家舍入; - 拼接 ASCII 构成稳定的跨平台进度条;
- 对齐格式让多次打印读起来更整齐。
银行家舍入
银行家舍入(Banker’s Rounding,也叫“四舍六入五留双 / 五成双”、“round half to even”)是一种在恰好落在中点时(小数部分正好是 0.5,或保留位后全是 0)把数值舍入到最接近的偶数的规则。它常用于金融与会计,目的是在大量数据汇总时消除系统性偏差(避免总是向上或总是向下)。
1. 规则一眼看懂
- 小于 0.5 → 舍(向下)
- 大于 0.5 → 入(向上)
- 等于 0.5 → 向最近的“偶数”舍入(关键!)
2. 快速例子(取整)
1.5 → 2(2 是偶数)2.5 → 2(2 是偶数)3.5 → 4(4 是偶数)4.5 → 4(4 是偶数)
负数也一样按“就近偶数”:
-1.5 → -2(-2 是偶数)-2.5 → -2(-2 是偶数)
3. 保留到指定位(看保留位后一位)
以保留两位小数为例(看“第三位”):
2.345→ 第三位是 5,第二位是 4(偶) →2.342.355→ 第三位是 5,第二位是 5(奇) →2.3612.1250→ 第三位是 5,第二位是 2(偶) →12.12
4. 为什么这么做?
- 在大规模求和/统计中,传统“四舍五入(0.5 一律进位)”会产生系统性偏大;
- “五留双(中点向偶数)”让上、下的机会更均衡,长期误差更小,因此银行、保险、审计等常用。
5. 在编程语言里的表现
Python 3:
round()对“正好在中点”的情况使用银行家舍入round(1.5) # 2 round(2.5) # 2 round(-1.5) # -2注意浮点表示误差:
round(2.675, 2) # 2.67(不是 2.68)因为 2.675 在二进制浮点中并不精确等于 2.675。要严格十进制舍入可用
decimal:from decimal import Decimal, ROUND_HALF_EVEN Decimal("2.675").quantize(Decimal("0.01"), rounding=ROUND_HALF_EVEN) # Decimal('2.68')Excel 的
ROUND默认是“0.5 远离 0 方向”而不是银行家舍入:ROUND(2.5, 0) = 3,ROUND(-2.5, 0) = -3。.NET:
Math.Round(x)默认也是“ToEven”(银行家舍入)。
6. 和代码里的关系
在进度条里我用了:
filled = int(ratio * width + 0.5) # 四舍五入这是一种**“0.5 一律进位”**的直觉四舍五入(且只针对非负数)。之所以不用 round(),是避免出现:
round(8.5) == 8 # 银行家舍入:到偶数 8对进度条视觉不符合期望(你会希望 8.5 更像 9 格)。
如果你想用银行家舍入来保证数学一致性,可改成:
filled = round(ratio * width) # Python 3 的 round 是“到偶数”7. 一句话记忆
“五留双”= 中点就近偶数。它让大量舍入后的总和更公平、更接近真实值。
9.4.10 使用 Faker 库随机生成敌人姓名
每轮游戏的敌人都应该是不同的,我们就做到名称不同即可~
Python Faker 是一个非常好用的库,可以快速生成各种“假数据”(名字、地址、电话、邮箱、公司、银行卡号。。。),在写测试、做原型、模拟数据库时特别方便。
9.4.10.1 Faker 的基础使用
pip install fakerfrom faker import Faker
# 创建一个 Faker 实例(默认是英文环境)
fake = Faker()
print(fake.name())
print(fake.address())
print(fake.email())
print(fake.text())运行结果示例:
Christine Taylor
673 April Causeway
Randychester, WI 72072
ljohnson@example.org
Many toward style person daughter keep. Attorney explain use baby fine situation character.
Task task director create former walk plant collection. Hot meet past letter modern difference.Faker 默认是英文,但是支持多语言。比如生成中文名字和地址:
from faker import Faker
# 创建一个 Faker 实例(默认是英文环境)
fake = Faker('zh_CN')
print(fake.name())
print(fake.address())
print(fake.phone_number())输出示例:
葛丹丹
台湾省深圳县六枝特郑州街Z座 871973
18753320376| 方法 | 说明 | 示例输出 |
|---|---|---|
fake.name() | 姓名 | 王伟 |
fake.address() | 地址 | 上海市徐汇区漕溪北路... |
fake.email() | 邮箱 | test@qq.com |
fake.phone_number() | 手机号 | 13912345678 |
fake.company() | 公司 | 腾讯科技有限公司 |
fake.job() | 职位 | 软件工程师 |
fake.date() | 随机日期 | 2025-09-16 |
fake.ipv4() | IPv4 地址 | 192.168.1.10 |
fake.url() | URL | https://example.com |
经常用在模拟数据库测试数据:
个人实现:
from faker import Faker
# 创建一个 Faker 实例(默认是英文环境)
fake = Faker('zh_CN')
i = 0
while i <= 4:
print(fake.name(), fake.phone_number(), fake.email())
i+=1老师实现:
from faker import Faker
# 创建一个 Faker 实例(默认是英文环境)
fake = Faker('zh_CN')
for _ in range(5):
print(fake.name(), fake.phone_number(), fake.email())from faker import Faker
# 创建一个 Faker 实例(默认是英文环境)
fake = Faker('zh_CN')
data = [
{
'id': i,
'name': fake.name(),
'email': fake.email(),
'address': fake.address(),
'job': fake.job(),
'company': fake.company(),
}
for i in range(1, 6)
]
for item in data:
print(item)输出示例:
{'id': 1, 'name': '王桂兰', 'email': 'jie73@example.org', 'address': '内蒙古自治区秀英市长寿郝路L座 966460', 'job': '其他', 'company': '明腾科技有限公司'}
{'id': 2, 'name': '张玉英', 'email': 'yongfan@example.net', 'address': '江西省兰州县门头沟李街k座 529875', 'job': '理货员', 'company': '恩悌网络有限公司'}
{'id': 3, 'name': '董宇', 'email': 'csong@example.net', 'address': '安徽省浩县牧野王街U座 814580', 'job': '资金经理/主管', 'company': '方正科技网络有限公司'}
{'id': 4, 'name': '刘秀芳', 'email': 'jiayan@example.net', 'address': '湖北省霞市城北席街n座 380078', 'job': '其他', 'company': '华成育卓科技有限公司'}
{'id': 5, 'name': '徐磊', 'email': 'daimin@example.com', 'address': '山东省静市清城辽阳路a座 476086', 'job': '脚本开发工程师', 'company': '毕博诚信息有限公司'}有时需要生成“固定不变”的假数据:
from faker import Faker
Faker.seed(1234) # 全局种子,数字随便设置
fake = Faker('zh_CN')
print(fake.name())
print(fake.name())每次运行都会输出一样的结果。
需要名字和邮箱的姓名保持一致,比如:
姓名:李娜 → 邮箱:lina@example.com
姓名:王刚 → 邮箱:wanggang@example.com这个就需要在生成邮箱时,根据名字来构造,而不是让 fake.email() 随机生成。
把中文名字转换成拼音,再拼接邮箱
常用方法是借助 pypinyin 库:
pip install pinyin代码如下:
from faker import Faker
import pandas as pd
from pypinyin import lazy_pinyin
fake = Faker('zh_CN')
users = []
for i in range(1, 11):
name = fake.name()
# 把中文名字转成拼音(list 转成字符串)
name_pinyin = ''.join(lazy_pinyin(name))
email = f'{name_pinyin}@example.com'
user = {
'ID': i,
'姓名': name,
'邮箱': email,
'手机号': fake.phone_number(),
'地址': fake.address(),
}
users.append(user)
df = pd.DataFrame(users)
df.to_csv('用户表数据.csv', index=False, encoding='utf-8-sig')
print(df.head())9.4.10.2 敌人姓名随机生成
在生成玩家和敌人时增加 Faker ,Faker 也需要先进行“实例化”,代码修改如下:
from faker import Faker
#---snip---
player = Creature(100, "AI悦创")
enemy_fake = Faker('zh_CN')
enemy = Creature(80, enemy_fake.name())目前完整代码:
import random
from faker import Faker
# —— 简单无色进度条(纯 ASCII,跨平台)——
def hp_bar(cur: int, maxv: int, width: int = 20) -> str:
"""返回形如:[##########----------] 50% 5g0/100 的进度条文本"""
if maxv <= 0:
maxv = 1
cur = max(0, min(cur, maxv))
ratio = cur / maxv
filled = int(ratio * width + 0.5) # 四舍五入
bar = "#" * filled + "-" * (width - filled)
return f"[{bar}] {int(ratio * 100):3d}% {cur}/{maxv}"
class Creature:
def __init__(self, hp, name):
self.hp = int(hp)
self.max_hp = int(hp) # 记录初始满血
self.name = name
def attack(self):
return random.randint(0, 50)
def not_dead(self):
return self.hp > 0
def being_attack(self, dmg: float):
"""受到伤害(向下取整以避免浮点 HP),并保证 HP 不会掉到负数以下"""
self.hp = max(0, int(self.hp - dmg))
def heal_full(self):
"""直接回到初始满血"""
self.hp = self.max_hp
def show_status(self):
print(f"{self.name}'s HP → {hp_bar(self.hp, self.max_hp)}")
fk = Faker(locale='zh_CN')
player = Creature(100, "AI悦创")
enemy = Creature(80, fk.name())
heal_used = False # 治疗仅限一次
heal_penalty_active = False # 是否已触发“敌人攻击翻倍”的惩罚
while player.not_dead() and enemy.not_dead():
player.show_status()
enemy.show_status()
# 是否出现治疗提示:仅当当前 HP < 初始 HP 的 50% 且尚未使用
can_heal_now = (not heal_used) and (player.hp < player.max_hp * 0.5)
if can_heal_now:
prompt = 'Attack or Defence or Heal (A/D/H):'
valid_inputs = {"A", "D", "H"}
print('(提示:你现在可以按 H 回满血,仅此一次)')
else:
prompt = 'Attack or Defence (A/D):'
valid_inputs = {"A", "D"}
if heal_penalty_active:
print('【警告】治疗代价生效中:敌人对你的伤害 ×2!')
user_input = input(prompt).strip().upper()
while user_input not in valid_inputs:
user_input = input("输入无效,请重新输入:" + prompt).strip().upper()
# 敌人选择(对 A/D 有影响;若玩家选择 H,我们让敌人本回合直接攻击)
enemy_status = ['Attack', 'Defence']
enemy_choice = random.choices(enemy_status, weights=[0.7, 0.3], k=1)[0] # 敌人更倾向于攻击
# 当前敌人伤害倍率(是否翻倍)
def enemy_mul():
return 2.0 if heal_penalty_active else 1.0
if user_input == "H":
# 只有在 can_heal_now 为 True 时才会进入到这里
print("你使用了治疗技能!血量已回满。")
player.heal_full()
heal_used = True
# 触发治疗代价:从现在起敌人攻击翻倍(包含本回合的随后的敌人攻击)
heal_penalty_active = True
# 敌人回合:直接攻击(先治再挨打)
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f"{enemy.name} 攻击了你,造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
elif user_input == "A":
player_attack_coefficient = 1
if enemy_choice == "Defence":
print(f"{enemy.name} chose to defend!")
player_attack_coefficient = 0.5
else:
print(f"{enemy.name} chose to attack!")
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * enemy_mul()
print(f"{enemy.name} 对你造成 {int(damage)} 点伤害!(原始{int(raw_enemy_attack_value)} × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
player_attack_value = player.attack()
enemy.being_attack(player_attack_value * player_attack_coefficient)
elif user_input == "D":
# 防御:敌人攻击减伤为 90%,然后再应用翻倍倍率
raw_enemy_attack_value = enemy.attack()
damage = raw_enemy_attack_value * 0.1 * enemy_mul()
print(f"{enemy.name} 攻击了你(被你防住大部分),造成 {int(damage)} 点伤害!"
f"(原始{int(raw_enemy_attack_value)} × 减伤0.1 × 倍率{enemy_mul():.0f})")
player.being_attack(damage)
if player.not_dead():
print("You Win!")
else:
print("You Lose!")更新日志
106e2-于39cab-于
