In [2]:
# Boss
# Hit Points: 55
# Damage: 8
class Player(object):
def __init__(self, hp, mana, damage, armor):
self.hp = hp
self.mana = mana
self.damage = damage
self.armor = armor
me = Player(50, 500, 0, 0)
boss = Player(55, 0, 8, 0)
In [37]:
class Spell(object):
@classmethod
def cost(cls):
return 0
@classmethod
def duration(cls):
return 0
def __init__(self, me, boss):
self.me = me
self.boss = boss
self.cost = type(self).cost()
self.started = False
def effect(self):
assert False
def cast(self):
if self.started:
return False
# print 'Spell: ', type(self).__name__
self.started = True
self.me.mana -= self.cost
self.effect()
return True
class MagicMissile(Spell):
@classmethod
def cost(cls):
return 53
def __init__(self, me, boss):
super(MagicMissile, self).__init__(me, boss)
def effect(self):
self.boss.hp -= max(1, 4 - boss.armor)
class Die(Spell):
@classmethod
def cost(cls):
return 0
def __init__(self, me, boss):
super(Die, self).__init__(me, boss)
def effect(self):
self.me.hp = 0
test = MagicMissile(me, boss)
test.cast()
type(test).duration()
class Drain(Spell):
@classmethod
def cost(cls):
return 73
def __init__(self, me, boss):
super(Drain, self).__init__(me, boss)
def effect(self):
self.boss.hp -= max(1, 2 - boss.armor)
self.me.hp += 2
test = Drain(me, boss)
test.cast()
class Effect(Spell):
@classmethod
def cost(cls):
return 0
@classmethod
def duration(cls):
assert False
def __init__(self, me, boss):
super(Effect, self).__init__(me, boss)
self.duration = type(self).duration()
def done(self):
pass
def cast(self):
if not self.started:
self.started = True
self.me.mana -= type(self).cost()
return True
if 0 < self.duration:
# print 'Effect: ', type(self).__name__
self.effect()
self.duration -= 1
return True
if 0 == self.duration:
self.done()
self.duration -= 1
return False
return False
# test = Effect(me, boss)
# test.cast()
class Shield(Effect):
@classmethod
def cost(cls):
return 113
@classmethod
def duration(cls):
return 6
def __init__(self, me, boss):
super(Shield, self).__init__(me, boss)
self.active = False
def effect(self):
if not self.active:
self.me.armor += 7
self.active = True
def done(self):
if self.active:
self.me.armor -= 7
self.active = False
test = Shield(me, boss)
test.cast()
class Poison(Effect):
@classmethod
def cost(cls):
return 173
@classmethod
def duration(cls):
return 6
def __init__(self, me, boss):
super(Poison, self).__init__(me, boss)
def effect(self):
self.boss.hp -= 3
test = Poison(me, boss)
test.cast()
class Recharge(Effect):
@classmethod
def cost(cls):
return 229
@classmethod
def duration(cls):
return 5
def __init__(self, me, boss):
super(Recharge, self).__init__(me, boss)
def effect(self):
self.me.mana += 101
test = Recharge(me, boss)
test.cast()
Out[37]:
In [35]:
from copy import deepcopy
def duel(me, boss, spells, dbg=False):
me = deepcopy(me)
boss = deepcopy(boss)
spells = [cls(me, boss) for cls in spells]
def effects(count):
[spell.cast() for spell in spells[:count]]
def cast(count):
if len(spells) < count:
return False
spells[count - 1].cast()
return True
def check():
if dbg:
print 'Boss hp: ', boss.hp
print 'Me hp: ', me.hp
print 'Me mana: ', me.mana
if me.hp <= 0:
return False, (False, 'hp')
if me.mana < 0:
return False, (False, 'mana')
if boss.hp <= 0:
return False, (True, 'win!')
return True, None
round = 0
while True:
round += 1
if dbg:
print '== My turn =='
me.hp -= 1
res, ret = check()
if not res:
return ret
effects(round - 1)
res, ret = check()
if not res:
return ret
if not cast(round):
return False, 'no spells'
res, ret = check()
if not res:
return ret
if dbg:
print '== Boss\'s turn =='
effects(round)
res, ret = check()
if not res:
return ret
me.hp -= max(1, boss.damage - me.armor)
res, ret = check()
if not res:
return ret
In [34]:
me = Player(10, 250, 0, 0)
boss = Player(13, 0, 8, 0)
duel(me, boss, [Poison, MagicMissile])
Out[34]:
In [27]:
me = Player(10, 250, 0, 0)
boss = Player(14, 0, 8, 0)
duel(me, boss, [Recharge, Shield, Drain, Poison, MagicMissile])
Out[27]:
In [50]:
me = Player(50, 500, 0, 0)
boss = Player(55, 0, 8, 0)
all_spells = [Recharge, Shield, Drain, Poison, MagicMissile]
ret = None
best_spells = None
reasons = {}
def f(spells):
global ret
# print 'Depth: ', len(spells)
if 13 < len(spells):
return None
result, reason = duel(me, boss, spells)
if reason not in reasons:
reasons[reason] = 0
cost = sum([spell.cost() for spell in spells])
reasons[reason] += 1
if result:
if ret is None or cost < ret:
ret = cost
best_spells = spells
# print 'Duel!'
# print [spell.__name__ for spell in spells]
# duel(me, boss, spells, True)
print ret, len(spells)
print [spell.__name__ for spell in best_spells]
# print
if reason == 'no spells' and (ret is None or cost < ret):
for spell in all_spells:
# print spell
# print spells[-spell.duration():]
d = spell.duration()
if d < 3 or spell not in spells[-((d - 1) / 2):]:
f(spells + [spell])
f([])
print ret
print reasons
# between 953 and 1295