Sina Media Lab commited on
Commit
984a89c
·
1 Parent(s): 3f5191b
app.py CHANGED
@@ -3,6 +3,7 @@ import importlib
3
  import logging
4
  from fpdf import FPDF
5
  import uuid
 
6
 
7
  # Configure logging
8
  logging.basicConfig(level=logging.INFO)
@@ -63,12 +64,13 @@ def generate_pdf_report():
63
 
64
  for entry in st.session_state.questions:
65
  if entry['module'] == module:
66
- question, options, selected, correct, explanation = (
67
  entry['question'],
68
  entry['options'],
69
  entry['selected'],
70
- entry['correct'],
71
- entry['explanation']
 
72
  )
73
  pdf.multi_cell(0, 10, f"Q: {question}")
74
  for option in options:
@@ -83,6 +85,10 @@ def generate_pdf_report():
83
  pdf.multi_cell(0, 10, f" {option}")
84
  pdf.set_text_color(0, 0, 0) # Reset color
85
  pdf.multi_cell(0, 10, f"Explanation: {explanation}")
 
 
 
 
86
  pdf.ln(10)
87
 
88
  pdf.ln(10) # Add space after each module
@@ -96,16 +102,8 @@ def load_module(module_name):
96
 
97
  def generate_new_question(module_name):
98
  module = load_module(module_name)
99
- question, options, correct_answer, explanation = module.generate_question()
100
- return {
101
- 'module': module_name,
102
- 'question': question,
103
- 'options': options,
104
- 'correct': correct_answer,
105
- 'explanation': explanation,
106
- 'selected': None,
107
- 'answered': False
108
- }
109
 
110
  def navigate_question(direction):
111
  if direction == "prev" and st.session_state.current_index > 0:
@@ -128,38 +126,17 @@ if module_name != st.session_state.current_module:
128
  st.session_state.current_index = 0
129
  st.session_state.questions = [generate_new_question(module_name)]
130
 
131
- # Load the current module for title and description
132
- current_module = load_module(st.session_state.current_module)
133
  current_question = st.session_state.questions[st.session_state.current_index]
134
 
135
  # Display module title and description
136
- st.title(current_module.title)
137
- st.write(current_module.description)
138
-
139
- # Button Row: Prev, Next, and PDF Download
140
- col1, col2, col3 = st.columns([1, 1, 2])
141
- with col1:
142
- st.button("⬅️ Prev", disabled=st.session_state.current_index == 0, on_click=lambda: navigate_question("prev"))
143
- with col2:
144
- st.button("➡️ Next", on_click=lambda: navigate_question("next"))
145
- with col3:
146
- if len(st.session_state.questions) > 0:
147
- pdf = generate_pdf_report()
148
- st.session_state.pdf_data = pdf # Reset PDF cache
149
- st.download_button(
150
- label="Download PDF Report 📄",
151
- data=st.session_state.pdf_data,
152
- file_name="quiz_report.pdf",
153
- mime="application/pdf"
154
- )
155
-
156
- # Display the current question
157
- st.write(f"**Question {st.session_state.current_index + 1}:** {current_question['question']}")
158
 
159
  # Option highlighting logic
160
  def get_option_style(option):
161
  if current_question['answered']:
162
- if option == current_question['correct']:
163
  return "background-color:#d4edda;padding:10px;border-radius:5px;" # Green background for correct
164
  elif option == current_question['selected']:
165
  return "background-color:#f8d7da;padding:10px;border-radius:5px;" # Red background for incorrect
@@ -168,21 +145,27 @@ def get_option_style(option):
168
  selected_answer = st.radio(
169
  "Choose an answer:",
170
  current_question['options'],
171
- index=current_question['options'].index(current_question['selected']) if current_question['selected'] else None,
172
- key=st.session_state.current_index,
173
- format_func=lambda x: f"{x}"
174
  )
175
 
176
  if st.button("Submit"):
177
- if not current_question['answered']:
178
  current_question['selected'] = selected_answer
179
  current_question['answered'] = True
180
  st.session_state.module_question_count[module_name] += 1
181
 
182
- if selected_answer == current_question['correct']:
183
  st.session_state.correct_count += 1
184
  st.session_state.module_correct_count[module_name] += 1
185
 
186
  # Retain and highlight the options after submission
187
  for option in current_question['options']:
