-
Notifications
You must be signed in to change notification settings - Fork 0
/
solver.py
69 lines (54 loc) · 3.25 KB
/
solver.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
from level import *
class Solver:
def __call__(self, level: Level, solve_all = False, debug = False) -> List[List[Button.Action]]:
return self.solve(level, solve_all = solve_all, debug = debug)
def solve(self, level: Level, solve_all = False, debug = False) -> List[List[Button.Action]]:
solutions: List[List[Button.Action]] = []
# Idea: for each combination, use list of pairs of indexes (*, *) instead of list of actions
# Then, for each combination, deepcopy the used buttons, and use (nb, na)
# where nb = # of button, na = # of action within button nb to retrieve actions
# from copied button list => for each combination, deepcopy (used) buttons
# Create index of buttons and actions
buttons_idxs = range(len(level.buttons))
buttons_actions_idxs = [ (bi, ai) for bi in buttons_idxs for ai in range(len(level.buttons[bi].actions)) ]
# Compute number of iterations without unrolling the iterator
num_combinations = sum([ len(buttons_actions_idxs) ** i for i in range(1, level.max_moves + 1) ])
percentage_reached = 0
# Iterate over all possible combinations of actions
comb_by_len = [ product(buttons_actions_idxs, repeat = l) for l in range(1, level.max_moves + 1) ]
all_combinations = chain.from_iterable(comb_by_len)
for (i, combination) in enumerate(all_combinations):
# Display progress
percentage = 100 * i / num_combinations
if percentage > percentage_reached:
print(f"{int(percentage_reached)}%", end = '\r')
percentage_reached += 1
# Deepcopy all used buttons, works because one action cannot be bound to several buttons
copied_buttons = copy.deepcopy(level.buttons)
# Retrieve actions from copied buttons
copied_actions = [ copied_buttons[bi].actions[ai] for (bi, ai) in combination ]
if debug:
print(f"Testing combination {copied_actions}")
# Execute actions and build tentative solution
tentative_sol: List[Button.Action] = []
for action in copied_actions:
tentative_sol.append(copy.deepcopy(action))
action(level.screen, copied_buttons)
if debug:
print(f" action: {action}")
print(f" buttons: {copied_buttons}")
print(f" screen: {level.screen.screen_number.value}")
print()
if debug:
print(f"Result: {level.screen.screen_number.value}")
print(f"Goal: {level.goal.value}, (reached: {level.screen.screen_number.value == level.goal.value})")
print()
if level.screen.screen_number is not None and level.screen.screen_number.value == level.goal.value:
# Shallow copy tentative solution so we can clear it later without deleting it from the solution
solutions.append(copy.copy(tentative_sol))
if not solve_all:
level.screen = copy.deepcopy(level.init_screen)
return solutions
# Reset screen
level.screen = copy.deepcopy(level.init_screen)
return solutions