Vorbereitung für Skript für gemischte Brüche
This commit is contained in:
parent
397f32090e
commit
1fb7dd0c3d
594
aufgabengenerator_formulas_fraction_new_c.py
Normal file
594
aufgabengenerator_formulas_fraction_new_c.py
Normal file
@ -0,0 +1,594 @@
|
||||
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
|
||||
# Anzahl der zu generierenden Fragen.
|
||||
NUM_QUESTIONS = 5
|
||||
# Algebraische Struktur der Aufgaben
|
||||
STRUCTURE = "(+)-((+)-(+))"
|
||||
# Gleiche Nenner erlauben
|
||||
SAME_ALLOWED = True
|
||||
# Größter Zähler
|
||||
MAX_NUMERATOR = 10
|
||||
# Größter Nenner
|
||||
MAX_DENOMINATOR = 8
|
||||
# Größter erlaubter gemeinsamer Nenner
|
||||
MAX_COMMON_DENOMINATOR = 100
|
||||
# Dateiname für Ausgabe
|
||||
FILENAME = 'formulas_new_quiz.xml'
|
||||
|
||||
|
||||
def parse_expression(expression):
|
||||
"""Parse an algebraic expression and determine the required number of numbers.
|
||||
|
||||
Args:
|
||||
expression (str): The algebraic expression to parse.
|
||||
|
||||
Returns:
|
||||
int: The total number of numbers required for the expression.
|
||||
"""
|
||||
op_count = 0
|
||||
|
||||
# Count operators in parentheses
|
||||
paren_count = 1
|
||||
max_depth = 0
|
||||
|
||||
for i, char in enumerate(expression):
|
||||
if char in ops.keys():
|
||||
op_count += 1
|
||||
|
||||
return max_depth + op_count + 1
|
||||
|
||||
|
||||
# Anzahl der benötigten Brüche
|
||||
NUM_FRACTIONS = parse_expression(STRUCTURE)
|
||||
|
||||
|
||||
def add_placeholders(expression):
|
||||
"""Add placeholders to the expression for calculation.
|
||||
|
||||
Args:
|
||||
expression (str): The algebraic expression to modify.
|
||||
|
||||
Returns:
|
||||
str: The modified expression with placeholders.
|
||||
"""
|
||||
placeholder_counter = 0 # Zähler für die Platzhalter
|
||||
|
||||
def placeholder_generator():
|
||||
nonlocal placeholder_counter
|
||||
placeholder = f'n{placeholder_counter}'
|
||||
placeholder_counter += 1
|
||||
return placeholder
|
||||
|
||||
output = [] # Ausgabe als Liste zum späteren Zusammensetzen
|
||||
need_placeholder = True # Flag, um zu tracken, ob ein Platzhalter hinzugefügt werden soll
|
||||
|
||||
for char in expression:
|
||||
if char in '+-*/': # Operator gefunden
|
||||
if need_placeholder: # Wenn wir einen Platzhalter brauchen
|
||||
output.append(placeholder_generator())
|
||||
output.append(char) # Fügen Sie den Operator hinzu
|
||||
need_placeholder = True # Nach einem Operator müssen wir wieder einen Platzhalter hinzufügen
|
||||
elif char == '(': # Eine neue Sub-Expression beginnt
|
||||
output.append(char) # Fügen Sie die öffnende Klammer hinzu
|
||||
need_placeholder = True
|
||||
elif char == ')': # Eine Sub-Expression endet
|
||||
if need_placeholder: # Wenn wir einen Platzhalter brauchen
|
||||
output.append(placeholder_generator())
|
||||
output.append(char) # Fügen Sie die schließende Klammer hinzu
|
||||
need_placeholder = False # Nach einer schließenden Klammer erwarten wir keine Platzhalter mehr
|
||||
else: # Bei anderen Zeichen
|
||||
if need_placeholder: # Wenn wir einen Platzhalter brauchen
|
||||
output.append(placeholder_generator())
|
||||
output.append(char) # Fügen Sie das Zeichen hinzu
|
||||
need_placeholder = False # Nach einem Platzhalter sollten wir keinen weiteren setzen
|
||||
|
||||
# Platzhalter am Beginn hinzufügen
|
||||
if output and not (output[0] == f'n{0}' or output[0] == '('):
|
||||
result = [placeholder_generator()] + output
|
||||
else:
|
||||
result = output
|
||||
# Platzhalter am Ende hinzufügen, wenn nötig
|
||||
if output[-1] in '+-*/':
|
||||
result = result + [placeholder_generator()]
|
||||
else:
|
||||
pass
|
||||
|
||||
# Zusammensetzen des finalen Ausdrucks
|
||||
final_expression = ''.join(result).strip()
|
||||
print(final_expression)
|
||||
return final_expression
|
||||
|
||||
|
||||
# Algebraische Struktur mit Platzhaltern
|
||||
STRUCTURE_PH = add_placeholders(STRUCTURE)
|
||||
|
||||
|
||||
def calculate(expression, numbers):
|
||||
"""Calculate the result of the expression using provided numbers.
|
||||
|
||||
Args:
|
||||
expression (str): The algebraic expression with placeholders.
|
||||
numbers (list): A list of numbers to replace the placeholders.
|
||||
|
||||
Returns:
|
||||
float: The calculated result of the expression.
|
||||
"""
|
||||
print(numbers)
|
||||
# Replace placeholders with actual number values
|
||||
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)
|
||||
|
||||
print(expression)
|
||||
# Evaluate the result
|
||||
return eval(expression)
|
||||
|
||||
|
||||
def gen_calculate_string(expression: str, liststring: str):
|
||||
"""Generate a calculation string for the expression with actual number values.
|
||||
|
||||
Args:
|
||||
expression (str): The algebraic expression with placeholders.
|
||||
liststring (str): The list of values to replace the placeholders.
|
||||
|
||||
Returns:
|
||||
str: The modified expression with the list values.
|
||||
"""
|
||||
for i in range(NUM_FRACTIONS):
|
||||
placeholder = f'n{i}'
|
||||
expression = re.sub(rf'\{placeholder}\s*([+-/*])', rf'{liststring}[{i}] \1', expression)
|
||||
expression = re.sub(rf'({placeholder})\s*', rf'{liststring}[{i}]', expression)
|
||||
|
||||
print(expression)
|
||||
return expression
|
||||
|
||||
|
||||
def gen_latex_calculate_string(expression: str, liststring: str):
|
||||
"""Generate a LaTeX-compatible calculation string for the expression.
|
||||
|
||||
Args:
|
||||
expression (str): The algebraic expression with placeholders.
|
||||
liststring (str): A list of LaTeX strings to replace the placeholders.
|
||||
|
||||
Returns:
|
||||
str: The modified expression formatted for LaTeX.
|
||||
"""
|
||||
for i in range(NUM_FRACTIONS):
|
||||
placeholder = f'n{i}'
|
||||
replacement = liststring[i]
|
||||
print(replacement)
|
||||
expression = re.sub(rf'\{placeholder}\s*([+-/*])', replacement, expression)
|
||||
expression = re.sub(rf'({placeholder})\s*', replacement, expression)
|
||||
|
||||
# Klammern anpassen
|
||||
expression = re.sub(rf'\(', u'\\\\left(', expression)
|
||||
expression = re.sub(rf'\)', u'\\\\right)', expression)
|
||||
return expression
|
||||
|
||||
|
||||
def create_html_table_for_fracture_input(rows: list):
|
||||
"""Create an HTML table for displaying fraction inputs.
|
||||
|
||||
Args:
|
||||
rows (list): A list of rows to include in the table.
|
||||
|
||||
Returns:
|
||||
str: The generated HTML table as a string.
|
||||
"""
|
||||
table_rows = []
|
||||
for i, row in enumerate(rows):
|
||||
if (i % 2) == 0:
|
||||
table_row = "<tr style='border-bottom: 1px solid black;'>"
|
||||
else:
|
||||
table_row = "<tr>"
|
||||
|
||||
for cell in row:
|
||||
table_row += f"<td style='padding: 5px;'>{cell}</td>"
|
||||
|
||||
table_row += "</tr>"
|
||||
table_rows.append(table_row)
|
||||
|
||||
# Tabelle zusammenbauen
|
||||
table_html = f"<table style='border-collapse: collapse; display: inline-table;'>\n" + "\n".join(table_rows) + "</table>"
|
||||
|
||||
return table_html
|
||||
|
||||
|
||||
def create_formula_question(ex_number: int):
|
||||
"""Create a formula question based on a random set of fractions.
|
||||
|
||||
Args:
|
||||
ex_number (int): The index number of the exercise being created.
|
||||
|
||||
Returns:
|
||||
Element: The XML element representing the question.
|
||||
"""
|
||||
numerators = []
|
||||
denominators = []
|
||||
for i in range(NUM_FRACTIONS):
|
||||
n = random.randint(1, MAX_NUMERATOR)
|
||||
d = random.randint(2, MAX_DENOMINATOR)
|
||||
numerators.append(n)
|
||||
denominators.append(d)
|
||||
|
||||
# Müssen Nenner unterschiedlich sein?
|
||||
if not SAME_ALLOWED:
|
||||
# Sicherstellen, dass die Nenner unterschiedlich sind
|
||||
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]
|
||||
else:
|
||||
pass
|
||||
|
||||
# Hauptnenner bestimmen
|
||||
*denoms_integers, = denominators # Entpacken der Liste
|
||||
common_denominator = lcm(*denoms_integers)
|
||||
cd = common_denominator
|
||||
|
||||
fractions = []
|
||||
for i in range(NUM_FRACTIONS):
|
||||
fraction = {"n": numerators[i], "d": denominators[i]}
|
||||
fractions.append(fraction)
|
||||
|
||||
expanded_numerators = [frac["n"] * cd // frac["d"] for frac in fractions]
|
||||
|
||||
expanded_fractions = []
|
||||
for i in range(NUM_FRACTIONS):
|
||||
fraction = {"n": expanded_numerators[i], "d": cd}
|
||||
expanded_fractions.append(fraction)
|
||||
|
||||
result_numerator = calculate(STRUCTURE_PH, expanded_numerators)
|
||||
|
||||
gcd_result = gcd(result_numerator, cd)
|
||||
if gcd_result > 1:
|
||||
shortable = True
|
||||
shortened_numerator = result_numerator // gcd_result
|
||||
shortened_denominator = common_denominator // gcd_result
|
||||
else:
|
||||
shortable = False
|
||||
|
||||
# Start der Aufgabe
|
||||
question = ET.Element('question', attrib={'type': 'formulas'})
|
||||
|
||||
# Name der Aufgabe
|
||||
has_plus = '+' in STRUCTURE
|
||||
has_minus = '-' in STRUCTURE
|
||||
has_mult = '*' in STRUCTURE
|
||||
has_div = '/' in STRUCTURE
|
||||
|
||||
if has_plus and has_minus:
|
||||
expression_type = "Addition/Subtraktion" + f" ({STRUCTURE})"
|
||||
exercise_text = "Berechne den Term"
|
||||
elif has_plus:
|
||||
expression_type = "Addition" + f" ({STRUCTURE})"
|
||||
exercise_text = "Addiere die Brüche"
|
||||
elif has_minus:
|
||||
expression_type = "Subtraktion" + f" ({STRUCTURE})"
|
||||
exercise_text = "Subtrahiere die Brüche"
|
||||
else:
|
||||
expression_type = "Rechnung" + f" ({STRUCTURE})"
|
||||
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} ungleichnamigen Brüchen {ex_number}'
|
||||
|
||||
# Allgemeiner Aufgabentext
|
||||
questiontext_elem = ET.SubElement(question, 'questiontext', attrib={'format': 'html'})
|
||||
text_elem = ET.SubElement(questiontext_elem, 'text')
|
||||
if shortable:
|
||||
text_elem.text = f"<![CDATA[ <p>{exercise_text} und kürze das Ergebnis so weit wie möglich.</p>" + "<p>{#A} </p> ]]>"
|
||||
else:
|
||||
text_elem.text = f"<![CDATA[ <p>{exercise_text}.</p>"+"<p>{#A} </p> ]]>"
|
||||
|
||||
# Allgemeines Feedback
|
||||
generalfeedback_elem = ET.SubElement(question, 'generalfeedback', attrib={'format': 'html'})
|
||||
text_elem = ET.SubElement(generalfeedback_elem, 'text')
|
||||
text_elem.text = ' '
|
||||
|
||||
# Grundlegende Bewertungsinformationen
|
||||
ET.SubElement(question, 'defaultgrade').text = '1.0000000'
|
||||
ET.SubElement(question, 'penalty').text = '0.3333333'
|
||||
ET.SubElement(question, 'hidden').text = '0'
|
||||
ET.SubElement(question, 'idnumber').text = ' '
|
||||
|
||||
# Feedback für korrekte und inkorrekte Antworten
|
||||
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> ]]>'''
|
||||
|
||||
ET.SubElement(question, 'shownumcorrect')
|
||||
|
||||
varsrandom_elem = ET.SubElement(question, 'varsrandom')
|
||||
text_elem = ET.SubElement(varsrandom_elem, 'text')
|
||||
text_elem.text = f' '
|
||||
|
||||
# Globale Variablen definieren
|
||||
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}];'
|
||||
|
||||
# Durchnummerierung der Antworten
|
||||
answernumbering_elem = ET.SubElement(question, 'answernumbering')
|
||||
text_elem = ET.SubElement(answernumbering_elem, 'text')
|
||||
text_elem.text = 'ABCD'
|
||||
|
||||
# Antworten definieren
|
||||
answers_elem = ET.SubElement(question, 'answers')
|
||||
|
||||
# Indizes für die Antworten
|
||||
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'
|
||||
|
||||
# Punktzahl auf Teilaufgabe
|
||||
answermark_elem = ET.SubElement(answers_elem, 'answermark')
|
||||
if shortable:
|
||||
ET.SubElement(answermark_elem, 'text').text = '2'
|
||||
else:
|
||||
ET.SubElement(answermark_elem, 'text').text = '1'
|
||||
|
||||
# Antworttyp
|
||||
answertype_elem = ET.SubElement(answers_elem, 'answertype')
|
||||
ET.SubElement(answertype_elem, 'text').text = '0'
|
||||
numbox_elem = ET.SubElement(answers_elem, 'numbox')
|
||||
ET.SubElement(numbox_elem, 'text').text = '2'
|
||||
|
||||
# Berechnungsvariablen
|
||||
# common divisor
|
||||
cdtext = ""
|
||||
for i in range(NUM_FRACTIONS):
|
||||
if i == 0:
|
||||
pass
|
||||
elif i == 1:
|
||||
cdtext += f"cd{i} = lcm(d[{i}],d[{i-1}]);"
|
||||
else:
|
||||
cdtext += f"cd{i} = lcm(cd{i-1}, d[{i}]);"
|
||||
cdtext += f"cd = cd{NUM_FRACTIONS-1};"
|
||||
|
||||
# expansions
|
||||
extext = "e = ["
|
||||
for i in range(NUM_FRACTIONS):
|
||||
extext += f"cd / d[{i}],"
|
||||
extext = extext[:-1]
|
||||
extext += "];"
|
||||
|
||||
# expanded_numerators
|
||||
entext = "ens = ["
|
||||
for i in range(NUM_FRACTIONS):
|
||||
entext += f"n[{i}]*e[{i}],"
|
||||
entext = entext[:-1]
|
||||
entext += "];"
|
||||
|
||||
# result numerator
|
||||
resnum = "resnum = " + gen_calculate_string(STRUCTURE_PH, "ens") + ";"
|
||||
|
||||
# gcd of result numerator and result (common) denominator
|
||||
resgcd = "resgcd = gcd(resnum, cd);"
|
||||
|
||||
# shortened result numerator
|
||||
sresnum = "sresnum = resnum / resgcd;"
|
||||
|
||||
# shortened result denominator
|
||||
sresden = "sresden = cd / resgcd;"
|
||||
|
||||
vars1_elem = ET.SubElement(answers_elem, 'vars1')
|
||||
if shortable:
|
||||
vars1_elem_text = f"<![CDATA[{cdtext}\n {extext}\n {entext}\n {resnum}\n {resgcd}\n {sresnum}\n {sresden}]]>"
|
||||
else:
|
||||
vars1_elem_text = f"<![CDATA[{cdtext}\n {extext}\n {entext}\n {resnum}]]>"
|
||||
ET.SubElement(vars1_elem, 'text').text = vars1_elem_text
|
||||
|
||||
# Antwort
|
||||
answer_elem = ET.SubElement(answers_elem, 'answer')
|
||||
if shortable:
|
||||
answer_text = '[resnum, cd, sresnum, sresden]'
|
||||
else:
|
||||
answer_text = '[resnum, cd]'
|
||||
ET.SubElement(answer_elem, 'text').text = answer_text
|
||||
|
||||
answernotunique_elem = ET.SubElement(answers_elem, 'answernotunique')
|
||||
ET.SubElement(answernotunique_elem, 'text').text = '0'
|
||||
|
||||
vars2_elem = ET.SubElement(answers_elem, 'vars2')
|
||||
if shortable:
|
||||
vars2_elem_text = "<![CDATA[ ga = _0 == resnum && _1 == cd;\n gb = (_0 / _1) == (resnum / cd);\n gsa = _2 == sresnum && _3 == sresden;\n gsb = (_2 / _3) == (sresnum / sresden); ]]>"
|
||||
else:
|
||||
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')
|
||||
if shortable:
|
||||
ET.SubElement(correctness_elem, 'text').text = '0.25*ga + 0.25*gb + 0.25*gsa + 0.25*gsb'
|
||||
else:
|
||||
ET.SubElement(correctness_elem, 'text').text = '0.5*ga + 0.5*gb'
|
||||
|
||||
unitpenalty_elem = ET.SubElement(answers_elem, 'unitpenalty')
|
||||
ET.SubElement(unitpenalty_elem, 'text').text = '1'
|
||||
|
||||
postunit_elem = ET.SubElement(answers_elem, 'postunit')
|
||||
ET.SubElement(postunit_elem, 'text').text = ' '
|
||||
|
||||
ruleid_elem = ET.SubElement(answers_elem, 'ruleid')
|
||||
ET.SubElement(ruleid_elem, 'text').text = '1'
|
||||
|
||||
otherrule_elem = ET.SubElement(answers_elem, 'otherrule')
|
||||
ET.SubElement(otherrule_elem, 'text').text = ' '
|
||||
|
||||
# Unterfragen-Text
|
||||
subqtext_elem = ET.SubElement(answers_elem, 'subqtext', attrib={'format': 'html'})
|
||||
|
||||
fractions_latex_strings = []
|
||||
for i in range(NUM_FRACTIONS):
|
||||
l_str = "\\\\frac{{"+ f"n[{i}]" +"}}{{"+ f"d[{i}]" +"}}"
|
||||
fractions_latex_strings.append(l_str)
|
||||
latex_calculation = gen_latex_calculate_string(STRUCTURE_PH, fractions_latex_strings)
|
||||
|
||||
sub_q_t_begin = "<![CDATA[ <p>Berechne:</p>"
|
||||
sub_q_t_math = "<p>\$\\Large \\displaystyle " + f"{latex_calculation}" + "=\$</p>"
|
||||
rows_list = [
|
||||
["Zähler:", "{_0}"],
|
||||
["Nenner:", "{_1}"]
|
||||
]
|
||||
|
||||
sub_q_t_input = '<div style="display: inline-table"> ='
|
||||
if shortable:
|
||||
sub_q_t_input += create_html_table_for_fracture_input(rows_list)
|
||||
|
||||
rows_list_s = [["Gekürzter Zähler:", "{_2}"],
|
||||
["Gekürzter Nenner:", "{_3}"]]
|
||||
sub_q_t_input += " = "
|
||||
sub_q_t_input += create_html_table_for_fracture_input(rows_list_s)
|
||||
|
||||
else:
|
||||
sub_q_t_input += create_html_table_for_fracture_input(rows_list)
|
||||
sub_q_t_input += '</div>'
|
||||
sub_q_t_end = "]]>"
|
||||
|
||||
sub_question_text = sub_q_t_begin + sub_q_t_math + sub_q_t_input + sub_q_t_end
|
||||
ET.SubElement(subqtext_elem, 'text').text = sub_question_text
|
||||
|
||||
expanded_fractions_latex_strings = []
|
||||
for i in range(NUM_FRACTIONS):
|
||||
l_str = "\\\\frac{{"+ f"ens[{i}]" +"}}{{"+ f"cd" +"}}"
|
||||
expanded_fractions_latex_strings.append(l_str)
|
||||
expanded_latex_calculation = gen_latex_calculate_string(STRUCTURE_PH, expanded_fractions_latex_strings)
|
||||
|
||||
# Lösungshinweis
|
||||
feedback_elem = ET.SubElement(answers_elem, 'feedback', attrib={'format': 'html'})
|
||||
if shortable:
|
||||
feedback_text = '''<![CDATA[ <h4>Lösungshinweis</h4>
|
||||
<p>Die korrekte Lösung ist:</p>
|
||||
<p>\$\\displaystyle''' + f"{latex_calculation}" +" = " + f"{expanded_latex_calculation}" + ''' = \\frac{{resnum}}{{cd}} = \\frac{{sresnum}}{{sresden}} \$ </p> ]]>'''
|
||||
else:
|
||||
feedback_text = '''<![CDATA[ <h4>Lösungshinweis</h4>
|
||||
<p>Die korrekte Lösung ist:</p>
|
||||
<p>\$ \\displaystyle ''' + f"{latex_calculation}" +" = " + f"{expanded_latex_calculation}" + ''' = \\frac{{resnum}}{{cd}} \$ </p> ]]>'''
|
||||
ET.SubElement(feedback_elem, 'text').text = feedback_text
|
||||
|
||||
# correctfeedback
|
||||
correctfeedback_elem = ET.SubElement(answers_elem, 'correctfeedback', attrib={'format': 'html'})
|
||||
correctfeedback_text = '''<![CDATA[ <p>Richtig!</p>]]>'''
|
||||
ET.SubElement(correctfeedback_elem, 'text').text = correctfeedback_text
|
||||
|
||||
# partially correct feedback
|
||||
pcorrectfeedback_elem = ET.SubElement(answers_elem, 'partiallycorrectfeedback', attrib={'format': 'html'})
|
||||
pcorrectfeedback_text = '''<![CDATA[ <p>Teilweise richtig.</p>]]>'''
|
||||
ET.SubElement(pcorrectfeedback_elem, 'text').text = pcorrectfeedback_text
|
||||
|
||||
# incorrect feedback
|
||||
incorrectfeedback_elem = ET.SubElement(answers_elem, 'incorrectfeedback', attrib={'format': 'html'})
|
||||
incorrectfeedback_text = '''<![CDATA[ <p>Leider nicht richtig.</p>]]>'''
|
||||
ET.SubElement(incorrectfeedback_elem, 'text').text = incorrectfeedback_text
|
||||
|
||||
return question
|
||||
|
||||
def generate_questions(num_questions):
|
||||
"""Generates a list of questions.
|
||||
|
||||
Args:
|
||||
num_questions (int): The number of questions to generate.
|
||||
|
||||
Returns:
|
||||
list: A list of question elements.
|
||||
"""
|
||||
questions = []
|
||||
for i in range(num_questions):
|
||||
questions.append(create_formula_question(i))
|
||||
|
||||
return questions
|
||||
|
||||
def create_quiz(questions):
|
||||
"""Creates the overall quiz element.
|
||||
|
||||
Args:
|
||||
questions (list): A list of question elements.
|
||||
|
||||
Returns:
|
||||
Element: The complete quiz element.
|
||||
"""
|
||||
quiz = ET.Element('quiz')
|
||||
for q in questions:
|
||||
quiz.append(q)
|
||||
return quiz
|
||||
|
||||
def save_to_file(xml_element, filename):
|
||||
"""Saves the XML document to a file.
|
||||
|
||||
Args:
|
||||
xml_element (Element): The XML element to save.
|
||||
filename (str): The name of the target file.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
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):
|
||||
"""Replaces special characters in the XML file.
|
||||
|
||||
Args:
|
||||
xml_file (str): The name of the XML file to modify.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# XML-Datei lesen
|
||||
with open(xml_file, 'r') as f:
|
||||
text = f.read()
|
||||
|
||||
text = text.replace("&", "&")
|
||||
text = text.replace("<", "<")
|
||||
text = text.replace(">", ">")
|
||||
|
||||
with open(xml_file, 'w') as f:
|
||||
f.write(text)
|
||||
|
||||
print("Ersetzungen abgeschlossen.")
|
||||
|
||||
# Hauptprogramm
|
||||
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.")
|
||||
|
252
aufgabengenerator_formulas_gem_fraction_new.py
Normal file
252
aufgabengenerator_formulas_gem_fraction_new.py
Normal file
@ -0,0 +1,252 @@
|
||||
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("&", "&")
|
||||
text = text.replace("<", "<")
|
||||
text = text.replace(">", ">")
|
||||
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.")
|
Loading…
Reference in New Issue
Block a user