-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday21.py
executable file
·130 lines (101 loc) · 2.99 KB
/
day21.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#!/usr/bin/env python3
# [Day 21: RPG Simulator 20XX](https://adventofcode.com/2015/day/21)
import sys
from collections import namedtuple
from copy import deepcopy
from pathlib import Path
class Character:
def __init__(self, name, hitpoints=100, damage=0, armor=0) -> None:
self.name = name
self.hitpoints = hitpoints
self.damage = damage
self.armor = armor
def attack(self, enemy):
damage = max(0, self.damage - enemy.armor)
enemy.hitpoints -= damage
if enemy.hitpoints < 0:
enemy.hitpoints = 0
# print(
# f"The {self.name} deals {self.damage}-{enemy.armor} = {damage} damage;"
# f" the {enemy.name} goes down to {enemy.hitpoints} hit points."
# )
def combat(c1: Character, c2: Character):
while True:
c1.attack(c2)
if c2.hitpoints == 0:
return 1
c2.attack(c1)
if c1.hitpoints == 0:
return 2
Item = namedtuple("Item", ("cost", "damage", "armor"))
def parse(s: str):
t = []
for line in s.splitlines():
line = line.strip()
if not line:
continue
item = Item(*map(int, line.split()[-3:]))
t.append(item)
return t
filename = ("test.txt" if sys.argv[1] == "-t" else sys.argv[1]) if len(sys.argv) > 1 else "input.txt"
data = Path(filename).read_text().strip()
lines = data.splitlines()
boss = Character("boss")
for line in lines:
k, v = line.split(":")
match k:
case "Hit Points":
boss.hitpoints = int(v)
case "Damage":
boss.damage = int(v)
case "Armor":
boss.armor = int(v)
weapons = parse(
"""
Dagger 8 4 0
Shortsword 10 5 0
Warhammer 25 6 0
Longsword 40 7 0
Greataxe 74 8 0
"""
)
armors = parse(
"""
Leather 13 0 1
Chainmail 31 0 2
Splintmail 53 0 3
Bandedmail 75 0 4
Platemail 102 0 5
"""
)
rings = parse(
"""
Damage +1 25 1 0
Damage +2 50 2 0
Damage +3 100 3 0
Defense +1 20 0 1
Defense +2 40 0 2
Defense +3 80 0 3
"""
)
armors.append(Item(0, 0, 0))
rings.append(Item(0, 0, 0))
min_win_cost = 100000
max_loose_cost = 0
for w in weapons:
for a in armors:
for r1 in rings:
for r2 in rings:
# cannot buy two same rings
if r1 == r2:
continue
cost = w.cost + a.cost + r1.cost + r2.cost
damage = w.damage + a.damage + r1.damage + r2.damage
armor = w.armor + a.armor + r1.armor + r2.armor
player = Character("player", 100, damage, armor)
if combat(player, deepcopy(boss)) == 1:
min_win_cost = min(min_win_cost, cost)
else:
max_loose_cost = max(max_loose_cost, cost)
print(min_win_cost)
print(max_loose_cost)