Benutzer:Andyk/Mitschriften/Technische I7-Auseinandersetzungen
Inhaltsverzeichnis
- 1 Was ist das hier?
- 2 Allgemeines
- 3 Wissenswertes über die Basics
- 4 Good, old coding @ Inform7
- 5 Wie hängen Phrasen, Funktionen und Regeln zusammen?
- 6 Wie hängen Inform und Objektorientierung zusammen?
- 7 Wie man bool'sche Eigenschaftswörter definieren kann
- 8 Das Äquivalent zu Globalen Funktionen: 'To ...'-Phrasen
- 9 Relationen
- 10 Regeln / rules
- 11 Regelbücher
- 12 Ein paar Bemerkungen zu Understand
- 13 Szenen: Die Entwicklung temporärer Strukturen
- 14 Arrays / Tables
- 15 Named Values ?
Was ist das hier?
Ich habe mir gedacht, dass das Schlussstatement in Session3 - nicht alles an Inform 7 ist objektorientiert - zu ungenau ist und wollte einfach mal nachhaken, weil es mich interessiert hat.
Es folgen nun einfach ein paar Notizen, die ich mir beim Lesen des Inform7-Tutorials für Programmierer gemacht habe. Vielleicht kann jemand etwas damit anfangen; für mich ist es einfach ein kleines Cheat-Sheet und der Versuch mir etwas klarer über die Möglichkeiten von I7 zu werden.
- Regeln sind in Regelbücher eingeordnet.
- Regeln sind auf 3 parameter eingeschränkt -> die höchste Stelligkeit (arity), die ein englisches VERB haben kann.
- Über Regeln wird noch mehr zu verstehen sein!!
Allgemeines
- Events werden Actions genannt, denn sie bestimmen die Handlungen des Protagonisten
- Verhältnis zur Objektorientierung: Einfachvererbung und Polymorphismus werden unterstützt, Abstraktion, Modularität und Namensräume nicht.
- Inform7 source code wird in Inform6 code und dann in die virtuelle Maschine kompiliert. Diese Kompilierungsvorgänge laufen aber für den durchschnittlichen IF7-Entwickler unbemerkt im Hintergrund ab. (vgl. I7-Dokumentation ab 24.13)
- Es ist nicht wirklich erwünscht, Inform6-code in ein Inform7-Projekt zu integrieren: "for those who do know I6 already, it would be all too easy to write highly hybridised code, constantly mixing I6 and I7. The authors of Inform hope that this will not happen: for almost all purposes, I7 is much more powerful than I6, and fails - when it has to fail - in a way more helpful to the user. Ideally, all I6 content would be confined to extensions (and this may be mandated in future releases of Inform), and even writers of extensions are asked to pare down their usage of I6 to the minimum necessary."
- Bei Inform-7 gibt es keine einheitliche Theorie. In der Objektorientierung kann man sagen "Alles ist ein Objekt" oder bei manchen Skriptsprachen zum Beispiel "Alles ist eine Liste". Das kann man generell nicht bei Inform7 sagen. Deswegen ist es leichter zu erlernen, weil man jedes Feature lernen kann, ohne die anderen zu benötigen. Für Nicht-Programmierer mag das eine zufriedenstellende Sache sein. "But at higher levels of programming, the language has a very ad-hoc feel to it."
- Jedes Programm braucht mindestens einen Raum. Das kleinste Programm:
X is room.
- Das obligatorische Hello-World in Inform:
My apartment is a room. When play begins: say "Hello world.
Wissenswertes über die Basics
- Die Artikel ('some', 'a', 'the', 'an') werden beim Kompilieren einfach entfernt.
- 'is' und 'are' sind synonym (ist also egal, was du verwendest)
Variablen
- Man kann einfach einen Satz schreiben der mit "that varies." endet.
- Die wichtigsten vordefinierten 'Kinds of Values' (Datentypen) sind:
- number, text, truth state
- thing, person, direction
- table-name, rulebook, rule
- indexed text, stored action
X is a number that varies.
Y is a number variable.
An excuse is some text that varies.
The best spot is a room that varies.
The light switch's boolean is a truth state that varies.
Objekte / things
Da ist mir das meiste schon von der Dokumentation gut bekannt, außer:
- Wenn nach einer Raum-Instanz wie
My house is a room,
ein Text wie "Schönes, großes Haus." kommt, dann wird der Text der Description-Property zugewiesen. - Wenn nach einer Objekt-Instanz wie
The apple is a thing.
so ein Text kommt, dann wird er der "Initial Appearance"-property zugewiesen. Wenn das Ding von der Spielerin aufgehoben wird, wird AFAIK der Initial appearance-text ausgegeben.
Klassen / kinds
- Funktion von usually: Wenn man
usually
schreibt, dann dürfen Objekte der Klasse trotzdem noch nen anderen Wert haben, wenn man es explizit angibt. Wenn manalways
schreiben würde, dann wäre für alle Objekte der Klasse fixiert, welchen Wert sie annehmen. Mit Wert annehmen meine ich sowas wie dass die Farbe eines Pferdes braun istA horse is a kind of animal. A horse has a text called color. The color of a horse is usually "brown".
Was ist bei den Klassen sonst noch wissenswert?
- Eine Region ist ein Container für Räume
- Supporter: Gegenstände, wo man andere Gegenstände draufstellt (anbietet). Ist normalerweise "fixed in place"
- Backdrop (Kulisse/Hintergrund): Eine Szenerie (die Sonne am Himmel, der immer präsente Bach)
- "The positioning of Animal is our first hint that we're stepping out of a scientific worldview, and into a humanistic one. Likewise, the purpose of the language as a whole is to produce works of art, not software tools."
- anonyme (dichotomische oder:) boolean-Eigenschaft mit benannten Werten anstatt true und false:
A human can be just or unjust.
- "yourself" ist ein thing von der Klasse 'person'. "The player" ist nur eine Variable auf "yourself". Diese Person mit der Variable gibts bei jedem Spiel (außer man ändert es im Code).
- Es gibt eine Instanz der Super-Klasse (die, die in der Hierarchie ganz oben steht) 'object', nämlich "nothing". Synonyme von nothing sind nowhere,nobody,no-one und 'no one'.
Good, old coding @ Inform7
Weil es so schön instruktiv ist, würde ich einfach die ganze Demonstration der obligatorischen Programmierkonstrukte if, else, switch, while, for-each in Inform7 aus dem Tutorial hier rein kopieren. Damit es nicht zu unübersichtlich ist, reiß ich mich zusammen und mache einen Link:
- DER LINK, DER ALLE VERSCHIEDENEN NOTATIONEN VON ÜBLICHEN KONSTRUKTEN IN DER PROZEDURALEN PROGRAMMIERUNG FÜR INFORM7 VORSTELLT
- Erwähnenswert: Man kann das letzte Statement in einem Block entweder mit einem '.' beenden oder man nimmt wie immer ; und fügt danach eine leere Zeile hinzu.
Wie hängen Phrasen, Funktionen und Regeln zusammen?
- Alle Schlüsselworte/Befehle wie if, repeat, next, etc. sind Phrasen.
- Funktionen sind auch Phrasen, weil sie ähnlich aufgerufen werden (nämlich explizit im Code)
- Regeln sind keine Phrasen. Man ruft sie nicht explizit auf, sondern sie werden aufgerufen, wenn im Spiel ein Ereignis (z.b. eine Action) oder eine andere Situation eintritt.
Wie hängen Inform und Objektorientierung zusammen?
Das ist der Punkt, der mir in Session 3 bereits aufgefallen ist:
- "Frequently in OOPLs (AKA: Object Oriented Programming Languages), new properties and methods cannot be added to a pre-existing class because doing so would break pre-existing code that uses it; subclassing is required to add such embellishments. But since Inform isn't designed for re-usable code or even team-built works, Inform allows the direct modification of classes, and those changes are propagated down the subclasses regardless whether they are built-in or not."
Wie man bool'sche Eigenschaftswörter definieren kann
- Ganz klar ist mir noch nicht, wofür man diese Wörter genau verwendet, aber die Dokumentation sagt und das Tutorial deutet an, dass man mit ihrer Hilfe gut Regeln definieren kann
- Möglichkeit1: Eine anonyme bool'sche Eigenschaft mit benannten Namen (anstatt true/false) erstellen:
A person can be grumpy or happy.
- Möglichkeit2: Das Äquivalent zu dem, was man in OOPLs "eine Klassen-Methode erstellen, die einen Boolean-Wert zurückgibt" nennen könnte:
Definition: a person is unlikable if it is boring or it is grumpy.
Definition: a person is boring [...];
[...];
decide no.
Definition: A room is occupied rather than unoccupied if a person is in it.
(rather than unoccupied ist optional, sozusagen genau das Gegenteil, aber man braucht dafür nicht eine ähnliche Definition mit 'unoccupied' schreiben, wenn man es definieren will)
- Möglichkeit3: mit 'to decide wheather' (vgl. Inform7-Doku 11.16. oder siehe unten).
Und wie überprüft man diese Adjektive?
- Mit einem repeat-Konstrukt:
repeat with associate running through every chatty not grumpy spiffy person begin;
say "Hi [associate].";
end repeat;
Und was sind die expliziten Verwendungszwecke solcher Adjektive?
- Im Tutorial wird nur mal erwähnt, dass sie bei Inform7 die große Stärke sind. Kann man die Adjektive als analog zu den Prädikaten in der Prädikatenlogik verstehen? Mal sehen, ob ich diese Frage besser beantworten kann, wenn ich mehr über 'rules' weiß.
Das Äquivalent zu Globalen Funktionen: 'To ...'-Phrasen
- Man kann sich Funktionen definieren, die man dann in irgend einer Phrase aufrufen kann.
Funktionen, die keinen Wert zurückliefern
To plainly greet (friend - a person):
say "Hi [friend]."
To ponder/mull over/-- (good point - a thing) for (awhile - a time period) as (ponderer - a person):
say "[Ponderer] sits back in [his-her] chair for about [awhile]. 'Hm, [good point] is a very good point, sir.'" plainly greet Dr. Muller;
- Die Slashes ('/') trennen die Synonyme für den Funktionsnamen ab (man darf keine Leerzeichen dazwischen haben).
- Die beiden Bindestriche ('--') sagen aus, dass das Wort davor (nämlich 'over') optional ist.
- In Klammern steht immer die Bezeichnung des Parameters (good point, awhile, ponderer) und welche Klasse/kind erwartet wird (thing, time period, person)
- Das finde ich wirklich beeindruckend (vor allem weil ich die Mächtigkeit dieser Prozeduren In I7 noch nicht kannte). Man kann wie in der zweiten Funktion mehrere Parameter (thing, time period, person) angeben und dann für die Verarbeitung entsprechend verwenden. Aufrufen tut man die Funktion auf folgende mögliche Arten:
ponder the best idea yet for 7 minutes as Dr. Muller;
ponder over the best idea yet for 7 minutes as Dr. Muller;
mull best idea yet for 7 minutes as Muller;
mull over the best idea yet for 7 minutes as Dr. Muller;
- Zwei Parameter dürfen nicht direkt neben einander stehen (z.B.:
To ponder for (awhile - a time period) (good point - a thing):
)
- Das Tutorial sagt: Man nimmt nicht so gerne diese Art von globalen Funktionen sondern lieber 'rules': die kann man zwar nicht so schön aufrufen, dafür sind sie flexibler.
Funktionen mit Rückgabewert: To decide which/what...
- Funktion:
To decide what person is brother to/of (sibling - a person): [...]; decide sibling.
- Aufruf:
if the brother of the noun is not the noun, say "[Noun] has a brother, [Brother of the noun].";
- Zwischen 'to decide what' und 'is...' befindet sich das, was zurückgegeben wird... in diesem Fall ein 'thing' von der Art 'person'.
Funktionen mit Boolean-Rückgabewert: To decide whether/if...
- Wenn ein wahr/falsch zurückgegeben werden soll:
To decide whether (pants - a thing) is/are on fire:
decide on whether or not a random chance of 1 in 2 succeeds.
if the brother of the noun is on fire, say "That's gonna leave a mark.";
- Wie man beim Aufruf sieht, kann man den Rückgabewert gleich in dem if einbinden. Nützlich.
To say...
- Man kann für bestimmte (evt. durch Variablen generierte) Texte Platzhalter einführen. Ich würde mir das wie Funktionen vorstellen, die einen String (Zeichenkette) zurückliefern.
- Die Syntax funktioniert ansonsten genauso wie [[#Funktionen, die keinen Wert zurückliefern|hier] erklärt
To say He-She for (P - a person):
if P is plural begin;
say "They";
otherwise;
if P is female, say "She";
otherwise say "He";
end if.
Aufruf mit eckigen Klammern:
[...]; say "[He-She for Chris] says Hello.";
Relationen
- Darüber hab ich mir bei der I7-Einführung ein bisschen Gedanken gemacht
- Der Name einer Relation darf keine Leerzeichen enthalten.
- Ein Beispiel einer symmetrischen 1-zu-1-Relation: Wenn A mit B verheiratet ist, dann ist automatisch auch B mit A verheiratet. A kann aber nicht zusätzlich mit jemand anderen (z.B. C) verheiratet sein.
Marriage relates one person to another (called the spouse). ["to another" means a symmetric relation]
The verb to be married to implies the marriage relation.
- Ein Beispiel einer asymmetrischen Freundschafts-Relation. Wenn A mit B befreundet ist, ist B nicht mit A befreundet. Außerdem kann A zusätzlich mit C (D,E,F,G usw.) befreundet sein.
Friendship relates various people to various people. [an asymmetric relation]
The verb to be friends with implies the friendship relation.
The verb to be befriended by implies the reversed friendship relation. [ defining a "reversed" syntax for asymmetric relations is useful in Descriptions ]
- I7 kann Verben der Form "to be X" automatisch beugen (vgl. Flexion).
- Bei Verben der Form "to X" muss man alle Beugungen in Klammer angeben:
Trust relates people to each other in groups. [an equivalence relation]
The verb to trust (he trusts, they trust, he trusted, it is trusted, he is trusting) implies the Trust relation.
- Eine Übersicht über alle möglichen Relationen:
...one person to one person...
...various people to one person...
...one person to various people...
...various people to various people...
...one person to another... [ one-to-one, symmetric (if A~B, then also B~A; think "commutative operator")]
...people to each other... [various-to-various, symmetric]
...people to each other in groups... [equivalence (think "if A equals B, then A also equals everything that B equals)]
- Relationen kann man nicht nur wie oben einfach bedingungslos zwischen zwei Mengen herstellen, sondern auch (wie das bei der Prädikatenlogik AFAIK üblich ist) Bedingungen angeben, wann eine Relation zutrifft:
Siblinghood relates a person (called X) to a person (called Y) when X is the brother of Y or X is the sister of Y.
Wie kann man Relationen gebrauchen?
- Man kann keine Relations-Variable erstellen. Man kann auch keine Relation als Rückgabewert einer Funktion vorsehen.
- Nützlich ist so eine Relation zum Beispiel bei der Pfadsuche:
let X be the number of steps via the acts-with relation from Kevin Bacon to Jodie Foster;
let S be the next step via the acts-with relation from Christopher Walken to Kevin Bacon;
- Man kann solche Relationen gut für Abfragen (Queries) benutzen (mit repeat with kann man alle 'things' durchgehen, auf die die Abfragekriterien zutreffen).
Regeln / rules
Nun kommen wir zu dem berüchtigten Konzept, das ich in I7 noch nicht einordnen kann, weil es sich dem Prozeduralen bzw. dem Objektorientierten Paradigma widersetzt: Regeln.
- Das prozedurale Paradigma (Beispiel: C)führt Befehle einer Prozedur (Funktion, Operation) dann aus, wenn die Prozedur mit ihrem Namen (+ evt. Parameter) aufgerufen wird.
- Das regel-getriebene Paradigma (Beispiel: Prolog) braucht keinen Namen, da sie nicht notwendigerweise aufgerufen werden muss; sie ruft sich quasi selbst auf. Das klappt durch die inhärente Struktur einer Regel: Sie weiß, wann sie zum Zug komemn soll, da in ihr selbst die Bedingungen enthalten sind, unter welchen Umständen sie selbst auftritt. Ich stelle mir das zunächst mal so ähnlich vor wie wenn man die Regeln einer Turingmaschine definiert: "Wenn die Maschine in Zustand q1 ist, dann fahre mit dem Lese/Schreib-Kopf nach links und nimm Zustand q2 an." Diese Regel wird dann aktiv, wenn die Maschine in einer bestimmten Situation ist, nämlich in der Situation, die der Zustand q1 beschreibt.
- Man kann die Regeln nochmal unterteilen in Header und Code-Teil. Im Header sind die Situationsinformationen (vgl. Zustand q1 bei Turingmaschinen) gespeichert, im Code die einzelnen Befehle (vgl. Turingmaschinen: Nach Links fahren).
- Die Information, unter welchen Bedingungen eine Prozedur aufgerufen wird, ist im ganzen Code verstreut, nämlich überall, wo ihr Name auftaucht. Bei Regeln ist sie anscheinend im Header.
Syntax
Der Header einer Regel endet mit einem Doppelpunkt (:
). Danach kommen die einzelnen Instruktionen (jeweils abgetrennt durch einen Strichpunkt ;
) und enden mit einem Punkt (.
) oder mit einer leeren Zeile:
A persuasion rule: [...]; [...]; [...].
Every turn during the collapsing bridge scene: [...].
Carry out an actor helping someone: now the noun is friends with the actor.
- Regeln sind in Regelbücher eingeordnet. Im Header einer Regel gibt man im Wesentlichen an, in welches Regelbuch die Regel hinein gehört. Zusätzlich kann man auch noch andere Elemente nach der Angabe des Regelbuches reinpacken:
- when/while (bei if-then-strukturen)
- during (wenn man Szenen verwendet)
- eine einzelne Beschreibung einer Aktion ("someone burning something")
- Man kann sagen, dass Regelbücher veränderbares Verhalten kapseln (Im reinen Objektorientierten Paradigma tun das Objekte auch. Bei I7 tun das Objekte/things nicht.)
- "It could be said that objects implement nouns, while rulebooks implement verbs."
Wie benennt man Regeln und warum soll man das tun?
(vgl. I7-Doku 18.3)
This is the blossom shaking rule: say "The summer breeze shakes the apple-blossom."
- Fürs Debugging ist das ganz wichtig. Durch die Befehle
RULES
undRULES ALL
erfolgt eine Ausgabe, die die Namen aller Regeln auflistet, wenn sie ausgeführt weren. - "it is always good extension-writing practice to name all rules merely so client code can reference, modify, or delete them, to say nothing of documentation":
My magic hand rule is listed instead of the can't take distant objects rule in the check taking rulebook.
The landlubbers can't walk right rule is listed first in the check going rules.
AKA: Welche Regelbücher gibt es? Welche sind wichtig? Diese Frage wird im nächsten Kapitel behandelt.
Anwendungsbeispiel
- Ich hätte bei meinem Buch-Beispiel gerne die Switching-On/Off-Rules mit eigenen Rules ergänzt, die nur dann in Kraft treten, wenn es sich um ein Ding der Art "Buch" handelt (damit kann man die unpassenden Meldungen beim öffnen des Buches und beim Betrachten des Buches hoffentlich entfernen)
- Update: Es ist mir gelungen, neue Regeln hinzuzufügen, die unerwünschten Ausgaben der Standard-Regeln zu unterdrücken (zumeist mit
stop the action
) und zum Buch passende Ausgaben zu schreiben. Natürlich (!) kann man das Ganze auch leichter haben, indem man die Buch-Art direkt von 'thing' ableitet (A book is a thing
und sich einfach ein dichotomisches Adjektiv für die Frage, ob das Buch offen oder geschlossen ist, definiert:A book can be open or closed.
. Dementsprechend bräuchte man dann auch nochInstead of opening a book: say "The book is open."; now the noun is open.
und Ähnliches für closing.
Ich habe es umständlicher gemacht und dadurch ein bisschen die Abgründe der Rulebooks erkundet:
Carry out examining described books: abide by the standard examining rule; say "[if the noun is switched on]The book is open and I can see [a list of pages which are part of the noun].[otherwise]The book is closed.[end if]";stop the action.
Check switching off described books when the noun is switched off: say "You want to close a closed book?"; stop the action.
Check switching on described books when the noun is switched on: say "Oh my god... The book is already open."; stop the action.
Report switching on described books: say "The book is now open."; stop the action.
Report switching off described books: say "The book is now closed."; stop the action.
Regelbücher
- Hätte ich das Tutorial-Kapitel über Regelbücher vor dem Schreiben des obigen Anwendungsbeispiels gelesen, hätte ich das Übergehen der Standardregeln ein wenig anders gelöst:
- Ein Regelbuch geht die Regeln, die in ihm enthalten sind, von der ersten bis zur letzten durch. In diesem Vorgang wird es nur unterbrochen, wenn in einer Regel ein definitives Ergebnis der Form
rule succeeds
oderrule fails
vorkommt. Kommt so etwas nicht vor, wird implizit jeder Regel am Ende ein default-Ergebnis hinzugefügt (standardmäßig ist das:make no decision
, den man natürlich auch explizit hinschreiben kann). Man kann das default-Ergebnis auch für jedes einzelne Regelbuch ändern:
The pick a plan rules are a rulebook.
The pick a plan rules have default outcome success. [ Or failure, or no outcome ]
- Das Ergebnis/outcome (succeed,failed) ist verschieden von einem Rückgabewert/return value, den man für eine Regel folgendermaßen zurückliefern kann:
The audible rules have outcomes silent (failure), whisper (success), voiced (success - the default), shout, and deafening.
[...]; rule succeeds with result the whisper outcome. [Rückgabe von einem Objekt 'whisper outcome']
[...]; whisper.[die Regel hat ein erfolgreiches Ergebnis, das whisper benannt wurde]
[...]; rule succeeds with result my fabulous doodad.[Rückgabe von einem named value]
[...]; rule fails with result "In your dreams." [Rückgabe von Text; ein fehlgeschlagenes (nicht benanntes) Ergebnis]
- Wenn man neue Regelbücher schreibt, muss man irgendwo im Code festlegen, wann sie aufgerufen werden sollen. Dafür sind die Schlüsselwörter
consider
,follow
,abide by
(das ich im Anwendungsbeispiel der Regeln schon verwendet habe) undanonymously abide by
wichtig. Wenn wir mal in diese Verlegenheit kommen sollten, müssen wir hier oder in der I7-Doku (Kapitel 18.15/18.16) nachschlagen; es ist dort IMHO gut erklärt.
Regelbücher und Actions
- Das prinzipielle IF-Szenario ist: Die Spielerin steuert den Avatar/die Spielfigur durch Befehle, die von IF als Actions interpretiert werden. Diese Actions sind Regelgeleitet. Das heißt, wenn die Spielerin
examine Sim0n3
eingibt, wird zunächst geschaut, zu welcher Action der Befehlexamine (thing)
gehört, nämlich zuexamining
.- Nebenbemerkung: Man kann zum Beispiel mit
understand "examine (book)" as reading
die Zuordnung: Befehl <-> Action verändern.
- Nebenbemerkung: Man kann zum Beispiel mit
- Wenn man eine neue Action erstellt, werden automatisch 3 Regelbüchern erstellt, die jedoch zunächst leer sind und erst mit Regeln gefüllt werden können
- Nebenbemerkung: Ich habe in der Inform7-Einführung schon einmal etwas über Actions geschrieben, wobei das dort noch relativ rudimentär erklärt war (und eigentlich auch nicht sauber programmiert). Ich versuche es jetzt in einem neuen Anlauf:
Eine Action erstellt man in zwei Schritten:
- Action mit ihrem Namen und ihren Parametern definieren. Die Parameter können nicht nur Objekte, sondern auch kinds of values sein. Ich übernehme die folgende Liste aus dem Tutorial:
Donating is an action applying to one thing. [Man kann hier statt thing nicht genauer werden, z.B. device oder so verwenden]
Discussing is an action applying to one topic.
Accusing it of is an action applying to one object and one visible object.
Tabulating is an action applying to one number and requiring light.
Scheduling is an action applying to one time.
Temporarily waiting is an action applying to one time period.
Whining is an action applying to nothing.
Teleporting to is an action applying to one room.
Saving the game is an action out of world applying to nothing.
Tattooing it of is an action applying to one limb and one thing, requiring light.
Weaving is an action with past participle woven, applying to one thing.
- Drei Regelbücher, die für jede Actions erstellt werden, sind das
check
-, dascarry out
- und dasreport
-Regelbuch. Man muss (bzw. sollte) sie mit entsprechendem Inhalt füllen:- CHECK:' Hier wird überprüft, ob die Action überhaupt ausgeführt werden kann. Welche Vorbedinungen sind nötig?(Beispiel: Lesen kann man nur ein Buch.)
- CARRY OUT: Hier wird die eigentliche Aktion durchgeführt. Die Zustände der Welt können verändert werden. Es sollte aber kein Text ausgegeben werden (sonst wird
try silently
nicht den erwünschten Sinn haben, siehe nächster Absatz) - REPORT: Das, was getan wurde, kann hier nochmal kommentiert werden. (Beispiel eine Textausgabe: "Die Tür ist nun geöffnet.")
- Was noch erwähnenswert ist, wenn man Regeln für Actions schreibt: Falls man sich auf die Parameter beziehen will, für die die aktuelle Action angewandt wird, referenziert man Objekte mit
the noun
,the second nount
usw. Man kann aber, wenn es sich nicht um Objekte handelt, sondern um Zahlen, Text oder anderen kinds of values, diese referenzieren mitthe number understood
,the text understood
,the time understood
, ...
Man kann Actions auch ohne Understand
-Sätzen aufrufen, und zwar mit try
:
try Bob donating the jeans;
silently try donating the red Porsche;[Silently bedeutet: Alle Reporting-Rules werden übersprungen]
try teleporting to the tattoo parlor;[Man braucht hier keinen Parameter angeben, weil die Spielfigur, die die Action ausführt, automatisch in den Parameter hineingesteckt wird]
Außerdem kann man Actions in einer Variable abspeichern und erst später aufrufen:
An abeyance is a stored action that varies.
[...]; now the abeyance is the action of Bob examining the player;
[...]; try the abeyance;
[...]; now abeyance is the action of the current manager firing the noun;
Weitere Details bzgl. der Reihenfolge der Regelbücher bei Actions
Die drei oben beschriebenen Regelbücher (check, carry out, report) sind nicht die ganze Wahrheit, wie das Tutorial deutlich macht. Für jede Action werden eigens diese drei Regelbücher erstellt. Außerdem gibt es für alle Actions noch gemeinsame Regelbücher. Im Folgenden die Reihenfolge, in welcher die Regelbücher abgegrast werden:
- Setting Action Variables for <action>: Dieses Regelbuch wird auch für jede Action erstellt. Hier können Variablen gesetzt werden, die innerhalb der Action gebraucht werden. Sie sind auch nur dort gültig. Meistens braucht man dieses Regelbuch aber nicht.
- Before: Anhand der Reihenfolge sieht man, dass diese Aktionen noch VOR der eigentlichen Action kommen. Man kann hier z.B. Ergänzungen von Standardaktionen reinbringen.
- für NPCs: Persuasion: Hier wird überprüft, ob - wenn die Spielerin einen NPC auffordert, etwas zu tun - der NPC der Aufforderung nachkommt. Falls nicht, soll das entsprechend kommuniziert werden.
- Instead: hier ist das Default-Ergebnis: Failure, das heißt, im Normalfall wird nur eine Regel ausgeführt, und dann wird aufgehört). Ist geeignet, um einzelne oder Gruppen von Standard-Actions zu blockieren.
- Check <action>: Bereits von oben bekannt.
- Unsuccessful Attempt By: Kommt nur bei NPCs zum Zug, wenn Instead oder Check ein fehlgeschlagendes Ergebnis liefern. Regeln dieser Art kommen zum Zug, wenn der NPC die Aufforderung zwar annimmt, aber eine CHECK oder INSTEAD-OF-Regel ihn daran hindert, der Aufforderung nachzukommen. Beispiel: Man kann dem Wächter befehlen, die Tür zu öffnen und selbst wenn er so nett ist und das tatsächlich tun würde, wäre das noch keine Garantie dafür, dass er es tun kann (weil er z.B. den Schlüssel nicht hat).
- Carry out <action>: Bereits von oben bekannt.
- After: hier ist das Default-Ergebnis: Success, das heißt, im Normalfall wird nur eine Regel ausgeführt, und dann wird aufgehört. Außerdem werden die Report-Rules übergangen, wenn outcome=success. Dieses Rulebook ist nützlich für Szenenwechsel oder um bestimmte wichtige Scenen einzuleiten. Beispiel: Nachdem du den Schlüssel gefunden hast, wirst du von den Wachen in den Kerker geworfen (Verdacht: Landesverrat).
- Report <action>: Wie gesagt - bei
try silently
wird dieses Regelbuch übersprungen.
- Was noch ganz informativ ist:
an actor
schließt NPCs und die Spielerin ein,someone
meint nur die NPCs und wenn kein Subjekt genannt ist, dann ist die Spielerin gemeint. Instruktive Beispiele aus dem Tutorial:
Instead of Tiny jumping: say "Tiny is too overweight to jump. You all must find another way to help him across."
Carry out an actor jumping: now the actor is on the nearby platform. ["an actor" applies to everyone]
Report someone jumping: say "You see [the actor] jump over." ["someone" applies to any NPC]
Report jumping: say "You jump over." [subject-less means the player]
Kinds of Actions und Regeln
Man kann Actions gruppieren, wie ich das in Session 2 gemacht habe:
- Vorbedingung ist, dass die Actions die gruppiert werden, bereits definiert wurden
Attacking is unjust action.
Kissing is just action.
- Nun kann man Im Header der Regeln anstatt der Action die Action-Gruppe angeben:
Instead of unjust action when the being of the player is just:
say "I cannot do this because of my moralic Being.";
increase UnjustDeeds of player by 1;
decrease the score by 10.
- Anmerkung: Für die Szenen ist das Schlüsselwort
during
sehr wichtig im Rahmen von Regeln. Auf diese Weise kann man zu verschiedenen Szenen verschiedene Gesetzmäßigkeitenn der Welt definieren:
Tabulating is acting like a frickin' accountant.
Scheduling is acting like a frickin' accountant.
Instead of acting like a frickin' accountant during the collapsing bridge scene, say "You calculate (correctly) that you're about to become a victim of natural selection."
- Es gibt eine spezielle Action-Group:
doing something
oderdoing anything
. Sie enthält alle Actions. - Wenn man diese Action-Group in einer Regel verwendet, kann man nachfolgend mit
except
oderother than
und einer Liste von Actions veranlassen, dass diese Actions nicht unter diese Regel fallen:
Instead of someone doing anything except taking, dropping, or burning with something incriminating, say "[The actor] says, 'No, I must get rid of [the noun]!'"
with something incriminating
beschreibt näher, auf welche Objekte diese Regel zutrifft. Man kann das with
durch to
ersetzen oder ganz weglassen (je nachdem, wie es sich am Besten lesen lässt):
After examining, looking under, or searching anything owned by Mr Blackheart during a scene needing tension: say "Suddenly, Blackheart re-enters the room. 'What are you doing.' It wasn't a question."
Ein paar Bemerkungen zu Understand
- Wie bereits bekannt, kann man mit Understand eine Verbindung zwischen Eingaben der Spielerin und Actions herstellen. Wichtig dabei sind sogenannte Topics, das sind jene Texte, die im Understand-Befehl zwischen den Anführungszeichen (
"
)stehen:
Understand "read [book]" as reading.
- "read [book]" ist ein Topic. Es repräsentiert ein bestimmtes Eingabemuster. Der Parser schaut sich die Texteingaben der Spielerin an und prüft, ob die Texteingabe mit diesem Muster übereinstimmt (in der Informatik gibt es komplexere Muster, die mit sogenannten Regulären Ausdrücken alias Regexes beschrieben werden). Wenn eine Übereinstimmung festgestellt wird (das nennt man Match; sprich: Der Text "matched".) wird die Aktion ausgeführt.
- Man kann den Understand-Befehl nicht nur für Actions verwenden, sondern auch für viele andere Zwecke. Reihe von guten Beispielen finden sich im Tutorial.
Understand "dog" as Rover.
Understand "Rover" as Rover The Dog when the player knows-about Rover. [knows-about ist IMHO eine Relation. Die Eingabe wird nur mit dem Hundobjekt Rover assoziiert, wenn die Relation "knows-about" zwischen player und Rover hergestellt ist.]
- Man kann Texteingaben auch als Fehler/mistakes assoziieren. Der Parser reiht solche Understand-Befehle vor den non-mistake-Understand-Befehlen. Beispiel aus der Dokumentation (vgl. Kapitel 16.20 ):
Understand "take umbrage" as a mistake ("Nobody takes umbrage in this game, mister.").
- hat Vorrang gegenüber:
Understand "take [something]" as taking.
- außerdem kann man auch Bedingungen zu mistakes hinzufügen (aber erst nach dem Klammerausdruck):
Understand "xyzzy" as a mistake ("The machine doesn't seem to have a button with that label on it.") when in the teleportation chamber.
Szenen: Die Entwicklung temporärer Strukturen
"The Room class divides space into discrete places. Scenes divide an interactive fiction into durations of time."
- Szenen haben Anfangs- und Endbedingungen.
- Im Normalfall können sich Szenen wiederholen, außer man definiert sie als
non-recurring
.
A lightsaber duel is a [non-recurring?] scene.
A lightsaber duel begins when the location of Luke is the location of Darth.
A lightsaber duel ends when Luke is too injured to continue or Darth is too injured to continue.
A person can be too injured to continue. A person is rarely too injured to continue.
- Finde ich wichtig: Mit
during
kann man innerhalb von Regelheadern und mit is happening
innerhalb von normalem Befehlscode prüfen, ob man gerade in einer bestimmten Szene ist:
Every turn during a lightsaber duel: say "BWWAAUUAAAHH".
[...]; if a lightsaber duel is happening, [...]
- Wenn man eine Szene erstellt, erstellen sich automatisch zwei Regeln, die man mit Inhalt füllen kann oder nicht:
When a lightsaber duel begins: change the command prompt to the battle command prompt.
When a lightsaber duel ends: change the command prompt to the normal command prompt.
- Zu einer Szene kann man benannte Boolean-Eigenschaften hinzufügen, wie bei einem Objekt (auch wenn Szenen keine Objekte sind):
A scene can be thrilling or dull. Train Stop is dull.
A scene has a text called cue speech. The cue speech of Train Stop is "All aboard!".
Every turn during a dull scene: [...].
[...]; if a thrilling scene is happening, [...]
- Es gibt einen Debug-Befehl für Szenen, der dann im Spiel anzeigt, wann welche Szene beginnt bzw. endet.
SCENES
Arrays / Tables
- Arrays in Inform7 sind nur 2-Dimensional (also Tabellen) und eher nicht dazu da, Berechnungen durchzuführen, sondern um gelegentlich darin nachzusehen und das Ergebnis dieses Nachsehens ins Spiel einzubauen. Um eine Tabelle zu definieren, braucht man zunächst eine leere Zeile und danach einen von zwei möglichen Syntaxen (NB.: Das ist die korrekte Mehrzahl von Syntax):
Inline-Syntax
- Die Art (der Typ) der Elemente in der Spalte wird in der ersten Zeile, wo die Spaltennamen festgelegt werden, in Klammern angegeben.
- Nachteil: Man kann, wenn das Element ein thing sein soll, nicht differenzieren, welches thing es ist. Man muss
some object
und kann nicht some book
schreiben. Bei der In-Row-Syntax funktioniert das.
Table 2.1 - Selected Elements
Element (some text)
Symbol (some text)
Atomic number (a number)
Atomic weight (a number)
"Hydrogen"
"H"
1
1
"Iron"
"Fe"
26
56
"Zinc"
"Zn"
30
65
"Uranium"
"U"
92
238
In-Row-Syntax
- Die Art (der Typ) der Elemente einer Spalte wird in der ersten Zeile festgelegt.
- Nachteil: Die erste Zeile hat keinen Inhalt, wird aber von Inform7 nicht als leer erkannt.
Table of Selected Elements
Element
Symbol
Atomic number
Atomic weight
text
text
number
number
"Hydrogen"
"H"
1
1
"Iron"
"Fe"
26
56
- Wichtig ist, dass man tatsächlich den TAB-Character (ASCII-Code: 0009
- kann man auch durch drücken von ALT+"9" erreichen) zwischen den einzelnen Elementen verwendet.
- Man kann die Angabe der Art / des Typs auch ganz weglassen - meist erkennt Inform7 automatisch, welcher Typ zu verwenden ist.
Wie greift man auf die Tabellenelemente zu?
- Die Möglichkeiten in I7, was man mit einer Tabelle machen kann, sind (gegenüber anderen Programmiersprachen) ziemlich eingeschränkt, aber für viele Zwecke reicht es.
- Das Prinzip, wie man Tabellen abfragen kann, besteht darin, dass man zuerst genau eine Zeile auswählt (
choose row
und dann auf eine Spalte ([column-name] entry
) zugreifen kann. Es ist nicht möglich, mehrere Zeilen auszuwählen oder eine Zeile zurückzugeben um dann mit ihr zu arbeiten. Es folgen nun Beispiele aus dem Tutorial, die Anmerkungen sind von mir:
if Wind is a Fuel listed in The Table Of Energy Proponents ...[Wind ist ein Element; Fuel ein Spaltenname]
blank out the whole row;[Zeile löschen]
choose row My Favorite Number in The Table Of Energy Proponents;[Zeile auswählen; My Favorite Number ist eine Variable, die eine Zahl enthält]
if there is no Proponent entry ...[Proponent ist ein Spaltenname]
choose row with Danger of 10 in The Table Of Energy Proponents;[einfache Abfrage; gib mir die Zeile, wo das Element der Spalte Danger 10 ist]
if there is a Proponent corresponding to a Fuel of Geothermal in The Table Of Energy Proponents ...[Gibts einen Eintrag bei Proponent in der Zeile, wo die Spalte Fuael das Element "Geothermal" enthält?]
choose a blank row in Table 2.1;[leere Zeile auswählen]
change Element entry to "Fluorine";[Element eintragen]
change Atomic Number entry to 9;[Element eintragen]
if there is an Atomic Number in row 2 of The Table Of Standard Elements ...
sort The Table Of Energy Proponents in reverse Danger order;[reverse order heißt: absteigend - größter Wert als Erstes und dann wirds immer kleiner. Aufsteigend wäre in accession order]
sort The Table Of Energy Proponents in random order;[Zeilen zufällig anordnen]
... the number of blank rows in Table 2.1 ...[Gibt die Zahl der leeren Zeilen zurück]
... the number of filled rows in Table 2.1 ...[Gibt die Zahl der nicht-leeren Zeilen zurück]
... the Proponent corresponding to a Fuel of Hydrogen in The Table Of Energy Proponents ...[gibt den in Frage stehenden Proponenten zurück]
... Symbol in row 3 of The Table Of Selected Elements ..[Gibtt das Symbol in Zeile 3 zurück]
Anwendungsbeispiel: Buchseiten
- In meinem Buchbeispiel aus Session3 ist der Satz, der in den Seiten steht, eine zufällige Auswahl aus ein paar wenigen Sätzen. Außerdem: Wenn man sich zwei mal dieselbe Seite durchliest, kommt man sehr wahrscheinlich zu dem unrealistischen Effekt, dass plötzlich ein anderer Text auf dieser Seite steht. Ich versuche, das nun zu beheben, indem ich eine Tabelle erstelle, in der der Inhalt der einzelnen Seiten festgelegt wird. Außerdem soll man nur soweit blättern können, wie es definierte Seiteninhalte in der Tabelle gibt. Ans Werk...
Die aktuelle Version des Buchbeispiels befindet sich im hiesigen SVN-Verzeichnis Probegalopp. Dort steht der gesamte Quellcode zur Verfügung - anbei nur ein paar Erklärungen und Code-Schnippsel, die als Anwendungsbeispiele dieses Kapitels über Tabellen dienen können:
- Die Inhalte werden einfach gesagt mit jedem Umblättern (browsing) in die Seiten-Eigenschaft text geschrieben.
Understand "browse [something]" as browsing.
Carry out browsing:
pageswitch the noun.
Wenn die Spielerin 'browse yellowBrowser' eingibt und 'yellowBrowser' ein Ding in der IF-Welt ist (idealerweise ein Buch), werden die Regeln für die Aktion 'browsing' aufgerufen. Die wichtigsten sind: 'Check browsing', 'Carry out browsing' und 'Report browsing'. Bei Carry out browsing, dort wo die eigentliche Aktion stattfinden soll, wird eine Hilfsfunktion 'pageswitch <book>' aufgerufen, die dann - wie man gleich sieht - eine andere Hilfsfunktion 'content of <book> at page <number>' aufruft. Zunächst pageswitch:
To pageswitch (whatever - a book):
Let L be the list of pages which are part of the noun;
repeat with item running through L begin;
let x be the page number of the item;
increase x by 2;
let newcontent be content of the noun at page x;
if newcontent is empty begin;
say "I can not browse on. This is the end of the book.";
break;
else;
increase the page number of item by 2;
now the text of the item is newcontent;
end if;
end repeat.
Ein Buch hat zwei Seiten - eine linke und eine rechte. Bei beiden muss der Inhalt aktualisiert werden. Deswegen schreibt man in die Variable L eine Liste, die alle page-Objekte enthält, die Teil des Buches sind, das man umblättern möchte. Jetzt geht man einzeln durch die Liste durch (repeat with item), wobei item das jeweilige page-Objekt (left page oder right page) ist. Für jede Page wird nun die aktuelle Seitenzahl geholt, 2 dazugezählt und dann der Inhalt für die neue Seite geholt. Der Inhalt findet sich in der Tabelle (dazu siehe den gesamten source code). Geholt wird er mit der Hilfsfunktion 'content of <book> at page <number>'.
To decide what text is content of (bookvar - a book) at page (pagenum - a number):
repeat with N running from 1 to the number of filled rows in Table 1.0 begin;
if thing in row N of Table 1.0 is bookvar begin;
if page in row N of Table 1.0 is pagenum begin;
decide on content in row N of Table 1.0;
end if;
end if;
end repeat;
decide on "".
'To decide what text' zeigt an, dass ein Text zurückgegeben wird. Und zwar soll der content zurückgegeben werden, der in der Tabelle für die angegebene Seitenzahl für das angegebene Buch festgelegt wurde. Wenn nichts gefunden wurde, sollte ein leerer String zurückgegeben werden, doch leider ist I7 bei Zugriff auf einen Inhalt, der nicht existiert ziemlich heikel, weshalb eine Fehlermeldung erscheint. Deshalb sollte man immer eine gerade Anzahl an Buchseiten in der Tabelle definieren. Außerdem sollten die Einträge beginnend bei 1 fortlaufend (ohne Unterbrechungen) eingetragen werden.
- Um festzustellen, wie man am Ende des Buches angekommen ist, wird beim Öffnen des Buches eine Maximalseite festegestellt, die vor jedem Umblättern (in der Check browsing-Rule) überprüft wird. Es wird - wenn man am Ende angekommen ist - eine entsprechende Meldung ausgegeben. Um wieder auf den ersten beiden Seiten zu beginnen, muss man das Buch schließen und wieder öffnen (Man könnte natürlich ohne viel Aufwand eine entsprechende Aktion 'browsing back' oder sogar 'browsing back to <page number>' implementieren, die einfach zurückblättert).
Check browsing:
[...];
Let L be the list of right pages which are part of the noun;
repeat with item running through L begin;
if maxpage of the noun is page number of item begin;
say "I cannot browse [the noun] any more because this is the end of the book." instead;
end if;
end repeat.
Das Maximum muss man mit der rechten Seite vergleichen (es könnte sein, dass man auf die rechte Seite des Buches eleganter kommt, aber anders ist es mir kurzfristig nicht gelungen), weil rechts immer die höhere Seitenzahl steht. Wenn das Maximum erreicht wird, wird eine entsprechende Meldung ausgegeben, anstatt (instead
) dass weitergeblättert wird.
Carry out switching on described books:
Let L be the list of pages which are part of the noun;
repeat with item running through L begin;
let x be the page number of the item;
let newcontent be content of the noun at page x;
if newcontent is empty begin;
say "This seems to be an empy book.";
stop the action;
break;
else;
now the text of the item is newcontent;
end if;
end repeat;
now the maxpage of the noun is maximum page of noun.
Beim Öffnen des Buches müssen die aktuellen zwei Seiteninhalte aus der Tabelle gelesen werden. Das ist ein ähnlicher Vorgang wie beim Weiterblättern. In der letzten Zeile wird das Maximum mit der Hilfsfunktion 'maxpage of <book>' gesucht. Die zurückgegebene Zahl wird als Wert der Buch-Eigenschaft 'maximum page' (siehe vollständiger Quellcode im SVN) geschrieben.
Carry out switching off described books:
Let L be the list of pages which are part of the noun;
repeat with item running through L begin;
if the item is a left page begin;
now the page number of the item is 1;
else;
now the page number of the item is 2;
end if;
let x be the page number of the item;
let newcontent be content of item at page x;
if newcontent is empty begin;
break;
else;
now the text of the item is newcontent;
end if;
end repeat.
Beim Schließen des Buches wird der Anfangszustand wiederhergestellt, das heißt die ersten beiden Seiteinhalte werden jeweils in den Seitentext hinein geladen.
Named Values ?
<todo>
3,3 of 5 TUTORIAL-PARTS studied. TO BE CONTINUED...
- Eventuell sollte ich diesen Einschub auf eine extra Seite geben und dann nur eine Referenz drauflegen.
- Übrigens: Wenn man "Inform7" im deutschsprachigen Google eingibt, bekommt man einige Ergebnisse, die beim Philo-Wiki landen. --Andyk 18:54, 27. Feb. 2009 (UTC)