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 = 1 # Algebraische Struktur der Aufgaben STRUCTURE = "-(+)-" # Größter Zähler MAX_NUMERATOR = 20 # Größter Nenner MAX_DENOMINATOR = 20 # 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""" op_count = 0 # Count operators in parentheses paren_count = 1 max_depth = 0 for i, char in enumerate(expression): if char == '(': paren_count += 1 elif char == ')': paren_count -= 1 # Update max depth when a closed parenthesis is encountered max_depth = max(max_depth, paren_count) if char in ops.keys(): op_count += 1 return max_depth + op_count # Anzahl der benötigten Brüche NUM_FRACTIONS = parse_expression(STRUCTURE) # Platzhalter hinzufügen def add_placeholders(expression): 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 output[0] != f'n{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() return final_expression # Algebraische Struktur mit Platzhaltern STRUCTURE_PH = add_placeholders(STRUCTURE) def calculate(expression, numbers): """Calculate the result of the expression using n[0], n[1], ...""" # numbers = [random.randint(1, 10) for _ in range(num)] 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 create_formula_question(ex_number: int): 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) # 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) denominators.replace(same_denominators[0], new_denom) same_denominators = [k for k,v in Counter(denominators).items() if v>1] # [DEBUG] print(numerators) print(denominators) # [DEBUG] # Hauptnenner bestimmen *denoms_integers, = denominators 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) # [DEBUG] print(fractions) # [DEBUG] 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) # [DEBUG] print(expanded_fractions) # [DEBUG] result_numerator = calculate(STRUCTURE_PH, expanded_numerators) # [DEBUG] print(result_numerator) # [DEBUG] gcd_result = gcd(result_numerator, cd) if gcd_result > 1: # print("kürzbar") 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" exercise_text = "Berechne den Term" elif has_plus: expression_type = "Addition" exercise_text = "Addiere die Brüche" elif has_minus: expression_type = "Subtraktion" exercise_text = "Subtrahiere die 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} 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"{exercise_text} und kürze das Ergebnis so weit wie möglich.
" + "{#A}
]]>" else: text_elem.text = f"{exercise_text}."+"{#A}
]]>" # 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 = '''Die Antwort ist richtig. ]]> ''' partiallycorrectfeedback_elem = ET.SubElement(question, 'partiallycorrectfeedback', attrib={'format': 'html'}) text_elem = ET.SubElement(partiallycorrectfeedback_elem, 'text') text_elem.text = '''Die Antwort ist teilweise richtig. ]]> ''' incorrectfeedback_elem = ET.SubElement(question, 'incorrectfeedback', attrib={'format': 'html'}) text_elem = ET.SubElement(incorrectfeedback_elem, 'text') text_elem.text = '''Die Antwort ist falsch. ]]>''' 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' return question # Berechnungsvariablen vars1_elem = ET.SubElement(answers_elem, 'vars1') if shortable: vars1_elem_text = "" else: vars1_elem_text = "" ET.SubElement(vars1_elem, 'text').text = vars1_elem_text def generate_questions(num_questions): """ Generiert eine Liste von Aufgaben. Args: num_questions (int): Die Anzahl der zu generierenden Fragen. Returns: list: Eine Liste von Frage-Elementen. """ questions = [] for i in range(num_questions): # Hier können Sie die Funktionsdefinition für die Erzeugung einer Aufgabe hinzufügen questions.append(create_formula_question(i)) return questions def create_quiz(questions): """ Erstellt das gesamte Quiz-Element. Args: questions (list): Eine Liste von Frage-Elementen. Returns: Element: Das gesamte Quiz -Element. """ quiz = ET.Element('quiz') for q in questions: quiz.append(q) return quiz def save_to_file(xml_element, filename): """ Speichert das XML-Dokument in eine Datei. Args: xml_element (Element): Das XML-Element, zu speichern. filename (str): Der Name der Zieldatei. Returns: None """ tree = ET.ElementTree(xml_element) with open(filename, 'wb') as f: tree.write(f, encoding='utf_8', xml_declaration=True) return def replace_vars2(xml_file): # 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) # 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.")