File size: 4,573 Bytes
0104725
1a55a2e
0104725
90ad295
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd4a6f0
 
 
 
 
 
 
90ad295
 
b7be380
 
90ad295
fd4a6f0
 
 
 
 
 
b7be380
90ad295
0104725
fd4a6f0
1a55a2e
fb4bb01
1a55a2e
fd4a6f0
 
 
0104725
 
fd4a6f0
 
1a55a2e
b7be380
fb4bb01
fd4a6f0
 
b7be380
1a55a2e
0104725
fd4a6f0
0104725
 
fd4a6f0
1a55a2e
fb4bb01
90ad295
0104725
fd4a6f0
90ad295
fb4bb01
fd4a6f0
 
1a55a2e
90ad295
 
bff9d60
fd4a6f0
 
 
 
 
 
0104725
 
90ad295
 
 
fd4a6f0
0104725
 
fd4a6f0
 
 
 
0104725
 
 
90ad295
 
 
 
 
 
 
 
 
5bf1c20
90ad295
fd4a6f0
90ad295
b7be380
fd4a6f0
 
 
90ad295
bff9d60
 
90ad295
 
 
 
 
b7be380
0104725
90ad295
 
 
fd4a6f0
0104725
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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()