-
Notifications
You must be signed in to change notification settings - Fork 1
/
python_visualizer.py
executable file
·223 lines (205 loc) · 8.53 KB
/
python_visualizer.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/usr/bin/env python3
from tkinter import *
import sys
import time
import subprocess
import os
from math import sqrt
"""
__project__ = "push_swap visualizer"
__author__ = "Emmanuel Ruaud"
__email__ = "eruaud@student.le-101.fr"
This python script was created to visualize your work with the PUSH_SWAP
42 Project.
You must put this script in the same path or in a sibling path of your program
Of course you need Python3 with the builtin Tkinter.
You can install it with Brew.
--> Brew install python3
Execute the script with :
--> python3 pyviz.py `ruby -e "puts (-200..200).to_a.shuffle.join(' ')"`
You can change the PUSHS_PATH to get to the relative path of your push_swap
You can decrease or increase the speed with the matching buttons.
"""
RELATIVE_PATH = r'push_swap'
class PsGui:
def __init__(self, master):
ww = 600
wh = 600
self.i = 0
self.speed = 0
dirname = os.path.dirname(os.path.abspath(__file__))
PUSHS_PATH = os.path.join(dirname, RELATIVE_PATH)
self.pile_a = [int(num) for num in sys.argv[1:]]
self.first_pile = self.pile_a[:]
self.pile_b = []
self.cmds = subprocess.check_output([PUSHS_PATH] + sys.argv[1:], stderr=subprocess.STDOUT,
timeout=12).splitlines()
if len(self.pile_a) != 0:
self.prespeed = 1 / len(self.pile_a)
else:
self.prespeed = 0
self.master = master
master.title("Push_swap viewer")
self.mainframe = Frame(master)
self.mainframe.pack(fill=BOTH)
self.can = Canvas(self.mainframe, width=ww, height=wh, bg="black")
self.can.pack(side=LEFT)
self.toolframe = Frame(self.mainframe)
self.toolframe.pack(side=RIGHT, fill=BOTH)
self.butframe = Frame(self.toolframe)
self.butframe.pack(side=TOP, fill=Y)
self.PrevCtl = Button(self.butframe, text="<<", command=self.speed_down)
self.PrevCtl.pack(side=LEFT)
self.PauseCtl = Button(self.butframe, text=">", command=self.pause)
self.PauseCtl.pack(side=LEFT)
self.NextCtl = Button(self.butframe, text=">>", command=self.speed_up)
self.NextCtl.pack(side=LEFT)
self.ResetCtl = Button(self.butframe, text="R", command=self.reset)
self.ResetCtl.pack(side=LEFT)
self.listbox = Listbox(self.toolframe, bg='black', fg='light cyan',
font=("monospace", 12), relief=FLAT)
self.listbox.pack(fill=BOTH, expand=1)
for cmd in self.cmds:
self.listbox.insert(END, cmd)
self.statusframe = Frame(master)
self.statusframe.pack(side=BOTTOM, fill=X)
self.speedmeter = Label(self.statusframe,
text='frame rate = ' + str(self.speed),
font=("monospace", 10))
self.speedmeter.pack(side=LEFT)
self.totalcount = Label(self.statusframe,
text='- operations = ' + str(len(self.cmds)),
font=("monospace", 10))
self.totalcount.pack(side=LEFT)
self.draw_rectangles()
self.launch()
def reset(self):
self.speed = 0
self.i = 0
del self.pile_a[:]
self.pile_a = self.first_pile[:]
del self.pile_b[:]
self.can.delete("all")
self.draw_rectangles()
self.listbox.see(0)
self.PauseCtl.config(text='>')
self.launch()
def pause(self):
if self.speed != 0:
self.prespeed = self.speed
self.speed = 0
self.speedmeter.config(text='frame rate = 0')
self.PauseCtl.config(text='>')
else:
self.speed = self.prespeed
self.speedmeter.config(text='frame rate = ' \
+ '{:.2e}'.format(self.speed))
self.PauseCtl.config(text='||')
def speed_up(self):
if self.speed == 0:
self.PauseCtl.config(text='||')
self.speed = self.prespeed
self.speed = self.speed ** 2
self.speedmeter.config(text='frame rate = ' \
+ '{:.2e}'.format(self.speed))
def speed_down(self):
self.speed = sqrt(self.speed)
self.speedmeter.config(text='frame rate = ' \
+ '{:.2e}'.format(self.speed))
def launch_cmds(self, cmd):
if cmd == b'sa' and len(self.pile_a) >= 2:
self.pile_a[0], self.pile_a[1] = self.pile_a[1], self.pile_a[0]
if cmd == b'sb' and len(self.pile_b) >= 2:
self.pile_b[0], self.pile_b[1] = self.pile_b[1], self.pile_b[0]
if cmd == b'ss':
if (len(self.pile_a) >= 2):
self.pile_a[0], self.pile_a[1] = self.pile_a[1], self.pile_a[0]
if (len(self.pile_b) >= 2):
self.pile_b[0], self.pile_b[1] = self.pile_b[1], self.pile_b[0]
if cmd == b'ra' and len(self.pile_a) >= 2:
self.pile_a.append(self.pile_a[0])
del self.pile_a[0]
if cmd == b'rb' and len(self.pile_b) >= 2:
self.pile_b.append(self.pile_b[0])
del self.pile_b[0]
if cmd == b'rr':
if (len(self.pile_a) >= 2):
self.pile_a.append(self.pile_a[0])
del self.pile_a[0]
if (len(self.pile_b) >= 2):
self.pile_b.append(self.pile_b[0])
del self.pile_b[0]
if cmd == b'rra' and len(self.pile_a) >= 2:
self.pile_a = [self.pile_a[-1]] + self.pile_a
del self.pile_a[-1]
if cmd == b'rrb' and len(self.pile_b) >= 2:
self.pile_b = [self.pile_b[-1]] + self.pile_b
del self.pile_b[-1]
if cmd == b'rrr':
if (len(self.pile_a) >= 2):
self.pile_a = [self.pile_a[-1]] + self.pile_a
del self.pile_a[-1]
if (len(self.pile_b) >= 2):
self.pile_b = [self.pile_b[-1]] + self.pile_b
del self.pile_b[-1]
if cmd == b'pa' and len(self.pile_b) >= 1:
self.pile_a = [self.pile_b[0]] + self.pile_a
del self.pile_b[0]
if cmd == b'pb' and len(self.pile_a) >= 1:
self.pile_b = [self.pile_a[0]] + self.pile_b
del self.pile_a[0]
return self.pile_a, self.pile_b
def set_color(self, index):
col = '#%02x%02x%02x' % (int(255 * (index - 0.3) * (index > 0.3)),
int(255 * index
- ((510 * (index - 0.6)) * (index > 0.6))),
int((255 - 510 * index) * (index < 0.5)))
return col
def draw_rectangles(self):
vi = 0
ww = 600
wh = 600
hw = ww / 2
hm = len(self.pile_a) + len(self.pile_b)
mx, mn = (0, 0)
if (hm != 0):
mx = max(self.pile_a + self.pile_b)
mn = min(self.pile_a + self.pile_b)
rects = []
if len(self.pile_a) > 0:
a_val = [(num - mn) / (mx - mn) for num in self.pile_a]
for vala in a_val:
rects.append(self.can.create_rectangle(0, vi,
10 + vala * (hw - 100), vi + wh / hm,
fill=self.set_color(vala), outline=""))
vi += wh / hm
vi = 0
if len(self.pile_b) > 0:
b_val = [(num - mn) / (mx - mn) for num in self.pile_b]
for valb in b_val:
rects.append(self.can.create_rectangle(hw, vi,
hw + 10 + valb * (hw - 100), vi + wh / hm,
fill=self.set_color(valb), outline=""))
vi += wh / hm
def launch(self):
while self.i < len(self.cmds):
if self.speed != 0:
while self.i < len(self.cmds):
self.listbox.activate(self.i)
self.can.delete("all")
self.pile_a, self.pile_b = \
self.launch_cmds(self.cmds[self.i])
self.draw_rectangles()
time.sleep(2 * self.speed)
self.can.update()
self.listbox.yview_scroll(1, 'units')
self.i += 1
if self.speed == 0:
break
time.sleep(0.25)
self.can.update()
self.PauseCtl.config(text='>')
root = Tk()
root.resizable(width=False, height=False)
gui = PsGui(root)
root.mainloop()