Welche Datenstruktur für Multiple-Choice-Fragentrainer

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Sirius3
User
Beiträge: 17822
Registriert: Sonntag 21. Oktober 2012, 17:20

Durch einfache mathematische Operationen läßt sich mancher Code viel klarer schreiben:

Code: Alles auswählen

HEADING_ANGLE = {
    "Gegenanflug": -180,
    "Rechter Gegenanflug": -180,
    "Queranflug": 90,
    "Rechter Queranflug": -90,
}

def calculate_current_heading(flight_position, heading):
    return (heading + HEADING_ANGLE[flight_position]) % 360
In `check_for_three_values` stellt sich die Frage, was passiert, wenn current_heading einstellig ist? Deshalb sollte man Formatstrings benutzen (und einen besseren Funktionsnamen):

Code: Alles auswählen

def format_heading(heading):
    return f"{heading:03d}"
`number_of_questions` sollte eigentlich `question_ids` heißen, und ab 1 loslaufen:

Code: Alles auswählen

def question_ids():
    return [number for number, _ in enumerate(QUESTIONS, 1)
Und alle anderen Funktionen sollten dann auch mit IDs ab 1 zurecht kommen.
`get_answers_in_random_order` ist unnötigerweise auf 4 Antworten festgelegt. Mit shuffle wäre das klarer:

Code: Alles auswählen

def get_answers_in_random_order(question_id):
    answers = list(QUESTIONS[question_id - 1]["answers"])
    random.shuffle(answers)
    return answers
`get_right_answer` liefert gar nicht die korrekte Antwort, sondern prüft ob die Antwort korrekt ist.

Code: Alles auswählen

def check_right_answer(question_id, answer):
    return answer == QUESTIONS[question_id - 1]["answers"][0]
`answer` ist bereits ein String, das nochmal umzuwandeln ist unnötig. `chose_question`, `next_question` und `previous_question` haben viel kopierten Code. `try`-Blöcke sollten so kurz wie möglich sein. Warum heißt die `question_id` im `index.html` `answer`? Das macht den Code in `chose_question` verwirrend?

Code: Alles auswählen

def render_question(question_id, rating=None, answers=None):
    if answers is None:
        answers = get_answers_in_random_order(question_id)
    return render_template(
        "question.html",
        question=get_question(question_id),
        id=question_id,
        answers=answers,
        answers_json=dumps(answers),
        rating=rating,
    )


@app.route("/question", methods=["GET", "POST"])
def chose_question():
    question_id = int(request.form["id"])
    return render_question(question_id)


@app.route("/answer", methods=["GET", "POST"])
def check_answer():
    question_id = int(request.form["id"])
    answer = request.form["answer"]
    answers = loads(request.form["answers_json"])
    rating = (
        f"Richtig!\n{answer}" if get_right_answer(question_id, answer) else "Falsch!"
    )
    return render_question(question_id, rating, answers)


@app.route("/next", methods=["GET", "POST"])
def next_question():
    question_id = int(request.form["id"]) + 1
    try:
        _ = get_question(question_id)
    except IndexError:
        return render_template("finish.html")
    return render_question(question_id)


@app.route("/back", methods=["GET", "POST"])
def previous_question():
    question_id = int(request.form["id"]) - 1
    if question_id < 1:
        return index()
    return render_question(question_id)
Benutzeravatar
Dennis89
User
Beiträge: 1215
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo und vielen Dank für die ausführliche Rückmeldung.

Ich denke, die Fragen muss ich so nicht beantworten, weil die Antwort ist entweder "Habe ich nicht beachtet" oder "Stimmt, mein Fehler".
Ich habe alles umgesetzt und es funktioniert.

Eine Frage habe ich noch, jetzt wird in 'render_question' für 'answer' ein Default-Wert gesetzt und zwar None.
Wenn ich eine Frage aufrufe, dann steht da als Antwort schon das Wort "None". Wäre es in dem Fall in Ordnung ' answer="" ' als Default-Wert zu setzen oder würde man eher noch eine Abfrage einbauen, die 'answer' auf 'None' prüft und entsprechend dann einen leeren String zurück gibt oder die Antwort?

Oder macht man das im HTML-Code?

Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Sirius3
User
Beiträge: 17822
Registriert: Sonntag 21. Oktober 2012, 17:20

Du meinst `rating`? Da würde ich im Template prüfen, ob rating nicht None ist und nur dann den <h4>-Tag ausgeben. (Obwohl, das ist ja gar keine Überschrift, zum Auszeichnen würde man <b> oder <span> mit passender Klasse verwenden).
Benutzeravatar
Dennis89
User
Beiträge: 1215
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für die Antwort.

Habe das so hinbekommen.
Ich hatte den h-Tag genommen, weil dadurch "zufälligerweise" der Text an der Position stand, an dem ich es wollte. Dass die für Überschriften sind, hatte ich nicht bedacht. Nun verwende ich den span-Tag und habe mit css-Anpassungen den Text wieder an der gewünschten Stelle.

Beim Upload auf github, hatte ich gerade einen Fehler:

Code: Alles auswählen

To https://github.com/Dennis-89/BZF-Trainer.git
 ! [rejected]        main -> main (fetch first)
Fehler: Fehler beim Versenden einiger Referenzen nach 'https://github.com/Dennis-89/BZF-Trainer.git'
Hinweis: Aktualisierungen wurden zurückgewiesen, weil das Remote-Repository Commits enthält,
Hinweis: die lokal nicht vorhanden sind. Das wird üblicherweise durch einen "push" von
Hinweis: Commits auf dieselbe Referenz von einem anderen Repository aus verursacht.
Hinweis: Vielleicht müssen Sie die externen Änderungen zusammenführen (z. B. 'git pull ...')
Hinweis: bevor Sie erneut "push" ausführen.
Hinweis: Siehe auch die Sektion 'Note about fast-forwards' in 'git push --help'
Hinweis: für weitere Details.
Bin dann so vorgegangen:

Code: Alles auswählen

[dennis@dennis BZF-Trainer]$ git pull
remote: Enumerating objects: 5, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
Entpacke Objekte: 100% (3/3), 691 Bytes | 172.00 KiB/s, fertig.
Von https://github.com/Dennis-89/BZF-Trainer
   d8e5e0a..b67bab6  main       -> origin/main
Hinweis: Sie haben abweichende Branches und müssen angeben, wie mit diesen
Hinweis: umgegangen werden soll.
Hinweis: Sie können dies tun, indem Sie einen der folgenden Befehle vor dem
Hinweis: nächsten Pull ausführen:
Hinweis: 
Hinweis:   git config pull.rebase false  # Merge
Hinweis:   git config pull.rebase true   # Rebase
Hinweis:   git config pull.ff only       # ausschließlich Vorspulen
Hinweis: 
Hinweis: Sie können statt "git config" auch "git config --global" nutzen, um
Hinweis: einen Standard für alle Repositories festzulegen. Sie können auch die
Hinweis: Option --rebase, --no-rebase oder --ff-only auf der Kommandozeile nutzen,
Hinweis: um das konfigurierte Standardverhalten pro Aufruf zu überschreiben.
Schwerwiegend: Es muss angegeben werden, wie mit abweichenden Branches umgegangen werden sollen.
[dennis@dennis BZF-Trainer]$ git config pull.rebase false
[dennis@dennis BZF-Trainer]$ git pull
Merge made by the 'ort' strategy.
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
[dennis@dennis BZF-Trainer]$ git pull
Bereits aktuell.
[dennis@dennis BZF-Trainer]$ git push
Objekte aufzählen: 33, fertig.
Zähle Objekte: 100% (24/24), fertig.
Delta-Kompression verwendet bis zu 4 Threads.
Komprimiere Objekte: 100% (12/12), fertig.
Schreibe Objekte: 100% (13/13), 3.82 KiB | 488.00 KiB/s, fertig.
Gesamt 13 (Delta 6), Wiederverwendet 0 (Delta 0), Pack wiederverwendet 0
remote: Resolving deltas: 100% (6/6), completed with 5 local objects.
To https://github.com/Dennis-89/BZF-Trainer.git
   b67bab6..8f9ff04  main -> main
Und soweit ich es jetzt überblicken konnte, ist der aktuelle Code hochgeladen worden.
https://github.com/Dennis-89/BZF-Trainer

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Antworten