Skip to content

Commit 8fcb2d3

Browse files
committed
Performance improvements -- all days run below 60 sec now
1 parent e63baf5 commit 8fcb2d3

8 files changed

+934
-426
lines changed

2015/22-Wizard Simulator 20XX.py

Lines changed: 115 additions & 275 deletions
Large diffs are not rendered by default.

2015/22-Wizard Simulator 20XX.v1.py

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
# -------------------------------- Input data -------------------------------- #
2+
import os, itertools, random
3+
4+
test_data = {}
5+
6+
test = 1
7+
test_data[test] = {
8+
"input": """""",
9+
"expected": ["Unknown", "Unknown"],
10+
}
11+
12+
test += 1
13+
test_data[test] = {
14+
"input": """""",
15+
"expected": ["Unknown", "Unknown"],
16+
}
17+
18+
test = "real"
19+
test_data[test] = {
20+
"input": "",
21+
"expected": ["900", "1216"],
22+
}
23+
24+
# -------------------------------- Control program execution -------------------------------- #
25+
26+
case_to_test = 1
27+
part_to_test = 2
28+
verbose_level = 1
29+
30+
# -------------------------------- Initialize some variables -------------------------------- #
31+
32+
puzzle_input = test_data[case_to_test]["input"]
33+
puzzle_expected_result = test_data[case_to_test]["expected"][part_to_test - 1]
34+
puzzle_actual_result = "Unknown"
35+
36+
37+
# -------------------------------- Actual code execution -------------------------------- #
38+
39+
40+
spells = {
41+
# Cost, Duration, Damage, Heal, Armor, Mana
42+
"M": [53, 1, 4, 0, 0, 0],
43+
"D": [73, 1, 2, 2, 0, 0],
44+
"S": [113, 6, 0, 0, 7, 0],
45+
"P": [173, 6, 3, 0, 0, 0],
46+
"R": [229, 5, 0, 0, 0, 101],
47+
}
48+
49+
# Mana, HP, Armor
50+
init_player_stats = [500, 50, 0]
51+
# HP, Damage
52+
init_boss_stats = [51, 9]
53+
init_counters = {"S": 0, "P": 0, "R": 0}
54+
55+
# Maximum mana used - initially 10 ** 6, reduced with manual tests / strategy
56+
min_mana_used = 1300
57+
58+
59+
def apply_effects(counters, player_stats, boss_stats):
60+
global spells
61+
62+
for effect in counters:
63+
if counters[effect] == 0:
64+
if effect == "S":
65+
player_stats[2] = 0
66+
continue
67+
else:
68+
if effect == "S":
69+
player_stats[2] = spells[effect][4]
70+
else:
71+
boss_stats[0] -= spells[effect][2]
72+
player_stats[0] += spells[effect][5]
73+
74+
counters[effect] -= 1
75+
76+
return [counters, player_stats, boss_stats]
77+
78+
79+
if part_to_test == 1:
80+
count_strategies = 5 ** 10
81+
for strategy in itertools.product(spells.keys(), repeat=10):
82+
count_strategies -= 1
83+
print(
84+
"Min mana :",
85+
min_mana_used,
86+
"###### Strategy #",
87+
count_strategies,
88+
":",
89+
strategy,
90+
)
91+
if "S" not in strategy[0:5] or "R" not in strategy[0:5]:
92+
continue
93+
counters = init_counters.copy()
94+
player_stats = init_player_stats.copy()
95+
boss_stats = init_boss_stats.copy()
96+
mana_used = 0
97+
98+
for player_action in strategy:
99+
# Player turn
100+
if part_to_test == 2:
101+
player_stats[1] -= 1
102+
if player_stats[1] <= 0:
103+
if verbose_level >= 2:
104+
print("Boss wins")
105+
break
106+
107+
# Apply effects
108+
counters, player_stats, boss_stats = apply_effects(
109+
counters, player_stats, boss_stats
110+
)
111+
if verbose_level >= 2:
112+
print("### Player turn - Player casts", player_action)
113+
print(counters, player_stats, boss_stats)
114+
115+
# Apply player move
116+
if spells[player_action][0] > player_stats[0]:
117+
if verbose_level >= 2:
118+
print("Aborting: not enough mana")
119+
break
120+
if spells[player_action][1] == 1:
121+
player_stats[1] += spells[player_action][3]
122+
boss_stats[0] -= spells[player_action][2]
123+
else:
124+
if counters[player_action] != 0:
125+
if verbose_level >= 2:
126+
print("Aborting: reused " + player_action)
127+
break
128+
else:
129+
counters[player_action] = spells[player_action][1]
130+
# Mana usage
131+
player_stats[0] -= spells[player_action][0]
132+
mana_used += spells[player_action][0]
133+
if verbose_level >= 2:
134+
print(counters, player_stats, boss_stats)
135+
136+
if boss_stats[0] <= 0:
137+
if verbose_level >= 2:
138+
print("Player wins with", mana_used, "mana used")
139+
min_mana_used = min(min_mana_used, mana_used)
140+
break
141+
if mana_used > min_mana_used:
142+
print("Aborting: too much mana used")
143+
break
144+
145+
# Boss turn
146+
# Apply effects
147+
counters, player_stats, boss_stats = apply_effects(
148+
counters, player_stats, boss_stats
149+
)
150+
if verbose_level >= 2:
151+
print("### Boss turn")
152+
print(counters, player_stats, boss_stats)
153+
154+
player_stats[1] -= boss_stats[1] - player_stats[2]
155+
if verbose_level >= 2:
156+
print(counters, player_stats, boss_stats)
157+
158+
if player_stats[1] <= 0:
159+
if verbose_level >= 2:
160+
print("Boss wins")
161+
break
162+
else:
163+
max_moves = 15
164+
pruned_strategies = []
165+
count_strategies = 5 ** max_moves
166+
167+
# This code is not very efficient, becuase it changes the last spells first (and those are likely not to be used because we finish the combat or our mana before that)...
168+
169+
for strategy in itertools.product(spells.keys(), repeat=max_moves):
170+
count_strategies -= 1
171+
if "S" not in strategy[0:4] or "R" not in strategy[0:5]:
172+
if verbose_level >= 2:
173+
print(" Missing Shield or Recharge")
174+
continue
175+
if any(
176+
[True for i in range(1, max_moves) if strategy[0:i] in pruned_strategies]
177+
):
178+
print(" Pruned")
179+
continue
180+
181+
if verbose_level >= 2:
182+
print(
183+
"Min mana :",
184+
min_mana_used,
185+
"###### Strategy #",
186+
count_strategies,
187+
"- pruned: ",
188+
len(pruned_strategies),
189+
"-",
190+
strategy,
191+
)
192+
shield_left = 0
193+
poison_left = 0
194+
recharge_left = 0
195+
player_hp = 50
196+
player_mana = 500
197+
player_armor = 0
198+
mana_used = 0
199+
boss_hp = 51
200+
boss_dmg = 9
201+
202+
for player_action in strategy:
203+
204+
# Player turn
205+
player_hp -= 1
206+
if player_hp <= 0:
207+
if verbose_level >= 2:
208+
print("Boss wins")
209+
# pruned_strategies.append(tuple(actions_done))
210+
break
211+
212+
# actions_done += tuple(player_action)
213+
214+
# Apply effects
215+
if shield_left > 0:
216+
player_armor = 7
217+
shield_left -= 1
218+
else:
219+
player_armor = 0
220+
if poison_left > 0:
221+
boss_hp -= 3
222+
poison_left -= 0
223+
if recharge_left:
224+
player_mana += 101
225+
recharge_left -= 1
226+
227+
# Apply player move
228+
if spells[player_action][0] > player_mana:
229+
if verbose_level >= 2:
230+
print("Aborting: not enough mana")
231+
# pruned_strategies.append(actions_done)
232+
break
233+
# Missile
234+
if player_action == "M":
235+
player_mana -= 53
236+
mana_used += 53
237+
boss_hp -= 4
238+
# Drain
239+
elif player_action == "D":
240+
player_mana -= 73
241+
mana_used += 73
242+
boss_hp -= 2
243+
player_hp += 2
244+
# Shield
245+
elif player_action == "S":
246+
if shield_left != 0:
247+
if verbose_level >= 2:
248+
print("Aborting: reused " + player_action)
249+
# pruned_strategies.append(actions_done)
250+
break
251+
else:
252+
shield_left = 6
253+
# Poison
254+
elif player_action == "P":
255+
if poison_left != 0:
256+
if verbose_level >= 2:
257+
print("Aborting: reused " + player_action)
258+
# pruned_strategies.append(actions_done)
259+
break
260+
else:
261+
poison_left = 6
262+
# Recharge
263+
elif player_action == "R":
264+
if recharge_left != 0:
265+
if verbose_level >= 2:
266+
print("Aborting: reused " + player_action)
267+
# pruned_strategies.append(actions_done)
268+
break
269+
else:
270+
shield_left = 5
271+
272+
if boss_hp <= 0:
273+
if verbose_level >= 2:
274+
print("Player wins with", mana_used, "mana used")
275+
min_mana_used = min(min_mana_used, mana_used)
276+
break
277+
if mana_used > min_mana_used:
278+
if verbose_level >= 2:
279+
print("Aborting: too much mana used")
280+
break
281+
282+
# Boss turn
283+
# Apply effects
284+
if shield_left > 0:
285+
player_armor = 7
286+
shield_left -= 1
287+
else:
288+
player_armor = 0
289+
if poison_left > 0:
290+
boss_hp -= 3
291+
poison_left -= 0
292+
if recharge_left:
293+
player_mana += 101
294+
recharge_left -= 1
295+
296+
player_hp -= boss_dmg - player_armor
297+
298+
if player_hp <= 0:
299+
if verbose_level >= 2:
300+
print("Boss wins")
301+
# pruned_strategies.append(actions_done)
302+
break
303+
else:
304+
unknown_result.append(strategy)
305+
# print ('Pruned : ', pruned_strategies)
306+
print("Unknown : ", unknown_result)
307+
puzzle_actual_result = min_mana_used
308+
309+
310+
# -------------------------------- Outputs / results -------------------------------- #
311+
312+
if verbose_level >= 3:
313+
print("Input : " + puzzle_input)
314+
print("Expected result : " + str(puzzle_expected_result))
315+
print("Actual result : " + str(puzzle_actual_result))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy