KellyHaTran/Insertion-Sort-Visualizer
0
1import random2import gradio as gr3 4MAX_STEPS = 2005 6#Stage 1: Generate List7 8def generate_list():9 arr = random.sample(range(1, 50), 10)10 display = f"Random Unsorted List:\n{arr}"11 return display, arr12 13 14#Stage 2: Insertion Sort Trace15 16def insertion_sort_on_state(user_number, custom_list_str, arr_state):17 #Decide which list to use: custom (if provided) or generated18 arr = None19 source_label = ""20 21 # 1)Try custom list if the textbox is not empty22 if custom_list_str is not None and str(custom_list_str).strip() != "":23 try:24 # split on comma or space25 tokens = [t for t in str(custom_list_str).replace(",", " ").split() if t]26 arr = [int(t) for t in tokens]27 source_label = "Custom List"28 except ValueError:29 # if parsing fails, return an error30 error_msg = "Please enter only integers separated by commas or spaces (e.g., 5, 2, 9, 1)."31 return (32 error_msg,33 *["" for _ in range(MAX_STEPS)],34 "Invalid custom list input."35 )36 37 # 2)If no custom list, fall back to generated arr_state38 if arr is None:39 if not arr_state:40 list_msg = "Please either generate a list or enter your own list first."41 return (42 list_msg,43 *["" for _ in range(MAX_STEPS)],44 "No list to sort."45 )46 arr = arr_state[:]47 source_label = "Random Unsorted List"48 49 #Display of the original list50 original_display = f"{source_label}:\n{arr}"51 52 n = len(arr)53 54 #Optional number to track55 highlight = None56 if user_number is not None:57 try:58 highlight = int(user_number)59 except:60 highlight = None61 62 steps: list[str] = []63 64 def log_step(msg):65 steps.append(msg)66 67 #INSERTION SORT 68 for i in range(1, n):69 current_value = arr[i]70 j = i - 171 72 log_step(73 f"Pass {i}: take value {current_value} from index {i} "74 f"and insert it into the sorted part on the left (indices 0..{i-1})."75 )76 while j >= 0:77 log_step(f"Compare {current_value} with arr[{j}] = {arr[j]}.")78 79 if arr[j] > current_value:80 log_step(81 f"Shift: {arr[j]} > {current_value}, thus moving {arr[j]} right (index {j} -> {j+1}) to make room for {current_value}."82 )83 arr[j + 1] = arr[j]84 j -= 185 else:86 log_step(87 f"No shift needed: {current_value} ≥ {arr[j]} (stop shifting)."88 )89 break90 91 log_step(f"Insert {current_value} at position {j+1} of array")92 arr[j + 1] = current_value93 94 msg = f"After pass {i}: {arr}"95 if highlight is not None and highlight in arr:96 msg += f" | Tracked number {highlight} is at index {arr.index(highlight)} of array"97 98 log_step(msg)99 100 #Build final message101 if highlight is not None and highlight in arr:102 final_msg = f"Sorted: {arr}, tracked number {highlight} is at index {arr.index(highlight)} of array"103 elif highlight is not None:104 final_msg = f"Sorted: {arr}, tracked number {highlight} is not in the list"105 else:106 final_msg = f"Sorted: {arr}"107 108 # Convert steps into updates for each step box109 step_updates = []110 for i in range(MAX_STEPS):111 if i < len(steps):112 step_updates.append(113 gr.update(114 value=steps[i],115 visible=True,116 )117 )118 else:119 step_updates.append(120 gr.update(121 value="",122 visible=False,123 )124 )125 126 return original_display, *step_updates, final_msg127 128 129# UI130 131theme = gr.themes.Ocean(132 primary_hue="pink",133 neutral_hue="slate",134)135 136with gr.Blocks(title="Insertion Sort Visualizer") as demo:137 gr.Markdown(138 """139 # Insertion Sort Visualizer140 141 **Option A:** Click **Generate List** to create a random list of 10 numbers. 142 **Option B:** Type your own list of integers (comma or space separated). 143 Then Pick a number from the list to track, then click **Run Insertion Sort**.144 """145 )146 147 arr_state = gr.State([])148 149 # LEFT SIDE COLUMN holds Generate List AND the custom list box150 with gr.Row():151 with gr.Column(scale=1):152 gen_btn = gr.Button("Generate List", variant="secondary")153 custom_list_box = gr.Textbox(154 label="Or enter your own list (e.g., 5, 2, 9, 1, 7)",155 lines=1,156 placeholder="5, 2, 9, 1, 7",157 )158 159 # RIGHT SIDE COLUMN holds the number input + Run button160 with gr.Column(scale=1):161 user_number = gr.Number(162 label="Pick a number from the list to track it's index (optional)",163 value=None,164 precision=0165 )166 run_btn = gr.Button("Run Insertion Sort", variant="primary")167 168 list_box = gr.Textbox(label="List", lines=2, interactive=False)169 step_boxes = [170 gr.Textbox(171 label=f"Step {i+1}",172 lines=3,173 interactive=False,174 visible=False,175 )176 for i in range(MAX_STEPS)177 ]178 result_box = gr.Textbox(label="Final Result", lines=1, interactive=False)179 180 # Wire Generate button181 gen_btn.click(182 generate_list,183 inputs=[],184 outputs=[list_box, arr_state]185 )186 187 188 run_btn.click(189 insertion_sort_on_state,190 inputs=[user_number, custom_list_box, arr_state],191 outputs=[list_box, *step_boxes, result_box],192 )193 194demo.launch(theme=theme)