@Mardor: Beim ersten Quelltext sieht man übrigens einen guten Grund warum man Redundanz vermeiden sollte. Der Spielregeltext sagt es ist das 1x1 bis 12x12 Spiel, aber eigentlich ist es das 1x1 bis 12x10 Spiel. In den folgenden Quelltexten stimmen die Zahlen dann zwar überein, aber die Gefahr das das wieder ”kaputt” geht, besteht weiterhin. Wenn man die Grenzen anpassen will, muss man daran denken *alle* Vorkommen der Zahl anzupassen. Sowohl als Zahlen, als auch in Texten. So etwas umgeht man üblicherweise durch definieren von Konstanten, so dass man den Quelltext nur noch an dieser Stelle einmal ändern muss, und sich das automatisch auf das gesamte Programm auswirkt.
Hier mal ein Ansatz das mit einer GUI umzusetzen und mit der ursprünglich geplanten Regel das die Antwortzeiten kürzer werden wenn man die Zeit überschreitet:
Code: Alles auswählen
from random import randint
import tkinter as tk
from tkinter.messagebox import showerror, showinfo
LOWER_LIMIT = 1
UPPER_LIMIT = 12
POINTS_FOR_CORRECT_ANSWER = 10
POINTS_FOR_INCORRECT_ANSWER = -20
GOAL = 100
RULES_TEXT = (
'\n'
'— {0}×{0} bis {1}×{1} Spiel —\n'
'\n'
'Du musst so schnell als möglich die Zielpunkte erreichen.\n'
'Richtige Antworten geben {2} Punkte.\n'
'Falsche Antworten geben {3} Minuspunkte.\n'
'\n'.format(
LOWER_LIMIT,
UPPER_LIMIT,
POINTS_FOR_CORRECT_ANSWER,
-POINTS_FOR_INCORRECT_ANSWER,
)
)
class MultiplicationGame(object):
def __init__(self):
self.timeout = 10
self.points = 0
self.trial_count = 0
self.operand_a = None
self.operand_b = None
@property
def is_over(self):
return self.timeout == 0 or self.points >= GOAL
def _adjust_points(self, amount):
self.points += amount
self.trial_count += 1
def start_round(self):
self.operand_a = randint(LOWER_LIMIT, UPPER_LIMIT)
self.operand_b = randint(LOWER_LIMIT, UPPER_LIMIT)
return self.operand_a, self.operand_b
def check_result(self, value):
result = (
False if value is None else self.operand_a * self.operand_b == value
)
self._adjust_points(
POINTS_FOR_CORRECT_ANSWER if result else POINTS_FOR_INCORRECT_ANSWER
)
return result
def timed_out(self):
self.timeout -= 1
self._adjust_points(POINTS_FOR_INCORRECT_ANSWER)
class MultiplicationGameUI(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.timer_id = None
frame = tk.LabelFrame(self, text='Spielregeln')
tk.Label(frame, text=RULES_TEXT).pack()
frame.pack(side=tk.TOP)
frame = tk.Frame(self)
question_frame = tk.LabelFrame(frame, text='Aufgabe')
self.question_var = tk.StringVar()
tk.Label(question_frame, textvariable=self.question_var).pack()
question_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
points_frame = tk.LabelFrame(frame, text='Punkte')
self.points_var = tk.IntVar()
tk.Label(points_frame, textvariable=self.points_var).pack()
points_frame.pack(side=tk.LEFT)
countdown_frame = tk.LabelFrame(frame, text='Zeit')
self.countdown_var = tk.IntVar()
tk.Label(countdown_frame, textvariable=self.countdown_var).pack()
countdown_frame.pack(side=tk.LEFT)
frame.pack(side=tk.TOP, fill=tk.X)
frame = tk.Frame(self)
answer_frame = tk.LabelFrame(frame, text='Antwort')
self.answer_var = tk.StringVar()
self.answer_entry = tk.Entry(answer_frame, textvariable=self.answer_var)
self.answer_entry.pack(fill=tk.X)
self.answer_entry.bind('<Return>', self.do_check_result)
answer_frame.pack(side=tk.LEFT, fill=tk.X, expand=True)
self.button = tk.Button(frame)
self.button.pack(side=tk.LEFT, fill=tk.BOTH)
frame.pack(side=tk.TOP, fill=tk.X)
self.create_new_game()
def create_new_game(self):
self.game = MultiplicationGame()
for var in [
self.question_var,
self.points_var,
self.countdown_var,
self.answer_var
]:
var.set('')
self.button.configure(text='Start', command=self.do_start)
self.button.focus()
def do_start(self):
self.button.configure(text='OK', command=self.do_check_result)
self.do_round()
def do_countdown(self):
value = self.countdown_var.get()
if value > 0:
self.countdown_var.set(value - 1)
self.timer_id = self.after(1000, self.do_countdown)
else:
self.timer_id = None
self.game.timed_out()
self.do_round()
def do_check_result(self, _event=None):
if self.timer_id is not None:
self.after_cancel(self.timer_id)
self.timer_id = None
try:
answer = int(self.answer_var.get())
except ValueError:
answer = None
self.game.check_result(answer)
self.do_round()
def do_round(self):
self.points_var.set(self.game.points)
if self.game.is_over:
if self.game.timeout == 0:
showerror(
'Ooooooh...',
'Du hast zu oft die Zeit überschritten und nur'
' {0} Punkte erreicht.'.format(self.game.points),
)
elif self.game.points >= GOAL:
showinfo(
'Yeaah!',
'Du hast die {0} Punkte mit insgesamt {1} Versuchen'
' erreicht.'.format(GOAL, self.game.trial_count),
)
else:
assert False, 'neither won nor zero timeout should not happen'
self.create_new_game()
else:
operand_a, operand_b = self.game.start_round()
self.question_var.set(
'Wieviel ist {0} × {1}'.format(operand_a, operand_b)
)
self.answer_var.set('')
self.answer_entry.focus()
self.countdown_var.set(self.game.timeout + 1)
self.do_countdown()
def main():
root = tk.Tk()
root.title('Multiplikationsspiel')
game_ui = MultiplicationGameUI(root)
game_ui.pack()
root.mainloop()
if __name__ == '__main__':
main()