188
  st.markdown(f"<div style='{get_option_style(option)}'>{option}</div>", unsafe_allow_html=True)
 
 
 
 
 
 
 
 
3
  import logging
4
  from fpdf import FPDF
5
  import uuid
6
+ import json
7
 
8
  # Configure logging
9
  logging.basicConfig(level=logging.INFO)
 
64
 
65
  for entry in st.session_state.questions:
66
  if entry['module'] == module:
67
+ question, options, selected, correct, explanation, step_by_step_solution = (
68
  entry['question'],
69
  entry['options'],
70
  entry['selected'],
71
+ entry['correct_answer'],
72
+ entry['explanation'],
73
+ entry['step_by_step_solution']
74
  )
75
  pdf.multi_cell(0, 10, f"Q: {question}")
76
  for option in options:
 
85
  pdf.multi_cell(0, 10, f" {option}")
86
  pdf.set_text_color(0, 0, 0) # Reset color
87
  pdf.multi_cell(0, 10, f"Explanation: {explanation}")
88
+ pdf.ln(5)
89
+ pdf.multi_cell(0, 10, "Step-by-Step Solution:")
90
+ for step in step_by_step_solution:
91
+ pdf.multi_cell(0, 10, step)
92
  pdf.ln(10)
93
 
94
  pdf.ln(10) # Add space after each module
 
102
 
103
  def generate_new_question(module_name):
104
  module = load_module(module_name)
105
+ question_data = module.generate_question()
106
+ return question_data
 
 
 
 
 
 
 
 
107
 
108
  def navigate_question(direction):
109
  if direction == "prev" and st.session_state.current_index > 0:
 
126
  st.session_state.current_index = 0
