21_rpg.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #!/usr/bin/env python3
  2. from collections import namedtuple
  3. from itertools import combinations
  4. from copy import copy
  5. class Shop:
  6. Item = namedtuple('Item', ['cost', 'damage', 'armor'])
  7. weapons = [Item( 8, 4, 0), Item( 10, 5, 0), Item( 25, 6, 0),
  8. Item( 40, 7, 0), Item( 74, 8, 0)]
  9. armors = [Item( 13, 0, 1), Item( 31, 0, 2), Item( 53, 0, 3),
  10. Item( 75, 0, 4), Item(102, 0, 5)]
  11. rings = [Item( 25, 1, 0), Item( 50, 2, 0), Item(100, 3, 0),
  12. Item( 20, 0, 1), Item( 40, 0, 2), Item( 80, 0, 3)]
  13. @classmethod
  14. def item_combos(cls):
  15. for nrings in range(0, 3):
  16. for rings in map(list, combinations(cls.rings, nrings)):
  17. for weapon in cls.weapons:
  18. yield [weapon] + rings
  19. for armor in cls.armors:
  20. yield [weapon, armor] + rings
  21. @classmethod
  22. def weighted_combos(cls):
  23. for items in cls.item_combos():
  24. yield sum(item.cost for item in items), items
  25. class Player:
  26. def __init__(self, hp, damage, armor):
  27. self.hp = hp
  28. self.damage = damage
  29. self.armor = armor
  30. def attack(self, other):
  31. other.hp -= max(self.damage - other.armor, 1)
  32. def alive(self):
  33. return self.hp > 0
  34. def with_items(self, items):
  35. newme = copy(self)
  36. for item in items:
  37. newme.damage += item.damage
  38. newme.armor += item.armor
  39. return newme
  40. def fight(self, other):
  41. attacker = self
  42. defender = other
  43. while attacker.alive() and defender.alive():
  44. attacker.attack(defender)
  45. attacker, defender = defender, attacker
  46. return self.alive()
  47. me = Player(100, 0, 0)
  48. boss = Player(104, 8, 1)
  49. # part 1
  50. combos = sorted(Shop.weighted_combos())
  51. for cost, items in combos:
  52. if me.with_items(items).fight(copy(boss)):
  53. print(cost)
  54. break
  55. # part 2
  56. for cost, items in reversed(combos):
  57. if not me.with_items(items).fight(copy(boss)):
  58. print(cost)
  59. break