import gradio as gr import random import re from pathlib import Path # -------------------- PARSER -------------------- # def parse_latex_questions(tex_path: str): text = Path(tex_path).read_text(encoding="utf-8") pattern = re.compile( r"\\question\s*(.*?)\s*\\choice\s*\{(.*?)\}\s*\{(.*?)\}\s*\{(.*?)\}\s*\{(.*?)\}\s*\{(.*?)\}", re.DOTALL ) letter_map = {"a": 0, "b": 1, "c": 2, "d": 3} questions = [] for m in pattern.finditer(text): q_text = m.group(1).strip() options = [m.group(i).strip() for i in range(2, 6)] answer_letter = m.group(6).strip().lower() correct_answer = options[letter_map.get(answer_letter, 0)] questions.append( { "question": q_text, "options": options, "answer": correct_answer, } ) return questions # -------------------- LOAD QUESTIONS -------------------- # all_questions = parse_latex_questions("questions.tex") # -------------------- GAME LOGIC -------------------- # def start_game(): questions = all_questions.copy() random.shuffle(questions) return {"index": 0, "score": 0, "finished": False, "questions": questions} def get_current_question(state): if state["index"] < len(state["questions"]): current_q = state["questions"][state["index"]] return current_q["question"], current_q["options"] else: state["finished"] = True return "Game Over! Please press 'Restart' to play again.", [] def process_answer(user_answer, state): total = len(state["questions"]) # If game already finished and user clicks again if state["finished"]: return ( "Game Over! Please press 'Restart' to play again.", state, gr.update(choices=["Quiz finished"], value="Quiz finished"), f"### 🎉 Game Over!\n**Final Score:** {state['score']}/{total}", str(state["score"]), ) current_q = state["questions"][state["index"]] correct_answer = current_q["answer"] if user_answer == correct_answer: state["score"] += 1 feedback = "✅ Correct!" else: feedback = f"❌ Incorrect. The correct answer was {correct_answer}." # Move to next question state["index"] += 1 # If no more questions if state["index"] == total: state["finished"] = True feedback += f" 🎉 Game Over! Your final score is {state['score']}/{total}." return ( feedback, state, gr.update(choices=["Quiz finished"], value="Quiz finished"), f"### 🎉 Game Over!\n**Final Score:** {state['score']}/{total}", str(state["score"]), ) # Otherwise show next question new_question, new_options = get_current_question(state) return ( feedback, state, gr.update(choices=new_options, value=None), f"### {new_question}", str(state["score"]), ) def reset_game(): new_state = start_game() question, options = get_current_question(new_state) return ( new_state, f"### {question}", gr.update(choices=options, value=None), "", "0", ) def load_game(): state = start_game() question, options = get_current_question(state) return ( state, f"### {question}", gr.update(choices=options, value=None), "0", "", ) # -------------------- UI -------------------- # with gr.Blocks() as demo: gr.Markdown("# CNC G-Codes and M-Codes Review") # make radio vertical gr.HTML(""" """) state = gr.State() # question shown as markdown so it can be multiline question_md = gr.Markdown("### Question will appear here") options_buttons = gr.Radio( choices=[], label=" ", show_label=False, interactive=True, elem_classes=["vertical-radio"] ) with gr.Row(): submit_btn = gr.Button("Submit") reset_btn = gr.Button("Restart") feedback_box = gr.Textbox(label="Feedback", interactive=False) score_box = gr.Textbox(label="Score", value="0", interactive=False) submit_btn.click( process_answer, inputs=[options_buttons, state], outputs=[feedback_box, state, options_buttons, question_md, score_box], ) reset_btn.click( reset_game, inputs=[], outputs=[state, question_md, options_buttons, feedback_box, score_box], ) demo.load( load_game, inputs=None, outputs=[state, question_md, options_buttons, score_box, feedback_box], ) gr.Markdown("---") gr.Markdown("""
Developed by Aspra, N. | © 2025 All Rights Reserved
""") demo.launch() # cd 251104_CNC_code_review/ # python app.py