Spaces:
Sleeping
Sleeping
| 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(""" | |
| <style> | |
| .vertical-radio .wrap { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 6px; | |
| } | |
| </style> | |
| """) | |
| 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(""" | |
| <div style="text-align: center;"> | |
| Developed by <strong>Aspra, N.</strong> | Β© 2025 All Rights Reserved | |
| </div> | |
| """) | |
| demo.launch() | |
| # cd 251104_CNC_code_review/ | |
| # python app.py |