@raiminator: Einige hier verwenden auch Linux oder MacOS, bei denen läuft das gar nicht erst wegen dem `winsound`-Modul, was wie der Name vermuten lässt, Windows-spezifisch ist. Da solltest Du vielleicht einen Rückfalllösung vorsehen. Zum Beispiel den `ImportError` behandeln und dort eine Dummy-Funktion `PlaySound()` mit zwei Argumenten und eine Konstante `SND_ASYNC` definieren.
Zur Form (Namenskonventionen, Leerzeichen, und so weiter) der obligatorische Hinweis auf
PEP 8 -- Style Guide for Python Code.
Dann fallen gleich am Anfang die Sternchen-Importe auf. Die sollte man vermeiden, weil man sich damit potentiell unmengen von Namen in den Namensraum des Moduls holt. Es kann Kollisionen geben, man kann auch Sachen zurückgreifen die man gar nicht wollte wenn man sich zufällig irgend wo vertippt und einen importierten Namen erwischt, und so weiter.
Bei `Tkinter` ist es üblich ``import Tkinter as tk`` zu verwenden um sich Tipparbeit zu sparen.
Die globalen Variablen sind schlecht, weil dadurch die Funktionen auf sehr undurchsichtige Weise zusammenhängen. Auf Modulebene sollten nur Konstanten definiert werden. Alle Variablen und ausführbarer Code der nicht zur Definition von Konstanten verwendet wird, sollte von der Modulebene in Funktionen verschwinden. ``global`` solltest Du gar nicht verwenden.
Bei dem GUI-Entwurf sollte man absolute Grössen und `place()` vermeiden. Bei mir sieht die GUI zum Beispiel so aus:

Und ich denke nicht, dass das so aussehen sollte‽
Abkürzungen bei Namen sollte man vermeiden, wenn sie nicht wirklich allgemein bekannt sind. `rAntwort`, `telJoker`, `pubJoker`, `fifJoker`, und die Präfixe bei den GUI-Objekten `b`, `l`, und so weiter, sollte man verständlicher benennen.
„Denglisch” bei den Namen sollte man auch vermeiden. Entscheide Dich für Deutsch oder für Englisch, aber bitte nicht so etwas wie `getRandomFrage()` oder `newFrage`. Sowohl im Deutschen als auch im Englischen heisst es übrigens „Standar**d**”.
Nicht verwendetes sollte man entfernen. `risiko` zum Beispiel wird zwar zugewiesen, soweit ich sehe aber nirgends tatsächlich benutzt.
Werte und Zeichenketten mit `str()` und ``+`` zusammen zu setzen hat was von BASIC. In Python verwendet man dafür Zeichenkettenformatierung mittels ``%``-Operator oder der `format()`-Methode auf Zeichenketten.
Code: Alles auswählen
main.geometry(str(main_width) + 'x' + str(main_height))
# ->
main.geometry('%sx%s' % (main_width, main_height))
# oder
main.geometry('{0}x{1}'.format(main_width, main_height))
Man sollte bei Nummerierungen und Indexierungen nicht gegen den Rechner arbeiten. Zumindest intern fängt die Zählung bei 0 an. Die Nummer der richtigen Antwort sollte deshalb nicht zwischen 1 und 4 liegen, sondern zwischen 0 und 3. Dann kann man die Nummern auch als Index in Listen verwenden. Die `getBtn()`-Funktion wäre zum Beispiel um einiges kürzer wenn man eine Liste mit den `Button`-Exemplaren hätte und das Argument der Funktion einfach als Index verwenden würde. Eigentlich könnte man die Funktion komplett weglassen und statt des Aufrufs so etwas hier schreiben:
Code: Alles auswählen
main.after(0, setgreen(answer_buttons[rAntwort - 1]))
Wenn die Antworten ab 0 nummeriert werden, kann man sich die ``- 1`` sparen.
In der Datenstruktur zu Fragen werden Daten mit unterschiedlichen Bedeutungen in der Liste vermischt. Die Antworten sollten in einer eigenen Liste zusammen gefasst werden. Dann kann man sie auch als ein Datum behandeln. Zum Beispiel kann man die Antworten mit `random.shuffle()` mischen und erhält so auf einfache Weise eine von *allen* möglichen Kombinationen und nicht nur die 4 Varianten, die Du hart kodiert hast, von den 24 Möglichkeiten die es gibt.
Mehrere Anweisungen auf einer Zeile durch Semikolons getrennt sollte man vermeiden, weil das die Lesbarkeit beeinträchtigen kann. In der `setFrage()`-Funktion würde man das sowieso kürzer schreiben können, wenn man die Antwort-`Button`\s wie schon vorgeschlagen in einer Liste speichern würde, denn dann könnte man eine Schleife verwenden, statt den selben Aufruf für jeden `Button` hin zu schreiben. Das könnte beispielsweise so aussehen:
Code: Alles auswählen
def set_question(question):
global correct_answer_index, frage
frage = question
answers = question[1]
correct_answer = answers[0]
random.shuffle(answers)
correct_answer_index = answers.index(correct_answer)
question_label.configure(text=question[0])
level_label.configure(text=level)
for button, letter, answer, button in zip(answer_buttons, 'ABCD', answers):
button.configure(text='%s: %s' % (letter, answer))
set_blue(button)
Die `after()`-Aufrufe in `antwort()` sind so unsinnig weil Du dort keine Funktionen übergibst, sondern immer `None`. Ausnahme ist der letzte Aufruf im ``else``-Zweig wo tatsächlich eine Funktion übergeben wird. Bei allen anderen Aufrufen ist es völlig egal welche Wartezeit Du übergibst, weil Du die Funktionen selbst und sofort ausführst. Um hier Funktionen als zweites Argument zu übergeben brauchst Du `functools.partial` oder ``lambda``-Funktionen.
Die Gewinnstufe würde ich von konkreten Beträgen entkoppeln. Also nicht die Beträge an `level` binden, sondern die Stufe einfach von 0 an hochzählen und eine Funktion schreiben, welche die Stufe für die Anzeige in einen Betrag umrechnet. Dann kann man da zum Beispiel für die Anfangsstufen mit einer Liste arbeiten und sich die vielen ``if``/``elif`` sparen, die in `getNextLevel()` stehen.
Bei den Schaltflächen für die Antworten ignorierst und umgehst Du eigentlich alle Eigenschaften die `Button` bietet und implementierst sie teilweise selbst. Entweder nutzt Du den `Button` mehr, oder Du solltest etwas anderes verwenden.
Ich denke hier kommt man um eigene Klassen nicht herum wenn man das sauber lösen möchte. Dabei sollte man das Spiel ohne GUI-Code kapseln. Und bei der GUI würden eigene Datentypen für einzelne Antwortschaltfächen und eins für die Antwortschaltflächen als Gruppe Sinn machen.
@EyDu: Was gibt's an RAR auszusetzen? Zumindest Entpacker gibt es kostenlos und frei für die gängigen Betriebssysteme und die meisten Werkzeuge die mit mehreren Formaten umgehen können, entpacken die Archive auch. Das Format ist in der Regel besser als ZIP und schon seit Urzeiten (== DOS-Zeiten) verbreitet. Ich könnte so eine Bemerkung vielleicht bei 7z- oder tar.xz- Archiven verstehen, weil die noch relativ neu sind. Aber verbreitet sind die auch.