Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 48 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -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)<br>**Bubble Sort** | ![Bucket Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/bucket_sort.gif?raw=true)<br>**Bucket Sort** |![Cocktail Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/cocktail_sort.gif?raw=true)<br>**Cocktail Sort** |
|![Counting Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/counting_sort.gif?raw=true)<br>**Counting Sort** | ![Heap Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/heap_sort.gif?raw=true)<br>**Heap Sort** |![Insertion Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/insertion_sort.gif?raw=true)<br>**Insertion Sort** |
|![Merge Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/merge_sort.gif?raw=true)<br>**Merge Sort** | ![Quick Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/quick_sort.gif?raw=true)<br>**Quick Sort** |![Selection Sort](https://github.com/LucasPilla/Sorting-Algorithms-Visualizer/blob/master/res/selection_sort.gif?raw=true)<br>**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!
258 changes: 168 additions & 90 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__':
Expand Down