我必须使用2个类来完成某种游戏,
“部队”是在我们虚拟战争中战斗的士兵。单位将由python中称为Unit的类定义。对于尼克战争,我们的部队将具有以下属性:
Team-一个字符串,指示该单位属于哪个团队。这将始终是“红色”或“蓝色”。必须初始化。 HP-生命值/健康/能量/活力。单位被杀死之前可以承受的伤害量。单位无法恢复或恢复HP。必须初始化。 ATT-攻击/力量。一次击中一个单位可以造成的伤害量。必须初始化。 Attack_timeout-两次攻击之间必须经过的时间,以滴答度数为单位(请参见下面的方法)。必须初始化。 isDead-如果此单元已死,则为True;如果存在,则为False。初始化为False。 方法:
tick(自己,对手)-每次调用tick,我们都会模拟一个时间单位经过游戏场景。此处定义了单元的任何“自动”行为(因此,我们实质上是对单元AI进行编程)。参数对手是有效攻击目标的所有单位的列表。如果isDead为False,则必须创建以下行为。死单元将不执行任何这些行为,并立即返回整数值0。 如果对手名单中有活单位,则该单位攻击HP最低的单位(请参阅攻击方法)。在这种情况下,此方法返回整数值0。如果多个单位具有相同的HP,请在相对单位列表中使用具有该HP的第一个单位。 如果对手列表为空或不包含任何生存单位,则返回该单位的攻击值。稍后将用于计算对敌人基地的伤害。 如果自本机上次攻击以来已达到指定的滴答数,则只能执行上述两个操作。如何保持尝试作为练习留给读者。 Attack(self,other)-当本单位(自身)攻击防御单位(其他)时调用。防御单位的生命值被其单位的攻击值降低。如果这会使防御单位的HP降低到零或超过零,则将isDead设置为True。
我已经完成了这一部分,看起来像这样
class Unit:
def __init__(self,Team,HP,ATT,attack_timeout,isDead = False):
self.Team = Team
self.HP = HP
self.ATT = ATT
self.attack_timeout = attack_timeout
self.isDead = isDead
self.lastuse = attack_timeout
def attack(self,other):
self.lastuse = 0
other.HP -= self.ATT
if other.HP <= 0:
other.isDead = True
def tick(self,opponents):
if self.isDead == True:
return 0
else:
healths = []
lowest = None
if not opponents:
self.lastuse = 0
return self.ATT
if self.lastuse == self.attack_timeout:
for i in opponents:
healths.append(i.HP)
if sum(healths)<=0:
self.lastuse = 0
return self.ATT
else:
for i in opponents:
if lowest == None or i.HP < lowest:
lowest = i.HP
for j in opponents:
if j.HP == lowest:
break
Unit.attack(self,j)
return (0)
self.lastuse += 1
return 0
给我带来困难的第二部分是在下面给出的军队课程中使用该课程
由于将在两个相对的军队之间重用许多代码,因此将它们封装为自己的类是很有意义的。
定义具有以下属性和方法的陆军课程:
属性:
Team-一个字符串,指示该单位属于哪个团队。这将始终是“红色”或“蓝色”。必须初始化。 BaseHP-陆军基地剩余的生命值。初始化到1000 GoldRate-军队每跳获得的金数。初始化为10。 黄金-团队用于购买单位和增加GoldRate的黄金数量。初始化为0。 名册-词典列表,用于指定可购买的单位的属性。必须初始化。 价格-单位成本的黄金数量 HP-单位起始的生命值 ATT-单位的攻击力 Attack_timeout-单元必须在两次攻击之间等待的时间。 单位-当前存在的单位对象列表。 方法:
勾号(self,opponents)-除self之外,还列出了另一支队伍的单位对手。调用“单位”列表中每个单位的报价方法,并传递每个对手列表。每个单位的tick方法的返回值表示对对手基地造成的伤害量。计算这些返回值的总和,然后从此tick方法返回该总和。此外,团队的黄金价值会随着GoldRate的价值而增加。 BuryDead(self)-从“单位”列表中删除isDead为True的所有单位。 BuyGoldRate(self)-如果团队拥有超过250金,则将团队的黄金减少250,并将GoldRate加2。 BuyUnit(self,x)-x是一个整数,指示要购买的名册中单位的索引。如果团队的黄金量大于或等于x所指定单位的价格值,则使用花名册条目中指定的属性初始化新的单位,并将其添加到“单位”列表中。如果指定的名册项目不存在,则引发NoSuchUnitError异常。如果没有足够的黄金来购买该装置,请创建一个TooPoorError异常。我尝试这样做
class TooPoorError (Exception):
pass
class NoSuchUnitError (Exception):
pass
class Army(Unit):
def __init__ (self,Team,Roster,BaseHP = 1000,GoldRate = 10,Gold = 0):
self.Team = Team
self.BaseHP = BaseHP
self.GoldRate = GoldRate
self.Gold = Gold
self.Roster = Roster
self.Units = []
def tick (self,opponents):
self.Gold += self.GoldRate
for i in self.Units:
return (Unit.tick(i,opponents))
def BuryDead(self):
pass
def BuyGoldRate(self):
if self.Gold>=250:
self.GoldRate += 2
self.Gold-= 250
def BuyUnit(self, x):
if self.Gold>=self.Roster[x]["Price"]:
self.Gold -= self.Roster[x]["Price"]
self.Units.append(Unit(self,self.Roster[x]["HP"],self.Roster[x]["ATT"],self.Roster[x]["attack_timeout"]) )
if self.Gold<self.Roster[x]["Price"]:
raise TooPoorError
我在使用上一个类时遇到麻烦,无法运行tick函数并始终获得0的返回值
测试用例如下:
#Visible test
RedArmy = Army('Red', [{'Price': 20, 'HP': 100, 'ATT': 7, 'attack_timeout': 3},
{'Price': 15, 'HP': 70, 'ATT': 5, 'attack_timeout': 2}])
BlueArmy = Army('Blue', [{'Price': 13, 'HP': 60, 'ATT': 4, 'attack_timeout': 1},
{'Price': 16, 'HP': 80, 'ATT': 6, 'attack_timeout': 3}])
# Collecting gold
for i in range(30):
RedArmy.tick([])
BlueArmy.tick([])
RedArmy.BuyGoldRate()
BlueArmy.BuyGoldRate()
for i in range(5):
RedArmy.tick([])
BlueArmy.tick([])
# Training the army
RedArmy.BuyUnit(0)
RedArmy.BuyUnit(0)
RedArmy.BuyUnit(1)
BlueArmy.BuyUnit(1)
BlueArmy.BuyUnit(1)
BlueArmy.BuyUnit(1)
BlueArmy.BuyUnit(0)
print('Gold calculation for Blue: --------', BlueArmy.Gold == 49)
print('Gold calculation for Red: ---------', RedArmy.Gold == 55)
# Fight
BlueDamage = 0
RedDamage = 0
BlueUnits_HP = []
BlueUnits_Dead = []
RedUnits_HP = []
RedUnits_Dead = []
for i in range(80):
BlueDamage += RedArmy.tick(BlueArmy.Units)
RedDamage += BlueArmy.tick(RedArmy.Units)
for u in BlueArmy.Units:
BlueUnits_HP += [u.HP]
BlueUnits_Dead += [u.isDead]
for u in RedArmy.Units:
RedUnits_HP += [u.HP]
RedUnits_Dead += [u.isDead]
print('Damage calcultion for Blue: -------', BlueDamage == 0)
print('Damage calcultion for Red: --------', RedDamage == 42)
print('Blue units HP: --------------------', BlueUnits_HP == [-4, 31, 80, -4] or BlueUnits_HP == [0, 31, 80, 0])
print('Blue units status: ----------------', BlueUnits_Dead == [True, False, False, True])
print('Red units HP: ---------------------', RedUnits_HP == [-4, -2, 0] or RedUnits_HP == [0, 0, 0])
print('Red units status: -----------------', RedUnits_Dead == [True, True, True])
答案 0 :(得分:2)
这是很有趣的代码! 我必须进行一些更改才能使其正常运行,部分原因是为了了解正在发生的事情并使代码更具Python风格。我对各种方法的预期目的/您希望攻击优先级如何发挥作用进行了一些假设,但我将解释所有内容并尝试证明所有理由。
常规 在整个过程中,我已从CamelCase切换到snake_case以获取变量名,并已通过linter传递了代码,以使其与Python PEP 8样式指南保持一致。
添加了TooPoorError
class NoSuchUnitError(Exception):
pass
class TooPoorError(Exception):
pass
军队
添加了保护条款,以在购买单位时引发例外情况。
更改了滴答的工作方式-现在您可以将其称为army.tick()
来推进金币,或者通过另一支军队与之战斗。您打勾的方式有点怪异,所以我不确定这是否是给您0回报的原因?您可以仅循环army.units
中的单位,并针对每个unit
,针对对手调用tick
方法。我使用列表理解来执行此循环并求和输出损害。我认为您可能会遇到一些问题,因为您正在返回第一个单元“ tick”的输出并杀死了循环。
您也从部队继承而来-我不会说陆军是一个部队,而是陆军是一个部队。
class Army:
def __init__(self, team, roster, hp=1000, gold_rate=10, gold=0):
self.team = team
self.hp = hp
self.gold_rate = gold_rate
self.gold = gold
self.roster = roster
self.units = []
def tick(self, opponents=None):
self.gold += self.gold_rate
if opponents is not None:
return sum([unit.tick(opponents) for unit in self.units])
def buy_gold_rate(self):
if self.gold >= 250:
self.gold_rate += 2
self.gold -= 250
def buy_unit(self, x):
if self.gold < self.roster[x]["Price"]:
raise TooPoorError
if x > len(self.roster):
raise NoSuchUnitError
self.gold -= self.roster[x]["Price"]
self.units.append(Unit(self.roster[x]["HP"], self.roster[x]["ATT"],
self.roster[x]["attack_timeout"]))
单位
删除了以关键字形式传递的团队,以清除一些未使用的内容。删除了isDead参数(您是否会创建一个开始失效的新Unit?)。
Guard子句是减少缩进量的一种好方法,我在tick
方法中加入了一些。我还添加了一个属性,该属性有助于简化对设备是否处于冷却状态的跟踪。
class Unit:
def __init__(self, hp, attack_strength, attack_timeout):
self.hp = hp
self.attack_strength = attack_strength
self.attack_timeout = attack_timeout
self._last_use = attack_timeout
self.is_dead = False
def attack(self, other):
self.lastuse = 0
other.hp -= self.attack_strength
if other.hp <= 0:
other.hp = 0
other.is_dead = True
def tick(self, opponent):
#
if self.is_dead:
return 0
if self.on_cooldown:
self._last_use += 1
return 0
# Find out if any opposing units are alive
if all([unit.is_dead for unit in opponent.units]):
self._last_use = 0
return self.attack_strength
else:
lowest_hp = 1e10
for unit in opponent.units:
if unit.hp < lowest_hp and not unit.is_dead:
lowest = unit
lowest_hp = unit.hp
self.attack(lowest)
self._last_use = 0
return 0
@property
def on_cooldown(self):
if self._last_use != self.attack_timeout:
return True
else:
return False
以下是更新的测试:
red_army = Army('Red', [{'Price': 20, 'HP': 100, 'ATT': 7, 'attack_timeout': 3},
{'Price': 15, 'HP': 70, 'ATT': 5, 'attack_timeout': 2}])
blue_army = Army('Blue', [{'Price': 13, 'HP': 60, 'ATT': 4, 'attack_timeout': 1},
{'Price': 16, 'HP': 80, 'ATT': 6, 'attack_timeout': 3}])
# Collecting gold
for _ in range(30):
red_army.tick()
blue_army.tick()
red_army.buy_gold_rate()
blue_army.buy_gold_rate()
for _ in range(5):
red_army.tick()
blue_army.tick()
# Training the army
red_army.buy_unit(0)
red_army.buy_unit(0)
red_army.buy_unit(1)
blue_army.buy_unit(1)
blue_army.buy_unit(1)
blue_army.buy_unit(1)
blue_army.buy_unit(0)
print('Gold calculation for Blue: --------', blue_army.gold == 49)
print('Gold calculation for Red: ---------', red_army.gold == 55)
# Fight
blue_damage = 0
red_damage = 0
for i in range(80):
blue_damage += red_army.tick(blue_army)
red_damage += blue_army.tick(red_army)
blue_units_hp = [unit.hp for unit in blue_army.units]
blue_units_dead = [unit.is_dead for unit in blue_army.units]
red_units_hp = [unit.hp for unit in red_army.units]
red_units_dead = [unit.is_dead for unit in red_army.units]
print('Damage calculation for Blue: ---', blue_damage == 0)
print('Damage calculation for Red: ----', red_damage == 42)
print('Blue units HP: -----------------', blue_units_hp == [0, 31, 80, 0])
print('Blue units status: -------------', blue_units_dead == [True, False, False, True])
print('Red units HP: ------------------', red_units_hp == [0, 0, 0])
print('Red units status: --------------', red_units_dead == [True, True, True])