Sina Media Lab
commited on
Commit
·
58956eb
1
Parent(s):
e6e6e74
Updates
Browse files- app.py +57 -42
- modules/valid_invalid_numbers.py +42 -204
app.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
-
import importlib
|
| 3 |
import os
|
| 4 |
from fpdf import FPDF
|
| 5 |
import uuid
|
|
@@ -22,6 +21,10 @@ if 'module_question_count' not in st.session_state:
|
|
| 22 |
st.session_state.module_question_count = {}
|
| 23 |
if 'pdf_data' not in st.session_state:
|
| 24 |
st.session_state.pdf_data = None
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
def reset_pdf_cache():
|
| 27 |
st.session_state.pdf_data = None
|
|
@@ -81,11 +84,12 @@ def load_modules():
|
|
| 81 |
for filename in os.listdir(module_dir):
|
| 82 |
if filename.endswith(".py") and filename != "__init__.py":
|
| 83 |
module_name = filename[:-3]
|
| 84 |
-
module
|
|
|
|
| 85 |
modules[module_name] = {
|
| 86 |
"title": getattr(module, "title", module_name),
|
| 87 |
"description": getattr(module, "description", "No description available."),
|
| 88 |
-
"generate_question": module.generate_question
|
| 89 |
}
|
| 90 |
return modules
|
| 91 |
|
|
@@ -104,34 +108,60 @@ def navigate_question(direction):
|
|
| 104 |
if direction == "prev" and st.session_state.current_index > 0:
|
| 105 |
st.session_state.current_index -= 1
|
| 106 |
elif direction == "next":
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
# Generate a new question if at the end of the list
|
| 111 |
-
new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
|
| 112 |
-
st.session_state.questions.append(new_question)
|
| 113 |
-
st.session_state.current_index += 1
|
| 114 |
|
| 115 |
# Load all modules dynamically
|
| 116 |
modules = load_modules()
|
| 117 |
|
| 118 |
# Streamlit interface
|
| 119 |
st.sidebar.title("Quiz Modules")
|
| 120 |
-
module_name = st.sidebar.radio("Choose a module:",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
|
| 122 |
-
if
|
| 123 |
-
st.session_state.current_module =
|
| 124 |
st.session_state.current_index = 0
|
| 125 |
-
st.session_state.questions = [generate_new_question(
|
| 126 |
-
st.session_state.module_question_count[
|
| 127 |
-
st.session_state.module_correct_count[
|
|
|
|
|
|
|
| 128 |
|
| 129 |
# Load the current module's question
|
| 130 |
current_question = st.session_state.questions[st.session_state.current_index]
|
| 131 |
|
| 132 |
# Display module title and description
|
| 133 |
-
st.title(modules[
|
| 134 |
-
st.write(modules[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
st.write(current_question["question"])
|
| 136 |
|
| 137 |
# Use a form to prevent rerun on option selection
|
|
@@ -142,7 +172,10 @@ with st.form(key=f'question_form_{st.session_state.current_index}'):
|
|
| 142 |
key=f"question_{st.session_state.current_index}_options",
|
| 143 |
index=None # No pre-selection
|
| 144 |
)
|
| 145 |
-
submit_button = st.form_submit_button(label="Submit")
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
if submit_button and not current_question.get('answered', False):
|
| 148 |
if selected_answer is None:
|
|
@@ -151,11 +184,14 @@ if submit_button and not current_question.get('answered', False):
|
|
| 151 |
# Process the answer
|
| 152 |
current_question['selected'] = selected_answer
|
| 153 |
current_question['answered'] = True
|
| 154 |
-
st.session_state.module_question_count[
|
| 155 |
|
| 156 |
if selected_answer == current_question['correct_answer']:
|
| 157 |
st.session_state.correct_count += 1
|
| 158 |
-
st.session_state.module_correct_count[
|
|
|
|
|
|
|
|
|
|
| 159 |
|
| 160 |
# Show correct/incorrect feedback after submission
|
| 161 |
if current_question.get('answered', False):
|
|
@@ -172,24 +208,3 @@ if current_question.get('answered', False):
|
|
| 172 |
st.write("**Step-by-Step Solution:**")
|
| 173 |
for step in current_question['step_by_step_solution']:
|
| 174 |
st.write(step)
|
| 175 |
-
|
| 176 |
-
# Navigation buttons (placed after question and options)
|
| 177 |
-
col1, col2 = st.columns([1, 1])
|
| 178 |
-
with col1:
|
| 179 |
-
if st.button("⬅️ Prev", key=f'prev_button_{st.session_state.current_index}', disabled=st.session_state.current_index == 0):
|
| 180 |
-
navigate_question("prev")
|
| 181 |
-
|
| 182 |
-
with col2:
|
| 183 |
-
if st.button("➡️ Next", key=f'next_button_{st.session_state.current_index}'):
|
| 184 |
-
navigate_question("next")
|
| 185 |
-
|
| 186 |
-
# PDF Download Button (at the bottom)
|
| 187 |
-
if len(st.session_state.questions) > 0:
|
| 188 |
-
pdf = generate_pdf_report()
|
| 189 |
-
st.session_state.pdf_data = pdf # Reset PDF cache
|
| 190 |
-
st.download_button(
|
| 191 |
-
label="Download PDF Report 📄",
|
| 192 |
-
data=st.session_state.pdf_data,
|
| 193 |
-
file_name="quiz_report.pdf",
|
| 194 |
-
mime="application/pdf"
|
| 195 |
-
)
|
|
|
|
| 1 |
import streamlit as st
|
|
|
|
| 2 |
import os
|
| 3 |
from fpdf import FPDF
|
| 4 |
import uuid
|
|
|
|
| 21 |
st.session_state.module_question_count = {}
|
| 22 |
if 'pdf_data' not in st.session_state:
|
| 23 |
st.session_state.pdf_data = None
|
| 24 |
+
if 'submit_disabled' not in st.session_state:
|
| 25 |
+
st.session_state.submit_disabled = True
|
| 26 |
+
if 'next_disabled' not in st.session_state:
|
| 27 |
+
st.session_state.next_disabled = True
|
| 28 |
|
| 29 |
def reset_pdf_cache():
|
| 30 |
st.session_state.pdf_data = None
|
|
|
|
| 84 |
for filename in os.listdir(module_dir):
|
| 85 |
if filename.endswith(".py") and filename != "__init__.py":
|
| 86 |
module_name = filename[:-3]
|
| 87 |
+
# Dynamically import the module only when needed
|
| 88 |
+
module = __import__(f"{module_dir}.{module_name}", fromlist=[''])
|
| 89 |
modules[module_name] = {
|
| 90 |
"title": getattr(module, "title", module_name),
|
| 91 |
"description": getattr(module, "description", "No description available."),
|
| 92 |
+
"generate_question": module.generate_question # Access the generate_question function
|
| 93 |
}
|
| 94 |
return modules
|
| 95 |
|
|
|
|
| 108 |
if direction == "prev" and st.session_state.current_index > 0:
|
| 109 |
st.session_state.current_index -= 1
|
| 110 |
elif direction == "next":
|
| 111 |
+
new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
|
| 112 |
+
st.session_state.questions.append(new_question)
|
| 113 |
+
st.session_state.current_index = len(st.session_state.questions) - 1
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
|
| 115 |
# Load all modules dynamically
|
| 116 |
modules = load_modules()
|
| 117 |
|
| 118 |
# Streamlit interface
|
| 119 |
st.sidebar.title("Quiz Modules")
|
| 120 |
+
module_name = st.sidebar.radio("Choose a module:", [modules[module]["title"] for module in modules], index=0)
|
| 121 |
+
|
| 122 |
+
selected_module = None
|
| 123 |
+
for module in modules:
|
| 124 |
+
if modules[module]["title"] == module_name:
|
| 125 |
+
selected_module = module
|
| 126 |
+
break
|
| 127 |
|
| 128 |
+
if selected_module != st.session_state.current_module:
|
| 129 |
+
st.session_state.current_module = selected_module
|
| 130 |
st.session_state.current_index = 0
|
| 131 |
+
st.session_state.questions = [generate_new_question(selected_module, modules[selected_module])]
|
| 132 |
+
st.session_state.module_question_count[selected_module] = 0
|
| 133 |
+
st.session_state.module_correct_count[selected_module] = 0
|
| 134 |
+
st.session_state.submit_disabled = True
|
| 135 |
+
st.session_state.next_disabled = True
|
| 136 |
|
| 137 |
# Load the current module's question
|
| 138 |
current_question = st.session_state.questions[st.session_state.current_index]
|
| 139 |
|
| 140 |
# Display module title and description
|
| 141 |
+
st.title(modules[selected_module]["title"])
|
| 142 |
+
st.write(modules[selected_module]["description"])
|
| 143 |
+
|
| 144 |
+
# Navigation and PDF report buttons
|
| 145 |
+
col1, col2, col3 = st.columns([1, 1, 2])
|
| 146 |
+
with col1:
|
| 147 |
+
if st.button("⬅️ Prev", disabled=st.session_state.current_index == 0):
|
| 148 |
+
navigate_question("prev")
|
| 149 |
+
with col2:
|
| 150 |
+
if st.button("➡️ Next", disabled=st.session_state.next_disabled):
|
| 151 |
+
st.session_state.submit_disabled = True
|
| 152 |
+
st.session_state.next_disabled = True
|
| 153 |
+
navigate_question("next")
|
| 154 |
+
with col3:
|
| 155 |
+
if len(st.session_state.questions) > 0:
|
| 156 |
+
pdf = generate_pdf_report()
|
| 157 |
+
st.session_state.pdf_data = pdf # Reset PDF cache
|
| 158 |
+
st.download_button(
|
| 159 |
+
label="Download PDF Report 📄",
|
| 160 |
+
data=st.session_state.pdf_data,
|
| 161 |
+
file_name="quiz_report.pdf",
|
| 162 |
+
mime="application/pdf"
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
st.write(current_question["question"])
|
| 166 |
|
| 167 |
# Use a form to prevent rerun on option selection
|
|
|
|
| 172 |
key=f"question_{st.session_state.current_index}_options",
|
| 173 |
index=None # No pre-selection
|
| 174 |
)
|
| 175 |
+
submit_button = st.form_submit_button(label="Submit", disabled=st.session_state.submit_disabled)
|
| 176 |
+
|
| 177 |
+
if selected_answer and st.session_state.submit_disabled:
|
| 178 |
+
st.session_state.submit_disabled = False
|
| 179 |
|
| 180 |
if submit_button and not current_question.get('answered', False):
|
| 181 |
if selected_answer is None:
|
|
|
|
| 184 |
# Process the answer
|
| 185 |
current_question['selected'] = selected_answer
|
| 186 |
current_question['answered'] = True
|
| 187 |
+
st.session_state.module_question_count[selected_module] += 1
|
| 188 |
|
| 189 |
if selected_answer == current_question['correct_answer']:
|
| 190 |
st.session_state.correct_count += 1
|
| 191 |
+
st.session_state.module_correct_count[selected_module] += 1
|
| 192 |
+
|
| 193 |
+
st.session_state.submit_disabled = True
|
| 194 |
+
st.session_state.next_disabled = False
|
| 195 |
|
| 196 |
# Show correct/incorrect feedback after submission
|
| 197 |
if current_question.get('answered', False):
|
|
|
|
| 208 |
st.write("**Step-by-Step Solution:**")
|
| 209 |
for step in current_question['step_by_step_solution']:
|
| 210 |
st.write(step)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
modules/valid_invalid_numbers.py
CHANGED
|
@@ -1,210 +1,48 @@
|
|
| 1 |
-
|
| 2 |
-
import os
|
| 3 |
-
from fpdf import FPDF
|
| 4 |
-
import uuid
|
| 5 |
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
st.session_state.session_id = str(uuid.uuid4())
|
| 9 |
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
if 'current_index' not in st.session_state:
|
| 13 |
-
st.session_state.current_index = 0
|
| 14 |
-
if 'current_module' not in st.session_state:
|
| 15 |
-
st.session_state.current_module = None
|
| 16 |
-
if 'correct_count' not in st.session_state:
|
| 17 |
-
st.session_state.correct_count = 0
|
| 18 |
-
if 'module_correct_count' not in st.session_state:
|
| 19 |
-
st.session_state.module_correct_count = {}
|
| 20 |
-
if 'module_question_count' not in st.session_state:
|
| 21 |
-
st.session_state.module_question_count = {}
|
| 22 |
-
if 'pdf_data' not in st.session_state:
|
| 23 |
-
st.session_state.pdf_data = None
|
| 24 |
-
if 'submit_disabled' not in st.session_state:
|
| 25 |
-
st.session_state.submit_disabled = True
|
| 26 |
-
if 'next_disabled' not in st.session_state:
|
| 27 |
-
st.session_state.next_disabled = True
|
| 28 |
-
|
| 29 |
-
def reset_pdf_cache():
|
| 30 |
-
st.session_state.pdf_data = None
|
| 31 |
-
|
| 32 |
-
def generate_pdf_report():
|
| 33 |
-
pdf = FPDF()
|
| 34 |
-
pdf.add_page()
|
| 35 |
-
pdf.set_font("Arial", size=12)
|
| 36 |
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
question, options, selected, correct, explanation, step_by_step_solution = (
|
| 51 |
-
entry['question'],
|
| 52 |
-
entry['options'],
|
| 53 |
-
entry['selected'] if entry['selected'] is not None else "Not Answered",
|
| 54 |
-
entry['correct_answer'],
|
| 55 |
-
entry['explanation'],
|
| 56 |
-
entry['step_by_step_solution']
|
| 57 |
-
)
|
| 58 |
-
pdf.multi_cell(0, 10, f"Q: {question}")
|
| 59 |
-
for option in options:
|
| 60 |
-
if option == correct:
|
| 61 |
-
pdf.set_text_color(0, 128, 0) # Green for correct
|
| 62 |
-
pdf.multi_cell(0, 10, f"{option}")
|
| 63 |
-
elif option == selected:
|
| 64 |
-
pdf.set_text_color(255, 0, 0) # Red for incorrect
|
| 65 |
-
pdf.multi_cell(0, 10, f"{option}")
|
| 66 |
-
else:
|
| 67 |
-
pdf.set_text_color(0, 0, 0) # Default color for others
|
| 68 |
-
pdf.multi_cell(0, 10, f" {option}")
|
| 69 |
-
pdf.set_text_color(0, 0, 0) # Reset color
|
| 70 |
-
pdf.multi_cell(0, 10, f"Explanation: {explanation}")
|
| 71 |
-
pdf.ln(5)
|
| 72 |
-
pdf.multi_cell(0, 10, "Step-by-Step Solution:")
|
| 73 |
-
for step in step_by_step_solution:
|
| 74 |
-
pdf.multi_cell(0, 10, step)
|
| 75 |
-
pdf.ln(10)
|
| 76 |
-
|
| 77 |
-
pdf.ln(10) # Add space after each module
|
| 78 |
-
|
| 79 |
-
return pdf.output(dest='S').encode('latin1', 'replace')
|
| 80 |
-
|
| 81 |
-
def load_modules():
|
| 82 |
-
modules = {}
|
| 83 |
-
module_dir = "modules"
|
| 84 |
-
for filename in os.listdir(module_dir):
|
| 85 |
-
if filename.endswith(".py") and filename != "__init__.py":
|
| 86 |
-
module_name = filename[:-3]
|
| 87 |
-
# Dynamically import the module only when needed
|
| 88 |
-
module = __import__(f"{module_dir}.{module_name}", fromlist=[''])
|
| 89 |
-
modules[module_name] = {
|
| 90 |
-
"title": getattr(module, "title", module_name),
|
| 91 |
-
"description": getattr(module, "description", "No description available."),
|
| 92 |
-
"generate_question": module.generate_question # Access the generate_question function
|
| 93 |
-
}
|
| 94 |
-
return modules
|
| 95 |
-
|
| 96 |
-
def generate_new_question(module_name, module):
|
| 97 |
-
question_data = module['generate_question']()
|
| 98 |
-
# Ensure 'answered' is initialized to False and add the 'module' and 'selected' keys
|
| 99 |
-
question_data['answered'] = False
|
| 100 |
-
question_data['module'] = module_name # Add the module name to the question data
|
| 101 |
-
question_data['selected'] = None # Initialize 'selected' to None
|
| 102 |
-
# Ensure there are exactly 4 options
|
| 103 |
-
if len(question_data['options']) != 4:
|
| 104 |
-
st.warning(f"Question in module '{module_name}' does not have 4 options. Found {len(question_data['options'])}.")
|
| 105 |
-
return question_data
|
| 106 |
-
|
| 107 |
-
def navigate_question(direction):
|
| 108 |
-
if direction == "prev" and st.session_state.current_index > 0:
|
| 109 |
-
st.session_state.current_index -= 1
|
| 110 |
-
elif direction == "next":
|
| 111 |
-
new_question = generate_new_question(st.session_state.current_module, modules[st.session_state.current_module])
|
| 112 |
-
st.session_state.questions.append(new_question)
|
| 113 |
-
st.session_state.current_index = len(st.session_state.questions) - 1
|
| 114 |
-
|
| 115 |
-
# Load all modules dynamically
|
| 116 |
-
modules = load_modules()
|
| 117 |
-
|
| 118 |
-
# Streamlit interface
|
| 119 |
-
st.sidebar.title("Quiz Modules")
|
| 120 |
-
module_name = st.sidebar.radio("Choose a module:", [modules[module]["title"] for module in modules], index=0)
|
| 121 |
-
|
| 122 |
-
selected_module = None
|
| 123 |
-
for module in modules:
|
| 124 |
-
if modules[module]["title"] == module_name:
|
| 125 |
-
selected_module = module
|
| 126 |
-
break
|
| 127 |
-
|
| 128 |
-
if selected_module != st.session_state.current_module:
|
| 129 |
-
st.session_state.current_module = selected_module
|
| 130 |
-
st.session_state.current_index = 0
|
| 131 |
-
st.session_state.questions = [generate_new_question(selected_module, modules[selected_module])]
|
| 132 |
-
st.session_state.module_question_count[selected_module] = 0
|
| 133 |
-
st.session_state.module_correct_count[selected_module] = 0
|
| 134 |
-
st.session_state.submit_disabled = True
|
| 135 |
-
st.session_state.next_disabled = True
|
| 136 |
-
|
| 137 |
-
# Load the current module's question
|
| 138 |
-
current_question = st.session_state.questions[st.session_state.current_index]
|
| 139 |
-
|
| 140 |
-
# Display module title and description
|
| 141 |
-
st.title(modules[selected_module]["title"])
|
| 142 |
-
st.write(modules[selected_module]["description"])
|
| 143 |
-
|
| 144 |
-
# Navigation and PDF report buttons
|
| 145 |
-
col1, col2, col3 = st.columns([1, 1, 2])
|
| 146 |
-
with col1:
|
| 147 |
-
if st.button("⬅️ Prev", disabled=st.session_state.current_index == 0):
|
| 148 |
-
navigate_question("prev")
|
| 149 |
-
with col2:
|
| 150 |
-
if st.button("➡️ Next", disabled=st.session_state.next_disabled):
|
| 151 |
-
st.session_state.submit_disabled = True
|
| 152 |
-
st.session_state.next_disabled = True
|
| 153 |
-
navigate_question("next")
|
| 154 |
-
with col3:
|
| 155 |
-
if len(st.session_state.questions) > 0:
|
| 156 |
-
pdf = generate_pdf_report()
|
| 157 |
-
st.session_state.pdf_data = pdf # Reset PDF cache
|
| 158 |
-
st.download_button(
|
| 159 |
-
label="Download PDF Report 📄",
|
| 160 |
-
data=st.session_state.pdf_data,
|
| 161 |
-
file_name="quiz_report.pdf",
|
| 162 |
-
mime="application/pdf"
|
| 163 |
-
)
|
| 164 |
-
|
| 165 |
-
st.write(current_question["question"])
|
| 166 |
-
|
| 167 |
-
# Use a form to prevent rerun on option selection
|
| 168 |
-
with st.form(key=f'question_form_{st.session_state.current_index}'):
|
| 169 |
-
selected_answer = st.radio(
|
| 170 |
-
"Choose an answer:",
|
| 171 |
-
options=current_question['options'],
|
| 172 |
-
key=f"question_{st.session_state.current_index}_options",
|
| 173 |
-
index=None # No pre-selection
|
| 174 |
-
)
|
| 175 |
-
submit_button = st.form_submit_button(label="Submit", disabled=st.session_state.submit_disabled)
|
| 176 |
-
|
| 177 |
-
if selected_answer and st.session_state.submit_disabled:
|
| 178 |
-
st.session_state.submit_disabled = False
|
| 179 |
-
|
| 180 |
-
if submit_button and not current_question.get('answered', False):
|
| 181 |
-
if selected_answer is None:
|
| 182 |
-
st.warning("Please select an answer before submitting.")
|
| 183 |
-
else:
|
| 184 |
-
# Process the answer
|
| 185 |
-
current_question['selected'] = selected_answer
|
| 186 |
-
current_question['answered'] = True
|
| 187 |
-
st.session_state.module_question_count[selected_module] += 1
|
| 188 |
-
|
| 189 |
-
if selected_answer == current_question['correct_answer']:
|
| 190 |
-
st.session_state.correct_count += 1
|
| 191 |
-
st.session_state.module_correct_count[selected_module] += 1
|
| 192 |
|
| 193 |
-
|
| 194 |
-
|
| 195 |
|
| 196 |
-
#
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
if
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
|
|
|
|
|
|
|
|
| 1 |
+
# modules/valid_invalid_numbers.py
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
title = "Validity of Numbers in Bases"
|
| 4 |
+
description = "This module helps determine the validity of numbers in different bases like binary, octal, decimal, and hexadecimal."
|
|
|
|
| 5 |
|
| 6 |
+
def generate_question():
|
| 7 |
+
import random
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
+
base = random.choice([2, 8, 10, 16])
|
| 10 |
+
length = random.randint(3, 5)
|
| 11 |
+
|
| 12 |
+
def generate_valid_number():
|
| 13 |
+
return ''.join([str(random.randint(0, base - 1)) for _ in range(length)])
|
| 14 |
+
|
| 15 |
+
def generate_invalid_number():
|
| 16 |
+
valid_digits = ''.join([str(random.randint(0, base - 1)) for _ in range(length - 1)])
|
| 17 |
+
if base < 10:
|
| 18 |
+
invalid_digit = str(random.randint(base, 9)) # For bases < 10, pick an invalid digit from [base, 9]
|
| 19 |
+
else:
|
| 20 |
+
invalid_digit = random.choice('ABCDEF') # For bases >= 10, pick a hex digit to make it invalid
|
| 21 |
+
return valid_digits + invalid_digit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
+
correct_answer = generate_invalid_number()
|
| 24 |
+
options = [correct_answer]
|
| 25 |
|
| 26 |
+
# Generate valid options
|
| 27 |
+
while len(options) < 4:
|
| 28 |
+
valid_option = generate_valid_number()
|
| 29 |
+
if valid_option not in options:
|
| 30 |
+
options.append(valid_option)
|
| 31 |
+
|
| 32 |
+
random.shuffle(options)
|
| 33 |
+
|
| 34 |
+
question = f"Which of the following is an invalid number in base {base}?"
|
| 35 |
+
explanation = f"The number {correct_answer} is invalid in base {base} because it contains a digit outside the range 0-{base-1}."
|
| 36 |
+
step_by_step_solution = [
|
| 37 |
+
"Step 1: Identify the valid digits for the base.",
|
| 38 |
+
"Step 2: Check each option to see if it contains any invalid digits.",
|
| 39 |
+
"Step 3: The correct answer will have a digit that is not allowed in the specified base."
|
| 40 |
+
]
|
| 41 |
|
| 42 |
+
return {
|
| 43 |
+
"question": question,
|
| 44 |
+
"options": options,
|
| 45 |
+
"correct_answer": correct_answer,
|
| 46 |
+
"explanation": explanation,
|
| 47 |
+
"step_by_step_solution": step_by_step_solution
|
| 48 |
+
}
|