shadowsnub/Quick-Sort-Visualizer
0
1import gradio as gr2import random3 4# -------------------------5# QuickSort with step tracking6# -------------------------7def quick_sort_with_steps(arr):8 steps = []9 10 def record_state(label, pivot_idx=None, i=None, j=None, sorted_indices=None):11 steps.append(render_bars(arr, label, pivot_idx, i, j, sorted_indices))12 13 def partition(low, high, sorted_indices):14 pivot = arr[high]15 pivot_idx = high16 17 record_state(f"Choosing pivot arr[{high}] = {pivot}", pivot_idx=pivot_idx, sorted_indices=sorted_indices)18 19 i = low - 120 for j in range(low, high):21 record_state(f"Comparing arr[{j}] < pivot", pivot_idx, i, j, sorted_indices)22 23 if arr[j] < pivot:24 i += 125 arr[i], arr[j] = arr[j], arr[i]26 record_state(f"Swapping arr[{i}] and arr[{j}]", pivot_idx, i, j, sorted_indices)27 28 arr[i+1], arr[high] = arr[high], arr[i+1]29 sorted_indices.add(i+1)30 record_state(f"Placing pivot at {i+1}", pivot_idx=i+1, sorted_indices=sorted_indices)31 32 return i + 133 34 def quicksort(low, high, sorted_indices):35 if low < high:36 record_state(f"QuickSort range [{low}, {high}]", sorted_indices=sorted_indices)37 pivot = partition(low, high, sorted_indices)38 quicksort(low, pivot - 1, sorted_indices)39 quicksort(pivot + 1, high, sorted_indices)40 else:41 if low == high:42 sorted_indices.add(low)43 record_state(f"Single element sorted at index {low}", sorted_indices=sorted_indices)44 45 sorted_indices = set()46 record_state("Starting QuickSort")47 quicksort(0, len(arr) - 1, sorted_indices)48 49 record_state("All elements sorted", sorted_indices=sorted_indices)50 return steps51 52 53# -------------------------54# Render bars as HTML55# -------------------------56def render_bars(arr, label, pivot_idx=None, i=None, j=None, sorted_indices=None):57 if sorted_indices is None:58 sorted_indices = set()59 60 max_height = max(arr) if arr else 161 62 bars_html = "<div style='display:flex;gap:4px;align-items:flex-end;height:200px;'>"63 64 for idx, val in enumerate(arr):65 height = int((val / max_height) * 180 + 20)66 67 color = "#6ca0dc" # default blue-gray68 69 if idx in sorted_indices:70 color = "#4CAF50" # green71 elif idx == pivot_idx:72 color = "#e74c3c" # red73 elif idx == i or idx == j:74 color = "#f1c40f" # yellow75 76 bars_html += f"""77 <div style="78 width: 18px;79 height:{height}px;80 background:{color};81 border-radius:4px;82 display:flex;83 align-items:center;84 justify-content:center;85 font-size:10px;86 color:white;87 " title="Index {idx}, Value {val}">88 </div>89 """90 91 bars_html += "</div>"92 93 return f"""94 <h4 style="margin-bottom:6px;">{label}</h4>95 {bars_html}96 """97 98 99# -------------------------100# UI Callbacks101# -------------------------102def generate(size):103 size = int(size)104 arr = random.sample(range(10, 99), size)105 frames = quick_sort_with_steps(arr.copy())106 107 return (108 frames,109 frames[0],110 gr.update(minimum=0, maximum=len(frames) - 1, value=0, interactive=True)111 )112 113 114def change_step(step, frames):115 step = int(step)116 return frames[step]117 118 119def prev_step(step, frames):120 return max(0, step - 1), frames[max(0, step - 1)]121 122 123def next_step(step, frames):124 return min(len(frames) - 1, step + 1), frames[min(len(frames) - 1, step + 1)]125 126 127def first_step(frames):128 return 0, frames[0]129 130 131def last_step(frames):132 idx = len(frames) - 1133 return idx, frames[idx]134 135 136# -------------------------137# Build Gradio App138# -------------------------139with gr.Blocks(title="QuickSort Visualizer") as demo:140 141 gr.Markdown("""142 # 🔄 QuickSort Visualizer 143 Step through the QuickSort algorithm with clean, colored bar animations.<br>144 **Red = Pivot | Yellow = Comparing | Blue = Normal | Green = Sorted**145 """)146 147 with gr.Row():148 size = gr.Slider(5, 40, value=15, label="Array Size")149 gen_btn = gr.Button("Generate Array", variant="primary")150 151 frames_state = gr.State([])152 current_step = gr.State(0)153 154 display = gr.HTML("<h4>Click Generate to begin.</h4>")155 step_slider = gr.Slider(0, 0, step=1, label="Step", interactive=False)156 157 with gr.Row():158 start_btn = gr.Button("⏮ Start")159 prev_btn = gr.Button("◀ Prev")160 next_btn = gr.Button("Next ▶")161 end_btn = gr.Button("End ⏭")162 163 # Generate button164 gen_btn.click(165 fn=generate,166 inputs=[size],167 outputs=[frames_state, display, step_slider]168 )169 170 # Slider control171 step_slider.change(change_step, [step_slider, frames_state], display)172 173 # Navigation buttons174 start_btn.click(175 lambda frames: first_step(frames),176 inputs=[frames_state],177 outputs=[step_slider, display]178 )179 180 end_btn.click(181 lambda frames: last_step(frames),182 inputs=[frames_state],183 outputs=[step_slider, display]184 )185 186 prev_btn.click(187 prev_step,188 inputs=[step_slider, frames_state],189 outputs=[step_slider, display]190 )191 192 next_btn.click(193 next_step,194 inputs=[step_slider, frames_state],195 outputs=[step_slider, display]196 )197 198demo.launch()