SimulateSearch / app.py
Rahatara's picture
Update app.py
eadd466 verified
import random
import gradio as gr
MAX_STEPS = 8 # number of step boxes to show
# -------------------------
# Stage 1: Generate the list
# -------------------------
def generate_list():
arr = sorted(random.sample(range(1, 50), 10)) # 10 unique ints in [1..49]
display = f"Random Sorted List:\n{arr}"
return display, arr
# -------------------------
# Stage 2: Run the search
# -------------------------
def binary_search_on_state(user_number, arr_state):
# If user hasn't generated a list yet
if not arr_state:
list_msg = "⚠️ Please click 'Generate List' first."
# Return list warning, blank step messages, blank ranges, and final result message
return (
list_msg,
*["" for _ in range(MAX_STEPS)], # step messages
*["" for _ in range(MAX_STEPS)], # range messages
"⚠️ No list to search."
)
# Validate input
try:
target = int(user_number)
except (TypeError, ValueError):
return (
f"Random Sorted List:\n{arr_state}",
*["" for _ in range(MAX_STEPS)],
*["" for _ in range(MAX_STEPS)],
"⚠️ Enter a valid integer."
)
arr = arr_state[:] # copy for safety
steps = []
ranges = []
low, high = 0, len(arr) - 1
found = False
# Record initial range before any check (optional but helpful)
ranges.append(f"Initial range [low={low}, high={high}] β†’ {arr[low:high+1]}")
while low <= high:
mid = (low + high) // 2
steps.append(f"Check middle index {mid} β†’ value {arr[mid]}")
if arr[mid] == target:
steps.append(f"βœ… Found {target} at index {mid}")
found = True
# After finding, remaining range is just the match
ranges.append(f"Remaining range [low={mid}, high={mid}] β†’ [{arr[mid]}]")
break
elif arr[mid] < target:
low = mid + 1
ranges.append(f"Move right β†’ new range [low={low}, high={high}] β†’ {arr[low:high+1] if low <= high else []}")
else:
high = mid - 1
ranges.append(f"Move left β†’ new range [low={low}, high={high}] β†’ {arr[low:high+1] if low <= high else []}")
if not found:
steps.append(f"❌ The number {target} was not found.")
# Pad to fill consistent UI boxes
while len(steps) < MAX_STEPS:
steps.append("")
while len(ranges) < MAX_STEPS:
ranges.append("")
final_msg = f"βœ… The number {target} was found!" if found else f"❌ The number {target} was not found."
list_display = f"Random Sorted List:\n{arr}"
# Return:
# 1 list box,
# MAX_STEPS step messages,
# MAX_STEPS range messages,
# 1 final result box
return list_display, *steps[:MAX_STEPS], *ranges[:MAX_STEPS], final_msg
# -------------------------
# UI
# -------------------------
with gr.Blocks(title="Binary Search Game β€” Two-Stage + Range View") as demo:
gr.Markdown(
"""
# 🎯 Binary Search Game β€” Two-Stage (with Remaining Range)
**Step 1:** Click **Generate List** (10 unique numbers in 1–49).
**Step 2:** Enter a number and click **Run Binary Search**.
See each decision and the *remaining range* after every step.
"""
)
# App state to hold the generated list across button clicks
arr_state = gr.State([])
with gr.Row():
gen_btn = gr.Button("Generate List 🎲", variant="secondary")
user_number = gr.Number(label="Enter a number to search (1–49)", value=1, precision=0)
run_btn = gr.Button("Run Binary Search πŸ”Ž", variant="primary")
# List display
list_box = gr.Textbox(label="Generated Sorted List", lines=2, interactive=False)
gr.Markdown("### πŸ”Ή Search Steps (Decision Trace)")
step_boxes = [gr.Textbox(label=f"Step {i+1}", lines=1, interactive=False) for i in range(MAX_STEPS)]
gr.Markdown("### πŸ”Έ Remaining Range After Each Step")
range_boxes = [gr.Textbox(label=f"Range {i+1}", lines=1, interactive=False) for i in range(MAX_STEPS)]
# Final result
result_box = gr.Textbox(label="Final Result", lines=1, interactive=False)
# Wire up events
gen_btn.click(
fn=generate_list,
inputs=[],
outputs=[list_box, arr_state],
)
run_btn.click(
fn=binary_search_on_state,
inputs=[user_number, arr_state],
outputs=[list_box, *step_boxes, *range_boxes, result_box],
)
if __name__ == "__main__":
demo.launch()