Dies können wir in enter_room einbauen:
Code: Alles auswählen
def enter_room(room):
...
if room is burghof and not room.visited:
room.visited = True
emit("Du schreckst ein Dutzend schwarze Raben auf, die sich laut "
"krächzend auf dem Dach des Burgfrieds in Sicherheit bringen.")
emit()
Code: Alles auswählen
class Room:
def __init__(self, name, description):
self.name = name
self.description = description
self.exits = {}
self.visited = False
Wir könnten uns entscheiden, beim Betreten eines Raumes eine Methode enter aufzurufen. Dies würde uns ermöglichen, in einer Unterklasse eine spezielle Implementierung anzugeben. Nun bräuchte aber jeder Raum seine eigene Klasse, denn Python zwingt uns leider dazu, für jedes Objekt eine Klasse zu definieren. In JavaScript, wo ich keine Klassen habe, wäre das ein guter Weg. Doch bei Python missfällt er mir.
Dennoch möchte ich ihn kurz skizzieren:
Code: Alles auswählen
class Room:
def enter(self):
self.describe()
class VorDerBurg(Room):
def describe(self):
emit("Vor dir ragt eine alte trutzige Burg auf...")
class Burghof(Room):
def describe(self):
emit("Die hohen Mauern lassen nur weg Licht...")
def enter(self):
super()
if not self.visited:
self.visited = True
emit("Du schreckst ein Dutzend schwarze Raben auf, die sich laut "
"krächzend auf dem Dach des Burgfrieds in Sicherheit bringen.")
emit()
vor_der_burg = VorDerBurg()
burghof = Burghof()
Das könnte so aussehen:
Code: Alles auswählen
@after("entering", burghof)
def do(room):
if not room.visited:
room.visited = True
emit("Du schreckst ein Dutzend schwarze Raben auf, die sich laut "
"krächzend auf dem Dach des Burgfrieds in Sicherheit bringen.")
emit()
Das sieht dann so aus:
Code: Alles auswählen
def enter_room(room):
global current_room
current_room = room
describe_room()
trigger("after entering", room)
Code: Alles auswählen
events = {}
def trigger(event_type, argument):
funcs = events.get(event_type)
if funcs:
for func in funcs:
if func(argument):
return True
def after(event_type, object):
def inner(func):
def event(argument):
if argument is object:
return func(argument)
funcs = events.setdefault("after " + event_type, [])
funcs.append(event)
return inner
Die Funktion trigger sucht dann aus events die passende Liste heraus und wenn sie existiert, geht sie alle Funktionen durch und ruft sie der Reihe nach auf. Ich vereinbare, dass eine Funktion, die etwas anderes als "falsch" zurück gibt, dazu führt, dass das Aufrufen der Funktionen abgebrochen wird und dass trigger in diesem Fall auch etwas anderes als "falsch" (jede Python-Funktion, die keine explizite return-Anweisung hat, liefert implizit None zurück, was als "falsch" gilt) liefert. Dies wird später noch nützlich sein.
Die Funktion after ist ein "Decorator", eine Funktion, die eine Funktion liefert, die mit der dekorierten Funktion als Argument aufgerufen wird. Ein Beispiel macht es hoffentlich klarer:
Code: Alles auswählen
@after("entering", burghof)
def do(room):
...
=>
def do(room):
...
decorator = after("entering", burghof)
decorator(do)
Nachdem wir dies verstanden haben, möchte ich den Mechanismus noch etwas erweitern.
Es wäre nett, wenn ich einfach
Code: Alles auswählen
@after("entering", burfhof, once=True)
Code: Alles auswählen
def after(event_type, object, once=False):
def wrapper(func):
doit = True
def event(argument):
nonlocal doit
if doit and argument is object:
if once: doit = False
return func(argument)
funcs = events.setdefault("after " + event_type, [])
funcs.append(event)
return wrapper
Code: Alles auswählen
def emit(s="", width=80):
global column
if s:
for word in str(s).split():
column += len(word) + 1
if column > width:
column = len(word) + 1
print()
print(word, end=" ")
else:
column = 0
print("\n")
Code: Alles auswählen
def describe_room():
emit(); emit(current_room.name)
emit(); emit(current_room.description)
Code: Alles auswählen
def execute_command():
emit()
...
Code: Alles auswählen
Der Burghof
Die hohen Mauern lassen nur weg Licht der untergehenden Sonne hinein. Der Hof
ist unübersichtlich. Im Laufe der Jahrhunderte hat sich hier viel Schutt und
Müll angesammelt. Doch im Westen führt ein Tor in den Burgfried. Alle anderen
Zugänge scheinen verschüttet zu sein. Du schreckst ein Dutzend schwarze Raben
auf, die sich laut krächzend auf dem Dach des Burgfrieds in Sicherheit bringen.
?
Stefan