Rennie44/Sorting-Algorithm-Visualization
0
1import gradio as gr2import time3import random4 5from algorithms.bubble_sort import bubble_sort_steps6from algorithms.insertion_sort import insertion_sort_steps7from algorithms.selection_sort import selection_sort_steps8from algorithms.binary_search import binary_search_steps9 10from utils.visualizer import render_single_step_html11 12# -------------------------------------------------------13# PAUSE / RESUME CONTROLLER14# -------------------------------------------------------15is_paused = False16 17def pause_sort():18 global is_paused19 is_paused = True20 21def resume_sort():22 global is_paused23 is_paused = False24 25# -------------------------------------------------------26# Helper: parse comma-separated array27# -------------------------------------------------------28def parse_array(text: str):29 if not text:30 raise ValueError("Input array is empty.")31 parts = [p.strip() for p in text.split(",")]32 arr = []33 for p in parts:34 if p == "":35 continue36 try:37 arr.append(float(p) if "." in p else int(p))38 except:39 raise ValueError(f"Invalid number: {p}")40 if len(arr) == 0:41 raise ValueError("No valid numbers found.")42 return arr43 44def generate_random_array(n):45 return [random.randint(1, 99) for _ in range(n)]46 47# -------------------------------------------------------48# Generator for streaming (REAL-TIME updates)49# -------------------------------------------------------50def stream_sort(algo, array_text, speed_ms, search_target, use_random, random_size):51 global is_paused52 is_paused = False53 54 # Get array (random or user input)55 if use_random:56 arr = generate_random_array(random_size)57 else:58 try:59 arr = parse_array(array_text)60 except Exception as e:61 yield f"<div style='color:red;'>Error: {e}</div>"62 return63 64 delay = speed_ms / 1000.065 66 # Choose algorithm67 if algo == "Bubble Sort":68 steps = bubble_sort_steps(arr)69 elif algo == "Insertion Sort":70 steps = insertion_sort_steps(arr)71 elif algo == "Selection Sort":72 steps = selection_sort_steps(arr)73 elif algo == "Binary Search":74 if search_target is None:75 yield "<div style='color:red;'>Binary Search needs a target.</div>"76 return77 arr_sorted = sorted(arr)78 steps = binary_search_steps(arr_sorted, search_target)79 else:80 yield "<div style='color:red;'>Unknown algorithm.</div>"81 return82 83 # Stream steps84 for i, step in enumerate(steps):85 while is_paused:86 time.sleep(0.05)87 yield render_single_step_html(step, i)88 time.sleep(delay)89 90# -------------------------------------------------------91# GRADIO UI (NO DARK THEME)92# -------------------------------------------------------93with gr.Blocks(title="Sorting/Searching Visualization") as demo:94 95 gr.Markdown("# ๐ Algorithm Visualizer (Real-Time + Adjustable Speed)")96 gr.Markdown("Choose an algorithm, enter an array, and watch it animate step by step.")97 98 with gr.Row():99 algo_dd = gr.Dropdown(100 label="Algorithm",101 choices=["Bubble Sort", "Insertion Sort", "Selection Sort", "Binary Search"],102 value="Bubble Sort"103 )104 use_random = gr.Checkbox(label="Use random array", value=False)105 random_size = gr.Slider(label="Random array size", minimum=3, maximum=50, step=1, value=10)106 array_input = gr.Textbox(107 label="Input Array",108 value="8, 3, 7, 4, 9, 1",109 interactive=True110 )111 speed = gr.Slider(112 label="Speed (ms per step)",113 minimum=10,114 maximum=1500,115 step=10,116 value=300117 )118 119 search_target = gr.Number(120 label="Binary Search Target",121 value=4,122 interactive=True,123 visible=False124 )125 126 # Auto-update the array textbox when random mode or size changes127 def update_array(use_random_val, size, current_value):128 if use_random_val:129 arr = generate_random_array(size)130 return gr.update(value=", ".join(str(x) for x in arr))131 return gr.update(value=current_value)132 133 use_random.change(update_array, inputs=[use_random, random_size, array_input], outputs=[array_input])134 random_size.change(update_array, inputs=[use_random, random_size, array_input], outputs=[array_input])135 136 # Toggle visibility for binary search target137 def toggle_target(algo_value):138 return gr.update(visible=(algo_value == "Binary Search"))139 140 algo_dd.change(toggle_target, inputs=[algo_dd], outputs=[search_target])141 142 run_btn = gr.Button("Run Visualization")143 144 with gr.Row():145 pause_btn = gr.Button("Pause")146 resume_btn = gr.Button("Resume")147 148 pause_btn.click(pause_sort, inputs=None, outputs=None)149 resume_btn.click(resume_sort, inputs=None, outputs=None)150 151 output = gr.HTML(label="Visualization")152 153 run_btn.click(154 stream_sort,155 inputs=[algo_dd, array_input, speed, search_target, use_random, random_size],156 outputs=[output]157 )158 159# Launch (Spaces auto-selects port)160if __name__ == "__main__":161 demo.launch(server_name="0.0.0.0", server_port=None)162 