Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aimacode
GitHub Repository: aimacode/aima-python
Path: blob/master/gui/eight_puzzle.py
621 views
1
import os.path
2
import random
3
import time
4
from functools import partial
5
from tkinter import *
6
7
from search import astar_search, EightPuzzle
8
9
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
10
11
root = Tk()
12
13
state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
14
puzzle = EightPuzzle(tuple(state))
15
solution = None
16
17
b = [None] * 9
18
19
20
# TODO: refactor into OOP, remove global variables
21
22
def scramble():
23
"""Scrambles the puzzle starting from the goal state"""
24
25
global state
26
global puzzle
27
possible_actions = ['UP', 'DOWN', 'LEFT', 'RIGHT']
28
scramble = []
29
for _ in range(60):
30
scramble.append(random.choice(possible_actions))
31
32
for move in scramble:
33
if move in puzzle.actions(state):
34
state = list(puzzle.result(state, move))
35
puzzle = EightPuzzle(tuple(state))
36
create_buttons()
37
38
39
def solve():
40
"""Solves the puzzle using astar_search"""
41
42
return astar_search(puzzle).solution()
43
44
45
def solve_steps():
46
"""Solves the puzzle step by step"""
47
48
global puzzle
49
global solution
50
global state
51
solution = solve()
52
print(solution)
53
54
for move in solution:
55
state = puzzle.result(state, move)
56
create_buttons()
57
root.update()
58
root.after(1, time.sleep(0.75))
59
60
61
def exchange(index):
62
"""Interchanges the position of the selected tile with the zero tile under certain conditions"""
63
64
global state
65
global solution
66
global puzzle
67
zero_ix = list(state).index(0)
68
actions = puzzle.actions(state)
69
current_action = ''
70
i_diff = index // 3 - zero_ix // 3
71
j_diff = index % 3 - zero_ix % 3
72
if i_diff == 1:
73
current_action += 'DOWN'
74
elif i_diff == -1:
75
current_action += 'UP'
76
77
if j_diff == 1:
78
current_action += 'RIGHT'
79
elif j_diff == -1:
80
current_action += 'LEFT'
81
82
if abs(i_diff) + abs(j_diff) != 1:
83
current_action = ''
84
85
if current_action in actions:
86
b[zero_ix].grid_forget()
87
b[zero_ix] = Button(root, text=f'{state[index]}', width=6, font=('Helvetica', 40, 'bold'),
88
command=partial(exchange, zero_ix))
89
b[zero_ix].grid(row=zero_ix // 3, column=zero_ix % 3, ipady=40)
90
b[index].grid_forget()
91
b[index] = Button(root, text=None, width=6, font=('Helvetica', 40, 'bold'), command=partial(exchange, index))
92
b[index].grid(row=index // 3, column=index % 3, ipady=40)
93
state[zero_ix], state[index] = state[index], state[zero_ix]
94
puzzle = EightPuzzle(tuple(state))
95
96
97
def create_buttons():
98
"""Creates dynamic buttons"""
99
100
# TODO: Find a way to use grid_forget() with a for loop for initialization
101
b[0] = Button(root, text=f'{state[0]}' if state[0] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
102
command=partial(exchange, 0))
103
b[0].grid(row=0, column=0, ipady=40)
104
b[1] = Button(root, text=f'{state[1]}' if state[1] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
105
command=partial(exchange, 1))
106
b[1].grid(row=0, column=1, ipady=40)
107
b[2] = Button(root, text=f'{state[2]}' if state[2] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
108
command=partial(exchange, 2))
109
b[2].grid(row=0, column=2, ipady=40)
110
b[3] = Button(root, text=f'{state[3]}' if state[3] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
111
command=partial(exchange, 3))
112
b[3].grid(row=1, column=0, ipady=40)
113
b[4] = Button(root, text=f'{state[4]}' if state[4] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
114
command=partial(exchange, 4))
115
b[4].grid(row=1, column=1, ipady=40)
116
b[5] = Button(root, text=f'{state[5]}' if state[5] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
117
command=partial(exchange, 5))
118
b[5].grid(row=1, column=2, ipady=40)
119
b[6] = Button(root, text=f'{state[6]}' if state[6] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
120
command=partial(exchange, 6))
121
b[6].grid(row=2, column=0, ipady=40)
122
b[7] = Button(root, text=f'{state[7]}' if state[7] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
123
command=partial(exchange, 7))
124
b[7].grid(row=2, column=1, ipady=40)
125
b[8] = Button(root, text=f'{state[8]}' if state[8] != 0 else None, width=6, font=('Helvetica', 40, 'bold'),
126
command=partial(exchange, 8))
127
b[8].grid(row=2, column=2, ipady=40)
128
129
130
def create_static_buttons():
131
"""Creates scramble and solve buttons"""
132
133
scramble_btn = Button(root, text='Scramble', font=('Helvetica', 30, 'bold'), width=8, command=partial(init))
134
scramble_btn.grid(row=3, column=0, ipady=10)
135
solve_btn = Button(root, text='Solve', font=('Helvetica', 30, 'bold'), width=8, command=partial(solve_steps))
136
solve_btn.grid(row=3, column=2, ipady=10)
137
138
139
def init():
140
"""Calls necessary functions"""
141
142
global state
143
global solution
144
state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
145
scramble()
146
create_buttons()
147
create_static_buttons()
148
149
150
init()
151
root.mainloop()
152
153