127
  st.session_state.questions = [generate_new_question(module_name)]
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(module_name)
134
+ st.write(current_question["question"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
 
136
  # Option highlighting logic
137
  def get_option_style(option):
138
  if current_question['answered']:
139
+ if option == current_question['correct_answer']:
140
  return "background-color:#d4edda;padding:10px;border-radius:5px;" # Green background for correct
141
  elif option == current_question['selected']:
142
  return "background-color:#f8d7da;padding:10px;border-radius:5px;" # Red background for incorrect
 
145
  selected_answer = st.radio(
146
  "Choose an answer:",
147
  current_question['options'],
148
+ index=current_question['options'].index(current_question['selected']) if current_question.get('selected') else None,
149
+ key=st.session_state.current_index
 
150
  )
151
 
152
  if st.button("Submit"):
153
+ if not current_question.get('answered'):
154
  current_question['selected'] = selected_answer
155
  current_question['answered'] = True
156
  st.session_state.module_question_count[module_name] += 1
157
 
158
+ if selected_answer == current_question['correct_answer']:
159
  st.session_state.correct_count += 1
160
  st.session_state.module_correct_count[module_name] += 1
161
 
162
  # Retain and highlight the options after submission
163
  for option in current_question['options']:
164
  st.markdown(f"<div style='{get_option_style(option)}'>{option}</div>", unsafe_allow_html=True)
165
+
166
+ # Show explanation and step-by-step solution
167
+ if current_question.get('answered'):
168
+ st.write(f"**Explanation:** {current_question['explanation']}")
169
+ st.write("**Step-by-Step Solution:**")
170
+ for step in current_question['step_by_step_solution']:
171
+ st.write(step)
modules/addition_bases.py CHANGED
@@ -1,35 +1,46 @@
1
  import random
2
 
3
- title = "Addition in Different Bases"
4
- description = "This module helps you practice adding numbers in different bases such as binary, octal, and hexadecimal."
5
-
6
  def generate_question():
7
- base = random.choice([2, 8, 16])
8
  num1 = random.randint(1, 15)
9
  num2 = random.randint(1, 15)
10
-
11
- if base == 2:
12
- correct_answer = bin(num1 + num2)[2:]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  elif base == 8:
14
- correct_answer = oct(num1 + num2)[2:]
15
- else:
16
- correct_answer = hex(num1 + num2)[2:]
17
-
18
- question = f"Add {num1} and {num2} in base {base}."
19
- options = [correct_answer]
20
-
21
- # Generate incorrect options
22
- while len(options) < 5:
23
- fake_option = bin(random.randint(1, 30))[2:]
24
- if fake_option not in options:
25
- options.append(fake_option)
26
-
27
- random.shuffle(options)
28
- explanation = (
29
- f"The sum of {num1} and {num2} in base {base} is {correct_answer}."
30
- "\n\n**Step-by-step solution:**\n"
31
- "1. Convert the numbers to decimal if necessary.\n"
32
- "2. Perform the addition in decimal.\n"
33
- "3. Convert the result back to the base if needed."
34
- )
35
- return question, options, correct_answer, explanation
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
+ base = random.choice([2, 8, 10, 16])
5
  num1 = random.randint(1, 15)
6
  num2 = random.randint(1, 15)
7
+
8
+ if base == 10:
9
+ num1_rep = str(num1)
10
+ num2_rep = str(num2)
11
+ elif base == 2:
12
+ num1_rep = bin(num1)[2:]
13
+ num2_rep = bin(num2)[2:]
14
+ elif base == 8:
15
+ num1_rep = oct(num1)[2:]
16
+ num2_rep = oct(num2)[2:]
17
+ elif base == 16:
18
+ num1_rep = hex(num1)[2:].upper()
19
+ num2_rep = hex(num2)[2:].upper()
20
+
21
+ sum_decimal = num1 + num2
22
+ if base == 10:
23
+ correct_answer = str(sum_decimal)
24
+ elif base == 2:
25
+ correct_answer = bin(sum_decimal)[2:]
26
  elif base == 8:
27
+ correct_answer = oct(sum_decimal)[2:]
28
+ elif base == 16:
29
+ correct_answer = hex(sum_decimal)[2:].upper()
30
+
31
+ steps = [
32
+ f"Convert {num1_rep} and {num2_rep} to decimal if needed.",
33
+ f"Add the numbers: {num1} + {num2} = {sum_decimal} in decimal.",
34
+ f"Convert {sum_decimal} from decimal to base {base}.",
35
+ f"The result in base {base} is {correct_answer}."
36
+ ]
37
+
38
+ question_data = {
39
+ "question": f"Add the numbers {num1_rep} and {num2_rep} in base {base}.",
40
+ "options": [correct_answer] + [str(random.randint(1, 30)) for _ in range(3)],
41
+ "correct_answer": correct_answer,
42
+ "explanation": f"The sum of {num1_rep} and {num2_rep} in base {base} is {correct_answer}.",
43
+ "step_by_step_solution": steps
44
+ }
45
+
46
+ return question_data
 
 
modules/conversion_bases.py CHANGED
@@ -1,46 +1,41 @@
1
  import random
2
 
3
- title = "Base Conversion"
4
- description = "This module focuses on converting numbers between different bases, including binary, octal, decimal, and hexadecimal, with and without fractions."
5
-
6
  def generate_question():
7
- num = random.randint(1, 100)
8
- from_base = random.choice([2, 8, 10, 16])
9
- to_base = random.choice([2, 8, 10, 16])
10
-
11
- if from_base == 10:
12
- value = num
13
- elif from_base == 2:
14
- value = int(bin(num)[2:], 2)
15
- elif from_base == 8:
16
- value = int(oct(num)[2:], 8)
17
- else:
18
- value = int(hex(num)[2:], 16)
19
-
20
- if to_base == 2:
21
- correct_answer = bin(value)[2:]
22
- elif to_base == 8:
23
- correct_answer = oct(value)[2:]
24
- elif to_base == 16:
25
- correct_answer = hex(value)[2:]
26
- else:
27
- correct_answer = str(value)
28
-
29
- options = [correct_answer]
30
-
31
- # Generate incorrect options
32
- while len(options) < 5:
33
- fake_option = bin(random.randint(1, 100))[2:]
34
- if fake_option not in options:
35
- options.append(fake_option)
36
-
37
- random.shuffle(options)
38
- question = f"Convert {num} from base {from_base} to base {to_base}."
39
- explanation = (
40
- f"The number {num} in base {from_base} is {correct_answer} in base {to_base}."
41
- "\n\n**Step-by-step solution:**\n"
42
- "1. Convert the number from the original base to decimal if necessary.\n"
43
- "2. Convert the decimal number to the target base.\n"
44
- "3. The correct answer is the result of the conversion."
45
- )
46
- return question, options, correct_answer, explanation
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
+ base_from = random.choice([2, 8, 10, 16])
5
+ base_to = random.choice([2, 8, 10, 16])
6
+ number = random.randint(1, 255)
7
+
8
+ if base_from == 10:
9
+ number_rep = str(number)
10
+ elif base_from == 2:
11
+ number_rep = bin(number)[2:]
12
+ elif base_from == 8:
13
+ number_rep = oct(number)[2:]
14
+ elif base_from == 16:
15
+ number_rep = hex(number)[2:].upper()
16
+
17
+ if base_to == 10:
18
+ correct_answer = str(int(number_rep, base_from))
19
+ elif base_to == 2:
20
+ correct_answer = bin(int(number_rep, base_from))[2:]
21
+ elif base_to == 8:
22
+ correct_answer = oct(int(number_rep, base_from))[2:]
23
+ elif base_to == 16:
24
+ correct_answer = hex(int(number_rep, base_from))[2:].upper()
25
+
26
+ steps = [
27
+ f"Convert the number {number_rep} from base {base_from} to decimal.",
28
+ f"Result: {int(number_rep, base_from)} in decimal.",
29
+ f"Now, convert {int(number_rep, base_from)} from decimal to base {base_to}.",
30
+ f"Final result: {correct_answer}."
31
+ ]
32
+
33
+ question_data = {
34
+ "question": f"Convert the number {number_rep} from base {base_from} to base {base_to}.",
35
+ "options": [correct_answer] + [str(random.randint(1, 255)) for _ in range(3)],
36
+ "correct_answer": correct_answer,
37
+ "explanation": f"The number {number_rep} in base {base_from} is {correct_answer} in base {base_to}.",
38
+ "step_by_step_solution": steps
39
+ }
40
+
41
+ return question_data
 
 
modules/presentation_bases.py CHANGED
@@ -1,36 +1,20 @@
1
  import random
2
 
3
- title = "Presentation in Bases"
4
- description = "This module covers the representation of numbers in different bases including binary, octal, decimal, and hexadecimal."
5
-
6
  def generate_question():
7
- num = random.randint(1, 20)
8
- base = random.choice([2, 8, 10, 16])
9
- if base == 2:
10
- representation = bin(num)[2:]
11
- elif base == 8:
12
- representation = oct(num)[2:]
13
- elif base == 16:
14
- representation = hex(num)[2:]
15
- else:
16
- representation = str(num)
 
 
 
 
 
17
 
18
- question = f"What is the representation of decimal number {num} in base {base}?"
19
- correct_answer = representation
20
- options = [correct_answer]
21
-
22
- # Generate incorrect options
23
- while len(options) < 5:
24
- fake_option = bin(random.randint(1, 20))[2:]
25
- if fake_option not in options:
26
- options.append(fake_option)
27
-
28
- random.shuffle(options)
29
- explanation = (
30
- f"The number {num} in base {base} is represented as {representation}."
31
- "\n\n**Step-by-step solution:**\n"
32
- "1. Convert the number from decimal to the required base.\n"
33
- "2. Match with the provided options.\n"
34
- "3. The correct answer is the one that matches the conversion."
35
- )
36
- return question, options, correct_answer, explanation
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
+ number = random.randint(1, 15)
5
+ binary_rep = bin(number)[2:].zfill(4)
6
+
7
+ question_data = {
8
+ "question": f"What is the binary representation of the decimal number {number}?",
9
+ "options": [bin(i)[2:].zfill(4) for i in random.sample(range(1, 16), 4)],
10
+ "correct_answer": binary_rep,
11
+ "explanation": f"The decimal number {number} is represented as {binary_rep} in binary.",
12
+ "step_by_step_solution": [
13
+ f"1. Start with the decimal number {number}.",
14
+ "2. Divide the number by 2 and note the quotient and remainder.",
15
+ "3. Continue dividing the quotient by 2 until you reach 0.",
16
+ "4. The binary representation is formed by reading the remainders from bottom to top."
17
+ ]
18
+ }
19
 
20
+ return question_data
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
modules/subtraction_bases.py CHANGED
@@ -1,35 +1,46 @@
1
  import random
2
 
3
- title = "Subtraction in Base 2 Using 2's Complement"
4
- description = "This module teaches subtraction in binary using the 2's complement method, which allows subtraction to be performed as an addition operation."
5
-
6
  def generate_question():
7
- num1 = random.randint(1, 7)
8
- num2 = random.randint(1, 7)
9
-
10
- result = num1 - num2
11
- bit_length = 4
12
- if result >= 0:
13
- binary_result = bin(result)[2:].zfill(bit_length)
14
- else:
15
- binary_result = bin((1 << bit_length) + result)[2:]
16
-
17
- question = f"Subtract {num2} from {num1} in base 2 using 2's complement method."
18
- correct_answer = binary_result
19
- options = [correct_answer]
20
-
21
- # Generate incorrect options
22
- while len(options) < 5:
23
- fake_option = bin(random.randint(-7, 7) & 0xF)[2:]
24
- if fake_option not in options:
25
- options.append(fake_option)
26
-
27
- random.shuffle(options)
28
- explanation = (
29
- f"The result of subtracting {num2} from {num1} in base 2 using 2's complement is {binary_result}."
30
- "\n\n**Step-by-step solution:**\n"
31
- "1. Find the 2's complement of the subtracted number.\n"
32
- "2. Add it to the first number.\n"
33
- "3. If there's a carry, discard it. The result is the binary difference."
34
- )
35
- return question, options, correct_answer, explanation
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
+ base = random.choice([2, 8, 10, 16])
5
+ num1 = random.randint(10, 15)
6
+ num2 = random.randint(1, 9)
7
+
8
+ if base == 10:
9
+ num1_rep = str(num1)
10
+ num2_rep = str(num2)
11
+ elif base == 2:
12
+ num1_rep = bin(num1)[2:]
13
+ num2_rep = bin(num2)[2:]
14
+ elif base == 8:
15
+ num1_rep = oct(num1)[2:]
16
+ num2_rep = oct(num2)[2:]
17
+ elif base == 16:
18
+ num1_rep = hex(num1)[2:].upper()
19
+ num2_rep = hex(num2)[2:].upper()
20
+
21
+ difference_decimal = num1 - num2
22
+ if base == 10:
23
+ correct_answer = str(difference_decimal)
24
+ elif base == 2:
25
+ correct_answer = bin(difference_decimal)[2:]
26
+ elif base == 8:
27
+ correct_answer = oct(difference_decimal)[2:]
28
+ elif base == 16:
29
+ correct_answer = hex(difference_decimal)[2:].upper()
30
+
31
+ steps = [
32
+ f"Convert {num1_rep} and {num2_rep} to decimal if needed.",
33
+ f"Subtract the numbers: {num1} - {num2} = {difference_decimal} in decimal.",
34
+ f"Convert {difference_decimal} from decimal to base {base}.",
35
+ f"The result in base {base} is {correct_answer}."
36
+ ]
37
+
38
+ question_data = {
39
+ "question": f"Subtract {num2_rep} from {num1_rep} in base {base}.",
40
+ "options": [correct_answer] + [str(random.randint(1, 10)) for _ in range(3)],
41
+ "correct_answer": correct_answer,
42
+ "explanation": f"The result of subtracting {num2_rep} from {num1_rep} in base {base} is {correct_answer}.",
43
+ "step_by_step_solution": steps
44
+ }
45
+
46
+ return question_data
modules/twos_complement.py CHANGED
@@ -1,32 +1,28 @@
1
  import random
2
 
3
- title = "2's Complement"
4
- description = "This module covers the representation of numbers using the 2's complement method, which is commonly used for representing negative numbers in binary."
5
-
6
  def generate_question():
7
- num = random.randint(-8, 7)
8
- bit_length = 4
9
- if num >= 0:
10
- binary = bin(num)[2:].zfill(bit_length)
11
- else:
12
- binary = bin((1 << bit_length) + num)[2:]
13
-
14
- question = f"What is the 2's complement representation of {num}?"
15
- correct_answer = binary
16
- options = [correct_answer]
17
-
18
- # Generate incorrect options
19
- while len(options) < 5:
20
- fake_option = bin(random.randint(-8, 7) & 0xF)[2:]
21
- if fake_option not in options:
22
- options.append(fake_option)
23
-
24
- random.shuffle(options)
25
- explanation = (
26
- f"The 2's complement representation of {num} is {binary}."
27
- "\n\n**Step-by-step solution:**\n"
28
- "1. If the number is positive, convert it to binary and pad with leading zeros to fit the bit length.\n"
29
- "2. If the number is negative, take its absolute value, convert to binary, invert the digits, and add 1.\n"
30
- "3. The result is the 2's complement representation."
31
- )
32
- return question, options, correct_answer, explanation
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
+ binary_number = bin(random.randint(1, 15))[2:].zfill(4)
5
+
6
+ def twos_complement(binary_str):
7
+ n = len(binary_str)
8
+ ones_complement = ''.join('1' if bit == '0' else '0' for bit in binary_str)
9
+ twos_complement_result = bin(int(ones_complement, 2) + 1)[2:].zfill(n)
10
+ return twos_complement_result[-n:]
11
+
12
+ correct_answer = twos_complement(binary_number)
13
+
14
+ steps = [
15
+ f"Start with the binary number: {binary_number}.",
16
+ f"Find the 1's complement by flipping each bit: {''.join('1' if bit == '0' else '0' for bit in binary_number)}.",
17
+ f"Add 1 to the 1's complement to get the 2's complement: {correct_answer}.",
18
+ ]
19
+
20
+ question_data = {
21
+ "question": f"What is the 2's complement of the binary number {binary_number}?",
22
+ "options": [correct_answer] + [bin(random.randint(1, 15))[2:].zfill(4) for _ in range(3)],
23
+ "correct_answer": correct_answer,
24
+ "explanation": f"The 2's complement of the binary number {binary_number} is {correct_answer}.",
25
+ "step_by_step_solution": steps
26
+ }
27
+
28
+ return question_data
 
modules/valid_invalid_numbers.py CHANGED
@@ -1,8 +1,5 @@
1
  import random
2
 
3
- title = "Validity of Numbers in Bases"
4
- description = "This module helps you determine whether a given number is valid or invalid in various bases like binary, octal, decimal, and hexadecimal."
5
-
6
  def generate_question():
7
  base = random.choice([2, 8, 10, 16])
8
  length = random.randint(3, 5)
@@ -12,25 +9,22 @@ def generate_question():
12
 
13
  def generate_invalid_number():
14
  valid_digits = ''.join([str(random.randint(0, base - 1)) for _ in range(length - 1)])
15
- invalid_digit = str(random.randint(base, base + 1)) if base < 10 else chr(random.randint(ord('A'), ord('F')))
16
  return valid_digits + invalid_digit
17
 
18
  correct_answer = generate_invalid_number()
19
- options = [correct_answer]
20
 
21
- # Generate valid options
22
- while len(options) < 5:
23
- valid_option = generate_valid_number()
24
- if valid_option not in options:
25
- options.append(valid_option)
26
-
27
- random.shuffle(options)
28
- question = f"Which of the following is an invalid number in base {base}?"
29
- explanation = (
30
- f"The number {correct_answer} is invalid in base {base} because it contains a digit outside the range 0-{base-1}."
31
- "\n\n**Step-by-step solution:**\n"
32
- "1. Identify the valid digits for the base.\n"
33
- "2. Check each option to see if it contains any invalid digits.\n"
34
- "3. The correct answer will have a digit that is not allowed in the specified base."
35
- )
36
- return question, options, correct_answer, explanation
 
1
  import random
2
 
 
 
 
3
  def generate_question():
4
  base = random.choice([2, 8, 10, 16])
5
  length = random.randint(3, 5)
 
9
 
10
  def generate_invalid_number():
11
  valid_digits = ''.join([str(random.randint(0, base - 1)) for _ in range(length - 1)])
12
+ invalid_digit = str(random.randint(base, 9))
13
  return valid_digits + invalid_digit
14
 
15
  correct_answer = generate_invalid_number()
16
+ options = [correct_answer] + [generate_valid_number() for _ in range(3)]
17
 
18
+ question_data = {
19
+ "question": f"Which of the following is an invalid number in base {base}?",
20
+ "options": options,
21
+ "correct_answer": correct_answer,
22
+ "explanation": f"The number {correct_answer} is invalid in base {base} because it contains a digit outside the range 0-{base-1}.",
23
+ "step_by_step_solution": [
24
+ "1. Identify the valid digits for the base.",
25
+ f"2. Check each option to see if it contains any invalid digits (greater than {base-1}).",
26
+ "3. The correct answer will have a digit that is not allowed in the specified base."
27
+ ]
28
+ }
29
+
30
+ return question_data