From d8b8ad13796fc7571f69cbb3634612a5b0e023e5 Mon Sep 17 00:00:00 2001 From: Abdullah Khan Date: Tue, 30 Dec 2025 18:24:15 +0500 Subject: [PATCH 1/2] refactor: restructure visualizer into class and improve rendering logic --- src/main.py | 258 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 168 insertions(+), 90 deletions(-) diff --git a/src/main.py b/src/main.py index 3a362de..fb6c93d 100644 --- a/src/main.py +++ b/src/main.py @@ -8,104 +8,182 @@ # Initialize pygame modules pygame.init() +# Constants +SCREEN_WIDTH = 900 +SCREEN_HEIGHT = 500 +BAR_AREA_HEIGHT = 400 +WIDGET_Y = 440 + # Font baseFont = pygame.font.SysFont('Arial', 24) # Colors -grey = (100, 100, 100) -green = (125, 240, 125) -white = (250, 250, 250) -red = (255, 50, 50) -black = (0, 0, 0) -blue = (50, 50, 255) - -pygame.display.set_caption('Sorting Algorithms Visualizer') -screen = pygame.display.set_mode((900, 500)) -window = Window(screen) - -window.add_widget( - widget_id = 'size_input', - widget = TextBox((30, 440, 100, 50), 'Size', grey, baseFont, '100') -) -window.add_widget( - widget_id='delay_slider', - widget=SlideBox((140, 440, 150, 50), 'Delay', grey, baseFont) -) -window.add_widget( - widget_id = 'algorithm_input', - widget = DropdownBox((300, 440, 200, 50), 'Algorithm', grey, baseFont, list(algorithmsDict.keys()), white) -) -window.add_widget( - widget_id = 'play_button', - widget = ButtonBox((510, 445, 40, 40), 'res/playButton.png', 'res/stopButton.png') -) - -def drawBars(screen, array, redBar1, redBar2, blueBar1, blueBar2, greenRows = {}): - '''Draw the bars and control their colors''' - numBars = len(array) - if numBars != 0: - bar_width = 900 / numBars +GREY = (100, 100, 100) +GREEN = (125, 240, 125) +WHITE = (250, 250, 250) +RED = (255, 50, 50) +BLACK = (0, 0, 0) +BLUE = (50, 50, 255) + +# Default values +DEFAULT_ARRAY_SIZE = 100 +MIN_BAR_HEIGHT = 10 +MAX_BAR_HEIGHT = 400 + +class SortingVisualizer: + """Main class to handle the sorting visualization""" + + def __init__(self): + pygame.display.set_caption('Sorting Algorithms Visualizer') + self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + self.window = Window(self.screen) + self.clock = pygame.time.Clock() + + self._setup_widgets() + self._reset_state() + + def _setup_widgets(self): + """Initialize all UI widgets""" + self.window.add_widget( + widget_id='size_input', + widget=TextBox((30, WIDGET_Y, 100, 50), 'Size', GREY, baseFont, str(DEFAULT_ARRAY_SIZE)) + ) + self.window.add_widget( + widget_id='delay_slider', + widget=SlideBox((140, WIDGET_Y, 150, 50), 'Delay', GREY, baseFont) + ) + self.window.add_widget( + widget_id='algorithm_input', + widget=DropdownBox((300, WIDGET_Y, 200, 50), 'Algorithm', GREY, baseFont, + list(algorithmsDict.keys()), WHITE) + ) + self.window.add_widget( + widget_id='play_button', + widget=ButtonBox((510, WIDGET_Y + 5, 40, 40), 'res/playButton.png', 'res/stopButton.png') + ) + + def _reset_state(self): + """Reset the visualizer state""" + self.numbers = [] + self.is_sorting = False + self.sorting_iterator = None + self.last_iteration = 0 + + def _generate_random_array(self, size): + """Generate a random array for sorting""" + try: + num_bars = max(1, min(int(size), SCREEN_WIDTH)) # Validate input + except (ValueError, TypeError): + num_bars = DEFAULT_ARRAY_SIZE + + return [randint(MIN_BAR_HEIGHT, MAX_BAR_HEIGHT) for _ in range(num_bars)] + + def _draw_bars(self, red_indices=(-1, -1), blue_indices=(-1, -1), green_indices=None): + """ + Draw the bars with appropriate colors + + Args: + red_indices: Tuple of indices to color red (comparison) + blue_indices: Tuple of indices to color blue (swap) + green_indices: Set of indices to color green (sorted) + """ + if not self.numbers: + return + + num_bars = len(self.numbers) + bar_width = SCREEN_WIDTH / num_bars ceil_width = math.ceil(bar_width) + green_indices = green_indices or set() + + for idx, height in enumerate(self.numbers): + # Determine bar color based on state + if idx in red_indices: + color = RED + elif idx in blue_indices: + color = BLUE + elif idx in green_indices: + color = GREEN + else: + color = GREY + + # Draw the bar + x_pos = idx * bar_width + y_pos = BAR_AREA_HEIGHT - height + pygame.draw.rect(self.screen, color, (x_pos, y_pos, ceil_width, height)) + + def _start_sorting(self): + """Initialize and start the sorting process""" + size_input = self.window.get_widget_value('size_input') + self.numbers = self._generate_random_array(size_input) + + algorithm_name = self.window.get_widget_value('algorithm_input') + self.sorting_iterator = algorithmsDict[algorithm_name]( + self.numbers, 0, len(self.numbers) - 1 + ) + self.is_sorting = True + self.last_iteration = time.time() + + def _update_sorting(self, delay): + """Update the sorting visualization""" + current_time = time.time() + + if current_time - self.last_iteration >= delay: + try: + self.numbers, red1, red2, blue1, blue2 = next(self.sorting_iterator) # type: ignore + self.last_iteration = current_time + self._draw_bars(red_indices=(red1, red2), blue_indices=(blue1, blue2)) + except StopIteration: + # Sorting completed + self.is_sorting = False + self.window.set_widget_value('play_button', False) + self._draw_bars(green_indices=set(range(len(self.numbers)))) + else: + # Redraw with current state + self._draw_bars() - for num in range(numBars): - if num in (redBar1, redBar2) : color = red - elif num in (blueBar1, blueBar2): color = blue - elif num in greenRows : color = green - else : color = grey - pygame.draw.rect(screen, color, (num * bar_width, 400 - array[num], ceil_width, array[num])) + def run(self): + """Main application loop""" + running = True -def main(): - numbers = [] - running = True - isPlaying = False - isSorting = False - sortingIterator = None - last_iteration = 0 - - while running: - screen.fill(white) - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - - window.update(event) - - # Get delay in seconds - delay = window.get_widget_value('delay_slider') / 10 - - isPlaying = window.get_widget_value('play_button') - if isPlaying and not isSorting: - # Random list to be sorted - numBars = int(window.get_widget_value('size_input')) - numbers = [randint(10, 400) for i in range(numBars)] - - # Initialize sorting iterator - sortingAlgorithm = window.get_widget_value('algorithm_input') - sortingIterator = algorithmsDict[sortingAlgorithm](numbers, 0, numBars - 1) - isSorting = True - - if not isPlaying: - isSorting = False - - if isSorting: - try: - # Get the next state from the sorting iterator - if time.time() - last_iteration >= delay: - numbers, redBar1, redBar2, blueBar1, blueBar2 = next(sortingIterator) - last_iteration = time.time() - - drawBars(screen, numbers, redBar1, redBar2, blueBar1, blueBar2) - window.render() - pygame.display.update() - - except StopIteration: - isSorting = False - window.set_widget_value('play_button', False) - else: - drawBars(screen, numbers, -1, -1, -1, -1, greenRows=set(range(len(numbers)))) + while running: + self.screen.fill(WHITE) + + # Handle events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + self.window.update(event) + + # Get current state + is_playing = self.window.get_widget_value('play_button') + delay = self.window.get_widget_value('delay_slider') / 10 - window.render() - pygame.display.update() + # Handle play/pause + if is_playing and not self.is_sorting: + self._start_sorting() + elif not is_playing and self.is_sorting: + self.is_sorting = False + + # Update visualization + if self.is_sorting: + self._update_sorting(delay) + else: + # Show array in final state + green_indices = set(range(len(self.numbers))) if self.numbers else set() + self._draw_bars(green_indices=green_indices) + + # Render UI and update display + self.window.render() + pygame.display.update() + self.clock.tick(60) # Limit to 60 FPS + + pygame.quit() + + +def main(): + """Entry point for the application""" + visualizer = SortingVisualizer() + visualizer.run() if __name__ == '__main__': From ff9781581c529441a243292943a1afac1527b4e7 Mon Sep 17 00:00:00 2001 From: Abdullah Khan Date: Tue, 30 Dec 2025 18:36:48 +0500 Subject: [PATCH 2/2] docs: improve README with clearer usage and contribution guidance --- README.md | 62 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 7076032..f11dcc5 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,59 @@ -# Sorting-Algorithms-Visualizer +# Sorting Algorithms Visualizer -## Run +An educational application developed in Python using the game development library Pygame, which helps illustrate how a variety of sorting algorithms function in real-time by making visual adjustments to the bars as the algorithms perform the calculations. + +## Features + +- **9 Sorting Algorithms**: Bubble Sort, Bucket Sort, Cocktail Sort, Counting Sort, Heap Sort, Insertion Sort, Merge Sort, Quick Sort, and Selection Sort +- **Real-time Visualization**: See each algorithm's step-by-step execution +- **Educational**: Perfect for students learning algorithms and data structures +- **Interactive**: Built with Pygame for smooth animations + +## Getting Started + +### Prerequisites + +- Python 3.x +- pip (Python package installer) + +### Installation + +1. Clone the repository: -- Clone GitHub repository -``` git clone https://github.com/LucasPilla/Sorting-Algorithms-Visualizer.git -``` -- Install requirements: -``` +cd Sorting-Algorithms-Visualizer + +2. Install dependencies: + pip install -r requirements.txt -``` -- Run: -``` + +3. Run the visualizer: + python3 src/main.py -``` ## Preview + +Watch the algorithms in action: + | | | | |:-------------------------:|:-------------------------:|:-------------------------:| -|![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/bubble_sort.gif?raw=true) Bubble sort | ![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/bucket_sort.gif?raw=true) Bucket sort |![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/cocktail_sort.gif?raw=true) Cocktail sort | -|![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/counting_sort.gif?raw=true) Counting sort | ![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/heap_sort.gif?raw=true) Heap sort |![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/insertion_sort.gif?raw=true) Insertion sort | -|![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/merge_sort.gif?raw=true) Merge sort | ![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/quick_sort.gif?raw=true) Quick sort |![](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/selection_sort.gif?raw=true) Selection sort | +|![Bubble Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/bubble_sort.gif?raw=true)
**Bubble Sort** | ![Bucket Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/bucket_sort.gif?raw=true)
**Bucket Sort** |![Cocktail Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/cocktail_sort.gif?raw=true)
**Cocktail Sort** | +|![Counting Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/counting_sort.gif?raw=true)
**Counting Sort** | ![Heap Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/heap_sort.gif?raw=true)
**Heap Sort** |![Insertion Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/insertion_sort.gif?raw=true)
**Insertion Sort** | +|![Merge Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/merge_sort.gif?raw=true)
**Merge Sort** | ![Quick Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/quick_sort.gif?raw=true)
**Quick Sort** |![Selection Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/selection_sort.gif?raw=true)
**Selection Sort** | + +## Contributing + +Contributions are welcome! Please check out our [Contributing Guidelines](CONTRIBUTING.md) to get started. + +## License + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + +## Acknowledgments + +- Built with [Pygame](https://www.pygame.org/) +- Inspired by the need to make algorithm learning more visual and intuitive +## Support +If you find this project helpful, please consider giving it a ⭐️ on GitHub!