Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0926c4f

Browse files
main.py
0 parents commit 0926c4f

File tree

1 file changed

+377
-0
lines changed

1 file changed

+377
-0
lines changed

‎main.py

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
import pygame
2+
import random
3+
import math
4+
5+
pygame.init()
6+
7+
8+
# The `DrawInformation` class is used for storing and managing information related to drawing elements
9+
# on a window.
10+
class DrawInformation:
11+
BLACK = 0, 0, 0
12+
WHITE = 255, 255, 255
13+
GREEN = 0, 128, 0
14+
RED = 255, 0, 0
15+
BACKGROUND_COLOR = WHITE
16+
17+
GRADIENTS = [
18+
(0, 0, 255),
19+
(0, 0, 230),
20+
(0, 0, 205),
21+
]
22+
23+
SMALL_FONT = pygame.font.SysFont("timesnewroman", 15)
24+
FONT = pygame.font.SysFont("timesnewroman", 20)
25+
LARGE_FONT = pygame.font.SysFont("timesnewroman", 30)
26+
27+
SIDE_PAD = 100
28+
TOP_PAD = 150
29+
30+
def __init__(self, width, height, lst):
31+
self.width = width
32+
self.height = height
33+
34+
self.window = pygame.display.set_mode((width, height))
35+
pygame.display.set_caption("SortingWiz")
36+
self.set_list(lst)
37+
38+
def set_list(self, lst):
39+
self.lst = lst
40+
self.min_val = min(lst)
41+
self.max_val = max(lst)
42+
43+
self.block_width = round((self.width - self.SIDE_PAD) / len(lst))
44+
self.block_height = math.floor(
45+
(self.height - self.TOP_PAD) / (self.max_val - self.min_val)
46+
)
47+
self.start_x = self.SIDE_PAD // 2
48+
49+
50+
def draw(draw_info, algo_name, ascending):
51+
"""
52+
The `draw` function is responsible for rendering the sorting visualization on the screen, including
53+
the title, controls, sorting options, the list being sorted, and additional information.
54+
55+
:param draw_info: The `draw_info` parameter is an object that contains information about the drawing
56+
window and other drawing-related properties. It likely includes attributes such as `window` (the
57+
drawing window), `BACKGROUND_COLOR` (the background color of the window), `LARGE_FONT` (a large font
58+
for titles),
59+
:param algo_name: The `algo_name` parameter is a string that represents the name of the sorting
60+
algorithm being used. It will be displayed in the title of the window
61+
:param ascending: The `ascending` parameter is a boolean value that determines whether the sorting
62+
algorithm should sort the data in ascending order (`True`) or descending order (`False`)
63+
:param time_complexity: The time complexity of the current algorithm.
64+
:param space_complexity: The space complexity of the current algorithm.
65+
"""
66+
67+
draw_info.window.fill(draw_info.BACKGROUND_COLOR)
68+
69+
title_text = f"{algo_name} - {'Ascending' if ascending else 'Descending'}"
70+
title_font = draw_info.LARGE_FONT
71+
title_surface = title_font.render(title_text, 1, draw_info.GREEN)
72+
73+
# Calculate the position with padding
74+
title_x = draw_info.width / 2 - title_surface.get_width() / 2
75+
title_y = -30 # Padding before the title
76+
title_y += title_surface.get_height() + 0 # Padding after the title
77+
78+
draw_info.window.blit(title_surface, (title_x, title_y))
79+
80+
controls_text = "Q - Quit | R - Reset | SPACE - Start/Resume/Stop | A - Ascending | D - Descending"
81+
controls_font = draw_info.FONT
82+
controls_surface = controls_font.render(controls_text, 1, draw_info.BLACK)
83+
controls_x = draw_info.width / 2 - controls_surface.get_width() / 2
84+
controls_y = title_y + title_surface.get_height()
85+
draw_info.window.blit(controls_surface, (controls_x, controls_y))
86+
87+
sorting_text = (
88+
"I - Insertion Sort | B - Bubble Sort | S - Selection Sort | H - Heap Sort"
89+
)
90+
sorting_surface = draw_info.FONT.render(sorting_text, 1, draw_info.BLACK)
91+
sorting_x = draw_info.width / 2 - sorting_surface.get_width() / 2
92+
sorting_y = controls_y + controls_surface.get_height()
93+
draw_info.window.blit(sorting_surface, (sorting_x, sorting_y))
94+
95+
# Display time and space complexity based on the selected algorithm
96+
if algo_name == "Bubble Sort":
97+
time_complexity = "O(n^2)"
98+
space_complexity = "O(1)"
99+
elif algo_name == "Insertion Sort":
100+
time_complexity = "O(n^2)"
101+
space_complexity = "O(1)"
102+
elif algo_name == "Selection Sort":
103+
time_complexity = "O(n^2)"
104+
space_complexity = "O(1)"
105+
elif algo_name == "Heap Sort":
106+
time_complexity = "O(n log n)"
107+
space_complexity = "O(1)"
108+
else:
109+
time_complexity = "Not specified"
110+
space_complexity = "Not specified"
111+
112+
complexity_text = (
113+
f"Time Complexity: {time_complexity} | Space Complexity: {space_complexity}"
114+
)
115+
complexity_surface = draw_info.SMALL_FONT.render(
116+
complexity_text, 1, draw_info.BLACK
117+
)
118+
complexity_x = draw_info.width / 2 - complexity_surface.get_width() / 2
119+
complexity_y = sorting_y + sorting_surface.get_height() + 10 # Padding on top
120+
draw_info.window.blit(complexity_surface, (complexity_x, complexity_y))
121+
122+
draw_list(draw_info)
123+
124+
# Additional information
125+
additional_info_text = "[CS50 Fall 2023 Final Project - SortingWiz | Made by Arjun Vijay Prakash (@ArjunCodess)]"
126+
additional_info_surface = draw_info.SMALL_FONT.render(
127+
additional_info_text, 1, draw_info.BLACK
128+
)
129+
additional_info_x = draw_info.width / 2 - additional_info_surface.get_width() / 2
130+
additional_info_y = (
131+
complexity_y + complexity_surface.get_height() + 5
132+
) # Padding on bottom
133+
draw_info.window.blit(
134+
additional_info_surface, (additional_info_x, additional_info_y)
135+
)
136+
137+
pygame.display.update()
138+
139+
140+
def draw_list(draw_info, color_positions={}, clear_bg=False):
141+
"""
142+
The function `draw_list` takes in a list of values and draws rectangles on a window based on the
143+
values in the list.
144+
145+
:param draw_info: The `draw_info` parameter is an object that contains information needed to draw
146+
the list. It likely has the following attributes:
147+
:param color_positions: The `color_positions` parameter is a dictionary that specifies the positions
148+
in the list where you want to change the color of the blocks. The keys of the dictionary represent
149+
the positions in the list, and the values represent the color you want to assign to those positions
150+
:param clear_bg: The `clear_bg` parameter is a boolean value that determines whether the background
151+
of the drawing window should be cleared before drawing the list. If `clear_bg` is `True`, a
152+
rectangle covering the entire drawing window will be filled with the background color specified in
153+
`draw_info.BACKGROUND_COLOR`. If, defaults to False (optional)
154+
"""
155+
lst = draw_info.lst
156+
157+
if clear_bg:
158+
clear_rect = (
159+
draw_info.SIDE_PAD // 2,
160+
draw_info.TOP_PAD,
161+
draw_info.width - draw_info.SIDE_PAD,
162+
draw_info.height - draw_info.TOP_PAD,
163+
)
164+
pygame.draw.rect(draw_info.window, draw_info.BACKGROUND_COLOR, clear_rect)
165+
166+
for i, val in enumerate(lst):
167+
x = draw_info.start_x + i * draw_info.block_width
168+
y = draw_info.height - (val - draw_info.min_val) * draw_info.block_height
169+
170+
color = draw_info.GRADIENTS[i % 3]
171+
172+
if i in color_positions:
173+
color = color_positions[i]
174+
175+
pygame.draw.rect(
176+
draw_info.window, color, (x, y, draw_info.block_width, draw_info.height)
177+
)
178+
179+
if clear_bg:
180+
pygame.display.update()
181+
182+
183+
def generate_starting_list(n, min_val, max_val):
184+
"""
185+
The function generates a list of random integers within a given range.
186+
187+
:param n: The parameter "n" represents the number of elements you want in the list
188+
:param min_val: The minimum value that can be generated in the list
189+
:param max_val: The maximum value that can be generated in the list
190+
:return: a list of n random integers between min_val and max_val.
191+
"""
192+
lst = []
193+
194+
for _ in range(n):
195+
val = random.randint(min_val, max_val)
196+
lst.append(val)
197+
198+
return lst
199+
200+
201+
def bubble_sort(draw_info, ascending=True):
202+
lst = draw_info.lst
203+
204+
for i in range(len(lst) - 1):
205+
for j in range(len(lst) - 1 - i):
206+
num1 = lst[j]
207+
num2 = lst[j + 1]
208+
209+
if (num1 > num2 and ascending) or (num1 < num2 and not ascending):
210+
lst[j], lst[j + 1] = lst[j + 1], lst[j]
211+
draw_list(draw_info, {j: draw_info.GREEN, j + 1: draw_info.RED}, True)
212+
yield True
213+
214+
return lst
215+
216+
217+
def insertion_sort(draw_info, ascending=True):
218+
lst = draw_info.lst
219+
220+
for i in range(1, len(lst)):
221+
current = lst[i]
222+
223+
while True:
224+
ascending_sort = i > 0 and lst[i - 1] > current and ascending
225+
descending_sort = i > 0 and lst[i - 1] < current and not ascending
226+
227+
if not ascending_sort and not descending_sort:
228+
break
229+
230+
lst[i] = lst[i - 1]
231+
i = i - 1
232+
lst[i] = current
233+
draw_list(draw_info, {i - 1: draw_info.GREEN, i: draw_info.RED}, True)
234+
yield True
235+
236+
return lst
237+
238+
239+
def selection_sort(draw_info, ascending=True):
240+
lst = draw_info.lst
241+
242+
for i in range(len(lst)):
243+
min_idx = i
244+
for j in range(i + 1, len(lst)):
245+
if (lst[j] < lst[min_idx] and ascending) or (
246+
lst[j] > lst[min_idx] and not ascending
247+
):
248+
min_idx = j
249+
lst[i], lst[min_idx] = lst[min_idx], lst[i]
250+
draw_list(draw_info, {i: draw_info.GREEN, min_idx: draw_info.RED}, True)
251+
yield True
252+
253+
return lst
254+
255+
256+
def heapify(draw_info, lst, n, i, ascending):
257+
largest = i
258+
left = 2 * i + 1
259+
right = 2 * i + 2
260+
261+
if left < n and (
262+
(lst[left] > lst[largest] and ascending)
263+
or (lst[left] < lst[largest] and not ascending)
264+
):
265+
largest = left
266+
267+
if right < n and (
268+
(lst[right] > lst[largest] and ascending)
269+
or (lst[right] < lst[largest] and not ascending)
270+
):
271+
largest = right
272+
273+
if largest != i:
274+
lst[i], lst[largest] = lst[largest], lst[i]
275+
draw_list(draw_info, {i: draw_info.GREEN, largest: draw_info.RED}, True)
276+
yield True
277+
278+
yield from heapify(draw_info, lst, n, largest, ascending)
279+
280+
281+
def heap_sort(draw_info, ascending=True):
282+
lst = draw_info.lst
283+
n = len(lst)
284+
285+
# Build a max heap
286+
for i in range(n // 2 - 1, -1, -1):
287+
yield from heapify(draw_info, lst, n, i, ascending)
288+
289+
# Extract elements one by one
290+
for i in range(n - 1, 0, -1):
291+
lst[i], lst[0] = lst[0], lst[i]
292+
draw_list(draw_info, {i: draw_info.GREEN, 0: draw_info.RED}, True)
293+
yield True
294+
295+
yield from heapify(draw_info, lst, i, 0, ascending)
296+
297+
return lst
298+
299+
300+
def main():
301+
"""
302+
The main function controls the sorting visualization program, allowing the user to select different
303+
sorting algorithms and sort the list in ascending or descending order.
304+
"""
305+
run = True
306+
clock = pygame.time.Clock()
307+
308+
n = 100
309+
min_val = 0
310+
max_val = 200
311+
312+
lst = generate_starting_list(n, min_val, max_val)
313+
draw_info = DrawInformation(1200, 1000, lst)
314+
sorting = False
315+
ascending = True
316+
step_by_step = False
317+
sorting_paused = False
318+
319+
sorting_algorithm = bubble_sort
320+
sorting_algo_name = "Bubble Sort"
321+
sorting_algorithm_generator = None
322+
323+
while run:
324+
clock.tick(60)
325+
326+
if sorting and not sorting_paused:
327+
try:
328+
next(sorting_algorithm_generator)
329+
except StopIteration:
330+
sorting = False
331+
else:
332+
draw(draw_info, sorting_algo_name, ascending)
333+
334+
for event in pygame.event.get():
335+
if event.type == pygame.QUIT:
336+
run = False
337+
338+
if event.type == pygame.KEYDOWN:
339+
if event.key == pygame.K_r:
340+
lst = generate_starting_list(n, min_val, max_val)
341+
draw_info.set_list(lst)
342+
sorting = False
343+
elif event.key == pygame.K_SPACE and not sorting:
344+
sorting = True
345+
sorting_algorithm_generator = sorting_algorithm(
346+
draw_info, ascending
347+
)
348+
elif event.key == pygame.K_RETURN and not sorting:
349+
sorting_paused = False
350+
elif event.key == pygame.K_a and not sorting:
351+
ascending = True
352+
elif event.key == pygame.K_d and not sorting:
353+
ascending = False
354+
elif event.key == pygame.K_i and not sorting:
355+
sorting_algorithm = insertion_sort
356+
sorting_algo_name = "Insertion Sort"
357+
elif event.key == pygame.K_b and not sorting:
358+
sorting_algorithm = bubble_sort
359+
sorting_algo_name = "Bubble Sort"
360+
elif event.key == pygame.K_h and not sorting:
361+
sorting_algorithm = heap_sort
362+
sorting_algo_name = "Heap Sort"
363+
elif event.key == pygame.K_s and not sorting:
364+
sorting_algorithm = selection_sort
365+
sorting_algo_name = "Selection Sort"
366+
elif event.key == pygame.K_q:
367+
run = False
368+
elif event.key == pygame.K_SPACE and sorting and not sorting_paused:
369+
sorting_paused = True
370+
elif event.key == pygame.K_SPACE and sorting and sorting_paused:
371+
sorting_paused = False
372+
373+
pygame.quit()
374+
375+
376+
if __name__ == "__main__":
377+
main()

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /