diff --git a/aufgabengenerator_formulas_fraction_new.py b/aufgabengenerator_formulas_fraction_new.py index 953a6eb..d113bda 100644 --- a/aufgabengenerator_formulas_fraction_new.py +++ b/aufgabengenerator_formulas_fraction_new.py @@ -15,13 +15,15 @@ ops = { # Konstanten # Anzahl der zu generierenden Fragen. -NUM_QUESTIONS = 1 +NUM_QUESTIONS = 5 # Algebraische Struktur der Aufgaben -STRUCTURE = "-(+)-" +STRUCTURE = "(-)-(+(-))" +# Gleiche Nenner erlauben +# TODO # Größter Zähler -MAX_NUMERATOR = 20 +MAX_NUMERATOR = 10 # Größter Nenner -MAX_DENOMINATOR = 20 +MAX_DENOMINATOR = 8 # Größter erlaubter gemeinsamer Nenner MAX_COMMON_DENOMINATOR = 100 # Dateiname für Ausgabe @@ -36,18 +38,18 @@ def parse_expression(expression): 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 == '(': + # 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 + return max_depth + op_count + 1 # Anzahl der benötigten Brüche NUM_FRACTIONS = parse_expression(STRUCTURE) @@ -87,7 +89,7 @@ def add_placeholders(expression): need_placeholder = False # Nach einem Platzhalter sollten wir keinen weiteren setzen # Platzhalter am Beginn hinzufügen - if output and output[0] != f'n{0}': + if output and not (output[0] == f'n{0}' or output[0] == '('): result = [placeholder_generator()] + output else: result = output @@ -99,6 +101,7 @@ def add_placeholders(expression): # Zusammensetzen des finalen Ausdrucks final_expression = ''.join(result).strip() + print(final_expression) return final_expression @@ -119,6 +122,54 @@ def calculate(expression, numbers): # Evaluate the result return eval(expression) +def gen_calculate_string(expression :str, liststring :str): + # Replace placeholders with actual number 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 the changed expression + return expression + +def gen_latex_calculate_string(expression :str, liststring: str): + # Replace placeholders with actual number values + 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) + # print(expression) + # Return the changed expression + return expression + +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 = "" + else: + table_row = "" + + for cell in row: + table_row += f"{cell}" + + table_row += "" + table_rows.append(table_row) + + # Tabelle zusammenbauen + table_html = f"\n" + "\n".join(table_rows) + "
" + + return table_html + + def create_formula_question(ex_number: int): numerators = [] denominators = [] @@ -132,7 +183,12 @@ def create_formula_question(ex_number: int): 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) + try: + index = denominators.index(same_denominators[0]) + denominators[index] = new_denom + except ValueError: + pass + # denominators.replace(same_denominators[0], new_denom) same_denominators = [k for k,v in Counter(denominators).items() if v>1] # [DEBUG] print(numerators) @@ -165,11 +221,12 @@ def create_formula_question(ex_number: int): result_numerator = calculate(STRUCTURE_PH, expanded_numerators) # [DEBUG] print(result_numerator) + print(cd) # [DEBUG] gcd_result = gcd(result_numerator, cd) if gcd_result > 1: - # print("kürzbar") + print("kürzbar") shortable = True shortened_numerator = result_numerator // gcd_result shortened_denominator = common_denominator // gcd_result @@ -186,16 +243,16 @@ def create_formula_question(ex_number: int): has_div = '/' in STRUCTURE if has_plus and has_minus: - expression_type = "Addition/Subtraktion" + expression_type = "Addition/Subtraktion" + f" ({STRUCTURE})" exercise_text = "Berechne den Term" elif has_plus: - expression_type = "Addition" + expression_type = "Addition" + f" ({STRUCTURE})" exercise_text = "Addiere die Brüche" elif has_minus: - expression_type = "Subtraktion" + expression_type = "Subtraktion" + f" ({STRUCTURE})" exercise_text = "Subtrahiere die Brüche" else: - expression_type = "Rechnung" + expression_type = "Rechnung" + f" ({STRUCTURE})" exercise_text = "Berechne den Term" name_elem = ET.SubElement(question, 'name') text_elem = ET.SubElement(name_elem, 'text') @@ -272,16 +329,160 @@ def create_formula_question(ex_number: int): ET.SubElement(answertype_elem, 'text').text = '0' numbox_elem = ET.SubElement(answers_elem, 'numbox') ET.SubElement(numbox_elem, 'text').text = '2' - return question + # 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 = "" + vars1_elem_text = f"" else: - vars1_elem_text = "" + vars1_elem_text = f"" 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 = "" + else: + vars2_elem_text = "" + 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 = "Berechne:

" + sub_q_t_math = "

\\(\\Large \\displaystyle " + f"{latex_calculation}" + "=\\)

" + rows_list = [ + ["Zähler:", "{_0}"], + ["Nenner:", "{_1}"] + ] + + sub_q_t_input = '
=' + 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 += '
' + 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 = '''Lösungshinweis +

Die korrekte Lösung ist:

+

\\(\\displaystyle''' + f"{latex_calculation}" +" = " + f"{expanded_latex_calculation}" + ''' = \\frac{{resnum}}{{cd}} = \\frac{{sresnum}}{{sresden}} \\)

]]>''' + else: + feedback_text = '''Lösungshinweis +

Die korrekte Lösung ist:

+

\\( \\displaystyle ''' + f"{latex_calculation}" +" = " + f"{expanded_latex_calculation}" + ''' = \\frac{{resnum}}{{cd}} \\)

]]>''' + ET.SubElement(feedback_elem, 'text').text = feedback_text + + # correctfeedback + + correctfeedback_elem = ET.SubElement(answers_elem, 'correctfeedback', attrib={'format': 'html'}) + correctfeedback_text = '''Richtig!

]]>''' + ET.SubElement(correctfeedback_elem, 'text').text = correctfeedback_text + + # partially correct feedback + + pcorrectfeedback_elem = ET.SubElement(answers_elem, 'partiallycorrectfeedback', attrib={'format': 'html'}) + pcorrectfeedback_text = '''Teilweise richtig.

]]>''' + ET.SubElement(pcorrectfeedback_elem, 'text').text = pcorrectfeedback_text + + # incorrect feedback + incorrectfeedback_elem = ET.SubElement(answers_elem, 'incorrectfeedback', attrib={'format': 'html'}) + incorrectfeedback_text = '''Leider nicht richtig.

]]>''' + ET.SubElement(incorrectfeedback_elem, 'text').text = incorrectfeedback_text + + return question def generate_questions(num_questions): @@ -328,6 +529,7 @@ def save_to_file(xml_element, filename): 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)