Final_Project / app.py
KareemAlk's picture
Update app.py
5a6daee verified
import random
import gradio as gr
# ---------- Helper functions ----------
def generate_random_students(n_students: int):
"""
Generate a random class with names 'Student 1', 'Student 2', ...
and random grades between 0 and 100.
"""
students = []
for i in range(n_students):
name = f"Student {i + 1}"
grade = random.randint(0, 100)
students.append([name, grade])
return students
def format_students(students):
"""
Turn a list like [["Student 1", 78], ["Student 2", 92]]
into: [Student 1 (78), Student 2 (92)]
"""
parts = [f"{name} ({grade:g})" for name, grade in students]
return "[" + ", ".join(parts) + "]"
def is_sorted(students, ascending):
"""
Check if the list is sorted by grade in the chosen order.
"""
grades = [g for _, g in students]
if ascending:
return all(grades[i] <= grades[i + 1] for i in range(len(grades) - 1))
else:
return all(grades[i] >= grades[i + 1] for i in range(len(grades) - 1))
def bubble_rule_should_swap(left_grade, right_grade, ascending):
"""
Bubble Sort rule: when do we swap?
"""
if ascending:
return left_grade > right_grade
else:
return left_grade < right_grade
# ---------- Simulation functions ----------
def start_simulation(n_students, order_choice):
"""
Create a random class and set up the first comparison.
"""
try:
n_students = int(n_students)
except ValueError:
n_students = 5 # default
if n_students < 2:
n_students = 2
students = generate_random_students(n_students)
n = len(students)
ascending = (order_choice == "Lowest to highest")
# Initial pass and position
i = 0 # pass index
j = 0 # position index
list_text = format_students(students)
left_name, left_grade = students[j]
right_name, right_grade = students[j + 1]
should_swap = bubble_rule_should_swap(left_grade, right_grade, ascending)
comparison_text = (
f"Pass {i + 1} – Compare {left_name} ({left_grade:g}) "
f"and {right_name} ({right_grade:g})\n"
f"Bubble Sort rule for this comparison: "
f"{'Swap' if should_swap else 'Do NOT swap'}"
)
status = (
"New random class generated.\n"
"Use the buttons below to decide each step."
)
# At start: no swaps yet, no accuracy info yet
swap_count = 0
correct_decisions = 0
total_decisions = 0
finished = False
return (
list_text,
comparison_text,
status,
students,
i,
j,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
def step_simulation(
action,
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
):
"""
One step after the teacher presses Swap / Don't swap.
"""
if students is None:
return (
"Click 'Start Simulation' to generate a class.",
"",
"No active simulation.",
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
if finished:
list_text = format_students(students)
status = "Simulation already finished. Start again with a new class."
return (
list_text,
"",
status,
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
n = len(students)
ascending = (order_choice == "Lowest to highest")
i = pass_index
j = position_index
# Current pair before action
left_name, left_grade = students[j]
right_name, right_grade = students[j + 1]
rule_says_swap = bubble_rule_should_swap(left_grade, right_grade, ascending)
teacher_chose_swap = (action == "swap")
# Update accuracy counters
total_decisions += 1
if teacher_chose_swap == rule_says_swap:
correct_decisions += 1
# Apply teacher choice
if teacher_chose_swap:
students[j], students[j + 1] = students[j + 1], students[j]
swap_count += 1
teacher_action_text = "Teacher chose to SWAP these two students."
else:
teacher_action_text = "Teacher chose NOT to swap these two students."
# Move to next position
j += 1
status = teacher_action_text
# End of this pass?
if j >= n - 1 - i:
i += 1
j = 0
status += f"\nEnd of pass {i}. Moving to the next pass."
# All passes done?
if i >= n - 1:
finished = True
list_text = format_students(students)
correct_order = is_sorted(students, ascending)
# Accuracy
if total_decisions > 0:
accuracy = (correct_decisions / total_decisions) * 100
else:
accuracy = 0.0
comparison_text = ""
status += "\n\nSimulation finished. Final list locked."
if correct_order:
status += "\nThe final list IS correctly sorted according to the chosen order."
else:
status += "\nThe final list is NOT correctly sorted according to the chosen order."
status += f"\nTotal swaps you performed: {swap_count}"
status += f"\nYour decision accuracy: {accuracy:.1f}% "
status += f"({correct_decisions} out of {total_decisions} decisions matched the Bubble Sort rule.)"
return (
list_text,
comparison_text,
status,
students,
i,
j,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
# Not finished: compute next comparison
left_name, left_grade = students[j]
right_name, right_grade = students[j + 1]
should_swap = bubble_rule_should_swap(left_grade, right_grade, ascending)
list_text = format_students(students)
comparison_text = (
f"Pass {i + 1} – Compare {left_name} ({left_grade:g}) "
f"and {right_name} ({right_grade:g})\n"
)
return (
list_text,
comparison_text,
status,
students,
i,
j,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
def finish_now(
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
):
"""
Teacher clicks 'Finish now' before all passes complete.
"""
if students is None:
return (
"Click 'Start Simulation' to generate a class.",
"",
"No active simulation.",
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
ascending = (order_choice == "Lowest to highest")
list_text = format_students(students)
correct_order = is_sorted(students, ascending)
status = "Teacher finished the list early.\n"
if correct_order:
status += "The final list IS correctly sorted according to the chosen order."
else:
status += "The final list is NOT correctly sorted according to the chosen order."
if total_decisions > 0:
accuracy = (correct_decisions / total_decisions) * 100
else:
accuracy = 0.0
status += f"\nTotal swaps you performed: {swap_count}"
status += f"\nYour decision accuracy: {accuracy:.1f}% "
status += f"({correct_decisions} out of {total_decisions} decisions matched the Bubble Sort rule.)"
finished = True
return (
list_text,
"",
status,
students,
pass_index,
position_index,
swap_count,
finished,
order_choice,
correct_decisions,
total_decisions,
)
# ---------- Gradio UI ----------
with gr.Blocks(title="Marking Day – Interactive Bubble Sort") as demo:
gr.Markdown(
"""
# Marking Day – Interactive Bubble Sort Grade Ranker
You are the teacher on marking day.
1. Choose how many students are in the class.
2. Choose the sort order.
3. Click **Start Simulation** to generate a random class.
4. For each comparison, choose whether to **Swap** or **Don't swap**.
5. Watch the list update after each choice.
6. Continue until Bubble Sort finishes, or click **Finish now**.
At the end, you will see:
- Whether the final list is correctly sorted.
- How many swaps you performed.
- How accurate your decisions were compared to the Bubble Sort rule.
"""
)
n_students_input = gr.Slider(
minimum=2,
maximum=20,
value=5,
step=1,
label="Number of students in the class",
)
order_choice = gr.Radio(
choices=["Highest to lowest", "Lowest to highest"],
value="Highest to lowest",
label="Sort order",
)
start_button = gr.Button("Start Simulation", variant="primary")
list_display = gr.Markdown(label="Current list")
comparison_display = gr.Markdown(label="Current comparison")
status_display = gr.Markdown(label="Status")
# State variables
students_state = gr.State()
pass_state = gr.State(0)
position_state = gr.State(0)
swap_count_state = gr.State(0)
finished_state = gr.State(False)
order_state = gr.State("Highest to lowest")
correct_decisions_state = gr.State(0)
total_decisions_state = gr.State(0)
# Start simulation
start_button.click(
fn=start_simulation,
inputs=[n_students_input, order_choice],
outputs=[
list_display,
comparison_display,
status_display,
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
)
with gr.Row():
swap_button = gr.Button("Swap students")
dont_swap_button = gr.Button("Don't swap")
finish_button = gr.Button("Finish now")
# Step with Swap
swap_button.click(
fn=lambda students, p, pos, swaps, fin, ord_choice, correct_dec, total_dec: step_simulation(
"swap",
students,
p,
pos,
swaps,
fin,
ord_choice,
correct_dec,
total_dec,
),
inputs=[
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
outputs=[
list_display,
comparison_display,
status_display,
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
)
# Step with Don't swap
dont_swap_button.click(
fn=lambda students, p, pos, swaps, fin, ord_choice, correct_dec, total_dec: step_simulation(
"no_swap",
students,
p,
pos,
swaps,
fin,
ord_choice,
correct_dec,
total_dec,
),
inputs=[
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
outputs=[
list_display,
comparison_display,
status_display,
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
)
# Finish early
finish_button.click(
fn=finish_now,
inputs=[
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
outputs=[
list_display,
comparison_display,
status_display,
students_state,
pass_state,
position_state,
swap_count_state,
finished_state,
order_state,
correct_decisions_state,
total_decisions_state,
],
)
if __name__ == "__main__":
demo.launch()