mdlAufgabengeneratoren/aufgabengenerator_formulas_gem_fraction_new.py

253 lines
9.4 KiB
Python
Raw Permalink Normal View History

import random
import operator
import re
from math import gcd, lcm
import xml.etree.ElementTree as ET
from collections import Counter
# Define operators and their corresponding functions
ops = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv
}
# Konstanten
NUM_QUESTIONS = 5
STRUCTURE = "(+)-((+)-(+))"
SAME_ALLOWED = True
MAX_WHOLE = 5 # Größte ganze Zahl für gemischte Brüche
MAX_NUMERATOR = 10 # Größter Zähler
MAX_DENOMINATOR = 8 # Größter Nenner
MAX_COMMON_DENOMINATOR = 100
FILENAME = 'formulas_new_quiz.xml'
def parse_expression(expression):
op_count = 0
for char in expression:
if char in ops.keys():
op_count += 1
return op_count + 1
NUM_FRACTIONS = parse_expression(STRUCTURE)
def add_placeholders(expression):
placeholder_counter = 0
def placeholder_generator():
nonlocal placeholder_counter
placeholder = f'n{placeholder_counter}'
placeholder_counter += 1
return placeholder
output = []
need_placeholder = True
for char in expression:
if char in '+-*/':
if need_placeholder:
output.append(placeholder_generator())
output.append(char)
need_placeholder = True
elif char == '(':
output.append(char)
need_placeholder = True
elif char == ')':
if need_placeholder:
output.append(placeholder_generator())
output.append(char)
need_placeholder = False
else:
if need_placeholder:
output.append(placeholder_generator())
output.append(char)
need_placeholder = False
if output and not (output[0] == f'n{0}' or output[0] == '('):
result = [placeholder_generator()] + output
else:
result = output
if output[-1] in '+-*/':
result = result + [placeholder_generator()]
final_expression = ''.join(result).strip()
return final_expression
STRUCTURE_PH = add_placeholders(STRUCTURE)
def calculate(expression, numbers):
for i, num in enumerate(numbers):
placeholder = f'n{i}'
expression = re.sub(rf'\{placeholder}\s*([+-/*])', rf'{num} \1', expression)
expression = re.sub(rf'({placeholder})\s*', rf'{num}', expression)
return eval(expression)
def create_mixed_fraction():
"""Generates a random mixed fraction represented as a dictionary."""
whole = random.randint(1, MAX_WHOLE)
numerator = random.randint(1, MAX_NUMERATOR)
denominator = random.randint(2, MAX_DENOMINATOR)
return {
"whole": whole,
"numerator": numerator,
"denominator": denominator
}
def create_formula_question(ex_number: int):
numerators = []
denominators = []
mixed_fractions = []
for i in range(NUM_FRACTIONS):
mixed_fraction = create_mixed_fraction()
mixed_fractions.append(mixed_fraction)
# Convert mixed fraction to improper fraction for calculation
improper_numerator = mixed_fraction["whole"] * mixed_fraction["denominator"] + mixed_fraction["numerator"]
numerators.append(improper_numerator)
denominators.append(mixed_fraction["denominator"])
if not SAME_ALLOWED:
same_denominators = [k for k, v in Counter(denominators).items() if v > 1]
while len(same_denominators) > 1:
new_denom = random.randint(2, MAX_DENOMINATOR)
try:
index = denominators.index(same_denominators[0])
denominators[index] = new_denom
except ValueError:
pass
same_denominators = [k for k, v in Counter(denominators).items() if v > 1]
*denoms_integers, = denominators
common_denominator = lcm(*denoms_integers)
expanded_numerators = [(frac["whole"] * frac["denominator"] + frac["numerator"]) * common_denominator // frac["denominator"] for frac in mixed_fractions]
result_numerator = calculate(STRUCTURE_PH, expanded_numerators)
gcd_result = gcd(result_numerator, common_denominator)
shortable = gcd_result > 1
shortened_numerator = result_numerator // gcd_result if shortable else result_numerator
shortened_denominator = common_denominator // gcd_result if shortable else common_denominator
question = ET.Element('question', attrib={'type': 'formulas'})
has_plus = '+' in STRUCTURE
has_minus = '-' in STRUCTURE
if has_plus and has_minus:
expression_type = "Addition/Subtraktion"
exercise_text = "Berechne den Term"
elif has_plus:
expression_type = "Addition"
exercise_text = "Addiere die gemischten Brüche"
elif has_minus:
expression_type = "Subtraktion"
exercise_text = "Subtrahiere die gemischten Brüche"
else:
expression_type = "Rechnung"
exercise_text = "Berechne den Term"
name_elem = ET.SubElement(question, 'name')
text_elem = ET.SubElement(name_elem, 'text')
text_elem.text = f'{expression_type} von {NUM_FRACTIONS} gemischten Brüchen {ex_number}'
questiontext_elem = ET.SubElement(question, 'questiontext', attrib={'format': 'html'})
text_elem = ET.SubElement(questiontext_elem, 'text')
text_elem.text = f"<![CDATA[ <p>{exercise_text} und kürze das Ergebnis so weit wie möglich.</p>" + "<p>{#A} </p> ]]>"
generalfeedback_elem = ET.SubElement(question, 'generalfeedback', attrib={'format': 'html'})
text_elem = ET.SubElement(generalfeedback_elem, 'text')
text_elem.text = ' '
ET.SubElement(question, 'defaultgrade').text = '1.0000000'
ET.SubElement(question, 'penalty').text = '0.3333333'
ET.SubElement(question, 'hidden').text = '0'
correctfeedback_elem = ET.SubElement(question, 'correctfeedback', attrib={'format': 'html'})
text_elem = ET.SubElement(correctfeedback_elem, 'text')
text_elem.text = '''<![CDATA[ <p>Die Antwort ist richtig.</p> ]]> '''
partiallycorrectfeedback_elem = ET.SubElement(question, 'partiallycorrectfeedback', attrib={'format': 'html'})
text_elem = ET.SubElement(partiallycorrectfeedback_elem, 'text')
text_elem.text = '''<![CDATA[ <p>Die Antwort ist teilweise richtig.</p> ]]> '''
incorrectfeedback_elem = ET.SubElement(question, 'incorrectfeedback', attrib={'format': 'html'})
text_elem = ET.SubElement(incorrectfeedback_elem, 'text')
text_elem.text = '''<![CDATA[ <p>Die Antwort ist falsch.</p> ]]>'''
varsrandom_elem = ET.SubElement(question, 'varsrandom')
text_elem = ET.SubElement(varsrandom_elem, 'text')
text_elem.text = f' '
varsglobal_elem = ET.SubElement(question, 'varsglobal')
text_elem = ET.SubElement(varsglobal_elem, 'text')
numerators_string = ",".join([str(n) for n in numerators])
denominators_string = ",".join([str(d) for d in denominators])
text_elem.text = f'n = [{numerators_string}];\n d = [{denominators_string}];'
answers_elem = ET.SubElement(question, 'answers')
partindex_elem = ET.SubElement(answers_elem, 'partindex')
ET.SubElement(partindex_elem, 'text').text = '0'
placeholder_elem = ET.SubElement(answers_elem, 'placeholder')
ET.SubElement(placeholder_elem, 'text').text = '#A'
answermark_elem = ET.SubElement(answers_elem, 'answermark')
ET.SubElement(answermark_elem, 'text').text = '2' if shortable else '1'
answer_elem = ET.SubElement(answers_elem, 'answer')
answer_text = '[resnum, cd, sresnum, sresden]' if shortable else '[resnum, cd]'
ET.SubElement(answer_elem, 'text').text = answer_text
vars1_elem = ET.SubElement(answers_elem, 'vars1')
vars1_elem_text = f"<![CDATA[resnum = {result_numerator}; cd = {common_denominator}; sresnum = {shortened_numerator}; sresden = {shortened_denominator};]]>"
ET.SubElement(vars1_elem, 'text').text = vars1_elem_text
vars2_elem = ET.SubElement(answers_elem, 'vars2')
vars2_elem_text = "<![CDATA[ ga = _0 == resnum && _1 == cd; gb = (_0 / _1) == (resnum / cd); ]]>"
ET.SubElement(vars2_elem, 'text').text = vars2_elem_text
correctness_elem = ET.SubElement(answers_elem, 'correctness')
ET.SubElement(correctness_elem, 'text').text = '0.5*ga + 0.5*gb'
feedback_elem = ET.SubElement(answers_elem, 'feedback', attrib={'format': 'html'})
feedback_text = '''<![CDATA[ <h4>Lösungshinweis</h4>
<p>Die korrekte Lösung ist:</p>
<p>\\(\\displaystyle''' + f"{result_numerator}/{common_denominator}" + '''\\)</p> ]]>'''
ET.SubElement(feedback_elem, 'text').text = feedback_text
return question
def generate_questions(num_questions):
questions = []
for i in range(num_questions):
questions.append(create_formula_question(i))
return questions
def create_quiz(questions):
quiz = ET.Element('quiz')
for q in questions:
quiz.append(q)
return quiz
def save_to_file(xml_element, filename):
tree = ET.ElementTree(xml_element)
ET.indent(tree, space="\t", level=0)
with open(filename, 'wb') as f:
tree.write(f, encoding='utf_8', xml_declaration=True)
return 0
def replace_vars2(xml_file):
with open(xml_file, 'r') as f:
text = f.read()
text = text.replace("&amp;", "&")
text = text.replace("&lt;", "<")
text = text.replace("&gt;", ">")
with open(xml_file, 'w') as f:
f.write(text)
print("Ersetzungen abgeschlossen.")
if __name__ == "__main__":
questions = generate_questions(NUM_QUESTIONS)
quiz = create_quiz(questions)
save_to_file(quiz, FILENAME)
replace_vars2(FILENAME)
print("Moodle-XMLDatei erfolgreich erstellt.")