from collections import namedtuple import itertools def play(spell, state): is_win = 0 hp, mp, boss_hp, boss_dmg, turns, mp_spent, is_hard = state for turn in (spell, None): # prelude if turn is not None and is_hard: hp -= 1 if hp <= 0: is_win = -1 break if 'r' in turns[-5:]: mp += 101 if 'p' in turns[-6:]: boss_hp -= 3 if boss_hp <= 0: is_win = 1 break # action if turn == 'm': mp_spent += 53 boss_hp -= 4 elif turn == 'd': mp_spent += 73 boss_hp -= 2 hp += 2 elif turn == 's': mp_spent += 113 if 's' in turns[-5:]: is_win = -1 break elif turn == 'p': mp_spent += 173 if 'p' in turns[-5:]: is_win = -1 break elif turn == 'r': mp_spent += 229 if 'r' in turns[-4:]: is_win = -1 break elif turn == None: hp -= max(boss_dmg - 7 if 's' in turns[-6:] else boss_dmg, 1) turns += (turn,) # denouement if mp_spent > mp: is_win = -1 break if boss_hp <= 0: is_win = 1 break if hp <= 0: is_win = -1 break return is_win, State(hp, mp, boss_hp, boss_dmg, turns, mp_spent, is_hard) State = namedtuple('State', 'hp,mp,boss_hp,boss_dmg,turns,mp_spent,is_hard') boss_hp, boss_dmg = map(int, re.findall(r'\d+', text)) pending, wins = [State(50, 500, boss_hp, boss_dmg, tuple(), 0, False)], set() while not wins: outcomes = [play(spell, state) for state in pending for spell in 'mdspr'] wins |= {state for is_win, state in outcomes if is_win == 1} pending = [state for is_win, state in outcomes if is_win == 0] ans1 = min(win.mp_spent for win in wins) pending, wins = [State(50, 500, boss_hp, boss_dmg, tuple(), 0, True)], set() while not wins: outcomes = [play(spell, state) for state in pending for spell in 'mdspr'] wins |= {state for is_win, state in outcomes if is_win == 1} pending = [state for is_win, state in outcomes if is_win == 0] ans2 = min(win.mp_spent for win in wins)