213 lines
9.4 KiB
Python
213 lines
9.4 KiB
Python
|
import xml.etree.ElementTree as ET
|
||
|
import random
|
||
|
from math import gcd
|
||
|
import re
|
||
|
|
||
|
def create_html_table_for_fracture_input(rows: list):
|
||
|
table_rows = []
|
||
|
# Tabellenzeilen festlegen
|
||
|
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;'>\n"
|
||
|
+ "\n".join(table_rows)
|
||
|
+ "</table>"
|
||
|
)
|
||
|
|
||
|
return re.sub("\\s+", " ", table_html)
|
||
|
|
||
|
def create_cloze_question(name, questiontext, question_math, calcstep_math, correct_answers, wrong_answers, feedback, tags):
|
||
|
question = ET.Element('question', attrib={'type': 'cloze'})
|
||
|
|
||
|
name_elem = ET.SubElement(question, 'name')
|
||
|
text_elem = ET.SubElement(name_elem, 'text')
|
||
|
text_elem.text = name
|
||
|
|
||
|
questiontext_elem = ET.SubElement(question, 'questiontext', attrib={'format': 'html'})
|
||
|
text_elem = ET.SubElement(questiontext_elem, 'text')
|
||
|
|
||
|
# Erstelle die Tabelle für die Lücken
|
||
|
|
||
|
rows_list = [
|
||
|
["Zähler:", f"{{1:SHORTANSWER:={correct_answers[0]}~%0%{wrong_answers[0][0]}#{wrong_answers[0][1]}}}"],
|
||
|
["Nenner:", f"{{1:SHORTANSWER:={correct_answers[1]}~%0%{wrong_answers[1][0]}#{wrong_answers[1][1]}}}"]
|
||
|
]
|
||
|
|
||
|
# Prüfe, ob der Bruch gekürzt werden kann
|
||
|
if gcd(correct_answers[0], correct_answers[1]) > 1:
|
||
|
common_divisor = gcd(correct_answers[0], correct_answers[1])
|
||
|
reduced_numerator = correct_answers[0] // common_divisor
|
||
|
reduced_denominator = correct_answers[1] // common_divisor
|
||
|
|
||
|
rows_list.append(["Gekürzter Zähler:", f"{{1:SHORTANSWER:={reduced_numerator}~%0%{wrong_answers[2][0]}#{wrong_answers[2][1]}}}"])
|
||
|
rows_list.append(["Gekürzter Nenner:", f"{{1:SHORTANSWER:={reduced_denominator}~%0%{wrong_answers[3][0]}#{wrong_answers[3][1]}}}"])
|
||
|
|
||
|
cloze_text = create_html_table_for_fracture_input(rows_list)
|
||
|
|
||
|
# Füge die Frage hinzu
|
||
|
text_elem.text = questiontext + " " + cloze_text
|
||
|
|
||
|
generalfeedback_elem = ET.SubElement(question, 'generalfeedback', attrib={'format': 'html'})
|
||
|
text_elem = ET.SubElement(generalfeedback_elem, 'text')
|
||
|
|
||
|
solution = f"<h3>Lösungshinweise:</h3>"
|
||
|
|
||
|
solution += "<p>"
|
||
|
# Musterlösung im LaTeX-Format
|
||
|
if gcd(correct_answers[0], correct_answers[1]) > 1:
|
||
|
solution += f"\\( {question_math} {calcstep_math} = \\frac{{{correct_answers[0]}}}{{{correct_answers[1]}}} = \\frac{{{reduced_numerator}}}{{{reduced_denominator}}} \\)."
|
||
|
else:
|
||
|
solution += f"\\( {question_math} {calcstep_math} = \\frac{{{correct_answers[0]}}}{{{correct_answers[1]}}} \\)"
|
||
|
solution += "</p>"
|
||
|
|
||
|
text_elem.text = solution
|
||
|
|
||
|
defaultgrade_elem = ET.SubElement(question, 'defaultgrade')
|
||
|
defaultgrade_elem.text = '1.0000000'
|
||
|
|
||
|
penalty_elem = ET.SubElement(question, 'penalty')
|
||
|
penalty_elem.text = '0.3333333'
|
||
|
|
||
|
hidden_elem = ET.SubElement(question, 'hidden')
|
||
|
hidden_elem.text = '0'
|
||
|
|
||
|
# Tags hinzufügen
|
||
|
tags_elem = ET.SubElement(question, 'tags')
|
||
|
for tag in tags:
|
||
|
tag_elem = ET.SubElement(tags_elem, 'tag')
|
||
|
text_elem = ET.SubElement(tag_elem, 'text')
|
||
|
text_elem.text = tag
|
||
|
|
||
|
return question
|
||
|
|
||
|
def lcm(a, b):
|
||
|
return abs(a * b) // gcd(a, b)
|
||
|
|
||
|
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)
|
||
|
with open(filename, 'wb') as f:
|
||
|
tree.write(f, encoding='utf-8', xml_declaration=True)
|
||
|
|
||
|
questions = []
|
||
|
|
||
|
# Generiere n Aufgaben zur Addition und Subtraktion von Brüchen mit verschiedenen Nennern
|
||
|
n = 20
|
||
|
for i in range(1, (n+1)):
|
||
|
# Zähler und Nenner generieren
|
||
|
numerator1 = random.randint(1, 20) # Zähler zwischen 1 und 20
|
||
|
numerator2 = random.randint(1, 20) # Zähler zwischen 1 und 20
|
||
|
numerator3 = random.randint(1, 20) # Zähler zwischen 1 und 20
|
||
|
numerator4 = random.randint(1, 20) # Zähler zwischen 1 und 20
|
||
|
denominator1 = random.randint(2, 10) # Nenner zwischen 2 und 10
|
||
|
denominator2 = random.randint(2, 10) # Nenner zwischen 2 und 10
|
||
|
denominator3 = random.randint(2, 10) # Nenner zwischen 2 und 10
|
||
|
denominator4 = random.randint(2, 10) # Nenner zwischen 2 und 10
|
||
|
|
||
|
# Berechne den gemeinsamen Nenner, der kleiner als 30 sein muss
|
||
|
common_denominator = lcm(denominator1, lcm(denominator2, lcm(denominator3, denominator4)))
|
||
|
while common_denominator >= 30:
|
||
|
denominator1 = random.randint(2, 10)
|
||
|
denominator2 = random.randint(2, 10)
|
||
|
denominator3 = random.randint(2, 10)
|
||
|
denominator4 = random.randint(2, 10)
|
||
|
common_denominator = lcm(denominator1, lcm(denominator2, lcm(denominator3, denominator4)))
|
||
|
|
||
|
# Berechne die äquivalenten Zähler
|
||
|
equivalent_numerator1 = numerator1 * (common_denominator // denominator1)
|
||
|
equivalent_numerator2 = numerator2 * (common_denominator // denominator2)
|
||
|
equivalent_numerator3 = numerator3 * (common_denominator // denominator3)
|
||
|
equivalent_numerator4 = numerator4 * (common_denominator // denominator4)
|
||
|
|
||
|
operations = random.choice(["+ + +", "+ + -", "+ - +", "+ - -", "- + +", "- + -", "- - +", "- - -"]) # Zufällige Operationen
|
||
|
if operations == "+ + +":
|
||
|
result_numerator = equivalent_numerator1 + (equivalent_numerator2 + (equivalent_numerator3 + equivalent_numerator4))
|
||
|
elif operations == "+ + -":
|
||
|
result_numerator = equivalent_numerator1 + (equivalent_numerator2 + (equivalent_numerator3 - equivalent_numerator4))
|
||
|
elif operations == "+ - +":
|
||
|
result_numerator = equivalent_numerator1 + (equivalent_numerator2 - (equivalent_numerator3 + equivalent_numerator4))
|
||
|
elif operations == "+ - -":
|
||
|
result_numerator = equivalent_numerator1 + (equivalent_numerator2 - (equivalent_numerator3 - equivalent_numerator4))
|
||
|
elif operations == "- + +":
|
||
|
result_numerator = equivalent_numerator1 - (equivalent_numerator2 + (equivalent_numerator3 + equivalent_numerator4))
|
||
|
elif operations == "- + -":
|
||
|
result_numerator = equivalent_numerator1 - (equivalent_numerator2 + (equivalent_numerator3 - equivalent_numerator4))
|
||
|
elif operations == "- - +":
|
||
|
result_numerator = equivalent_numerator1 - (equivalent_numerator2 - (equivalent_numerator3 + equivalent_numerator4))
|
||
|
else:
|
||
|
result_numerator = equivalent_numerator1 - (equivalent_numerator2 - (equivalent_numerator3 - equivalent_numerator4))
|
||
|
|
||
|
# Prüfe, ob der Bruch gekürzt werden kann
|
||
|
needs_reduction = gcd(result_numerator, common_denominator) > 1
|
||
|
|
||
|
question_puremath = f"\\Large \\displaystyle \\frac{{{numerator1}}}{{{denominator1}}} {operations[0]} \\left(\\frac{{{numerator2}}}{{{denominator2}}} {operations[2]} \\left(\\frac{{{numerator3}}}{{{denominator3}}} {operations[4]} \\frac{{{numerator4}}}{{{denominator4}}}\\right)\\right) ="
|
||
|
|
||
|
# Frage im LaTeX-Format
|
||
|
questiontext = (f"<p>Berechne und kürze das Ergebnis, wenn möglich:</p> "
|
||
|
f"<p> \\( {question_puremath} \\) </p>")
|
||
|
|
||
|
# Feedback-Ausgabe für notwendigen Zwischenschritt
|
||
|
calculation_step_math = (f"\\frac{{{equivalent_numerator1}}}{{{common_denominator}}} {operations[0]} "
|
||
|
f"\\left(\\frac{{{equivalent_numerator2}}}{{{common_denominator}}} {operations[2]} "
|
||
|
f"\\left(\\frac{{{equivalent_numerator3}}}{{{common_denominator}}} {operations[4]} "
|
||
|
f"\\frac{{{equivalent_numerator4}}}{{{common_denominator}}}\\right)\\right)")
|
||
|
|
||
|
# Antworten
|
||
|
correct_answers = [result_numerator, common_denominator]
|
||
|
if needs_reduction:
|
||
|
common_divisor = gcd(result_numerator, common_denominator)
|
||
|
reduced_numerator = result_numerator // common_divisor
|
||
|
reduced_denominator = common_denominator // common_divisor
|
||
|
|
||
|
correct_answers.extend([reduced_numerator, reduced_denominator]) # Füge gekürzte Antworten hinzu
|
||
|
|
||
|
wrong_answers = [
|
||
|
(result_numerator + random.randint(1, 5), "Dieser Zähler ist zu hoch."), # Falscher Zähler
|
||
|
(result_numerator - random.randint(1, 5), "Dieser Zähler ist zu niedrig."), # Falscher Zähler
|
||
|
(reduced_numerator + random.randint(1, 3), "Dieser gekürzte Zähler ist nicht korrekt."), # Falscher gekürzter Zähler
|
||
|
(reduced_denominator - random.randint(1, 3), "Dieser gekürzte Nenner ist nicht korrekt.") # Falscher gekürzter Nenner
|
||
|
]
|
||
|
else:
|
||
|
wrong_answers = [
|
||
|
(result_numerator + random.randint(1, 5), "Dieser Zähler ist zu hoch."), # Falscher Zähler
|
||
|
(result_numerator - random.randint(1, 5), "Dieser Zähler ist zu niedrig.") # Falscher Zähler
|
||
|
]
|
||
|
|
||
|
feedback = "Richtig! Die Lösung ist korrekt."
|
||
|
|
||
|
# Frage erstellen und hinzufügen
|
||
|
questions.append(create_cloze_question(
|
||
|
f"Addition/Subtraktion von 4 ungleichnamigen Brüchen {i}",
|
||
|
questiontext,
|
||
|
question_puremath,
|
||
|
calculation_step_math,
|
||
|
correct_answers,
|
||
|
wrong_answers,
|
||
|
feedback,
|
||
|
["Mathematik", "Brüche", "Addition", "Subtraktion"]
|
||
|
))
|
||
|
|
||
|
# Erstelle das Quiz
|
||
|
quiz = create_quiz(questions)
|
||
|
|
||
|
# Speichere die XML-Datei
|
||
|
save_to_file(quiz, 'cloze_4fraction_addition_subtraction_quiz.xml')
|
||
|
|
||
|
print("Moodle-XML-Datei 'cloze_4fraction_addition_subtraction_quiz.xml' erfolgreich erstellt.")
|