Benutzer:Andyk/Mitschriften/Technische I7-Auseinandersetzungen: Unterschied zwischen den Versionen

Aus Philo Wiki
Wechseln zu:Navigation, Suche
K (corr. Feinheit)
K (syntax: Inform-Code)
 
(17 dazwischenliegende Versionen von 3 Benutzern werden nicht angezeigt)
Zeile 1: Zeile 1:
 +
{{PSI}}
 
= Was ist das hier? =
 
= 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.
+
Ich habe mir gedacht, dass das [[Benutzer:Andyk/Mitschriften/Projekttagebuch#Zusammenfassung_und_Ausblick|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 [http://www.ifwiki.org/index.php/Inform_7_for_Programmers 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.
 
Es folgen nun einfach ein paar Notizen, die ich mir beim Lesen des [http://www.ifwiki.org/index.php/Inform_7_for_Programmers 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.
Zeile 26: Zeile 27:
 
= Wissenswertes über die Basics =
 
= Wissenswertes über die Basics =
  
* Die Artikel ('some', 'a', 'the', 'an') werden beim Kompilieren einfach entfernt.
+
* Die Artikel ('some', 'a', 'the', 'an') werden '''in den meisten Fällen''' beim Kompilieren einfach entfernt (manchmal sind sie aber relevant).
 
* 'is' und 'are' sind synonym (ist also egal, was du verwendest)
 
* 'is' und 'are' sind synonym (ist also egal, was du verwendest)
  
 
== Variablen ==
 
== Variablen ==
 
* Man kann einfach einen Satz schreiben der mit "that varies." endet.
 
* Man kann einfach einen Satz schreiben der mit "that varies." endet.
* Die wichtigsten vordefinierten 'Kinds of Values' (Datentypen) sind:
+
* Die wichtigsten vordefinierten 'Kinds of Values' (Datentypen) bzw. Kinds (Klassen), die man als Variablen verwenden kann, sind:
 
** number, text, truth state
 
** number, text, truth state
 
** thing, person, direction
 
** thing, person, direction
Zeile 45: Zeile 46:
 
Da ist mir das meiste schon von der Dokumentation gut bekannt, außer:
 
Da ist mir das meiste schon von der Dokumentation gut bekannt, außer:
 
* Wenn nach einer Raum-Instanz wie <code>My house is a room,</code> ein  Text wie "Schönes, großes Haus." kommt, dann wird der Text der  Description-Property zugewiesen.
 
* Wenn nach einer Raum-Instanz wie <code>My house is a room,</code> ein  Text wie "Schönes, großes Haus." kommt, dann wird der Text der  Description-Property zugewiesen.
* Wenn nach einer Objekt-Instanz wie <code>The apple is a thing.</code>  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.
+
* Wenn nach einer Objekt-Instanz wie <code>The apple is a thing.</code>  so ein Text kommt, dann wird er der "Initial Appearance"-property  zugewiesen. <s>Wenn das Ding von der Spielerin aufgehoben wird, wird AFAIK  der Initial appearance-text ausgegeben.</s>
 +
 
 +
'''UPDATE''': "Die initial appearance wird auf den Befehl "look" hin ausgegeben, wenn das Ding sich im Raum befindet und der Spieler das Ding noch nie in der Hand hatte (wird über die property "handled" geregelt)". (Danke an [[Benutzer:H.A.L.|H.A.L.]] für die Korrektur und für [[Benutzer_Diskussion:Andyk/Mitschriften/Technische_I7-Auseinandersetzungen|seine Demonstration]] diesbezüglich.)
  
 
== Klassen / kinds ==
 
== Klassen / kinds ==
Zeile 135: Zeile 138:
 
== To say... ==
 
== 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.
 
* 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
+
* Die Syntax funktioniert ansonsten genauso wie [[#Funktionen, die keinen Wert zurückliefern|hier]] erklärt
 
   
 
   
 
<code>To say He-She for (P - a person):</code>
 
<code>To say He-She for (P - a person):</code>
Zeile 147: Zeile 150:
 
Aufruf mit eckigen Klammern:
 
Aufruf mit eckigen Klammern:
 
:<code>[...]; say "[He-She for Chris] says Hello.";</code>
 
:<code>[...]; say "[He-She for Chris] says Hello.";</code>
 +
 +
 +
 +
* '''UPDATE''': H.A.L. [[Benutzer_Diskussion:Andyk/Mitschriften/Technische_I7-Auseinandersetzungen#To_say...|weist darauf hin]], dass man hier nicht nur say-Befehle sondern auch alle anderen Arten von Befehlen verwenden und so Code in Text einschmuggeln kann, was manchmal sehr nützlich ist, wie anhand einer kleinen [[Benutzer:H.A.L./Inform_Code-Beispiele#To_say..._-_Code_in_Strings_einschmuggeln|IF über eine 1000-jährige Eiche]] gezeigt wird.
  
 
= Relationen =
 
= Relationen =
Zeile 308: Zeile 315:
 
* Es gibt eine spezielle Action-Group: <code>doing something</code> oder <code>doing anything</code>. Sie enthält alle Actions.
 
* Es gibt eine spezielle Action-Group: <code>doing something</code> oder <code>doing anything</code>. Sie enthält alle Actions.
 
* Wenn man diese Action-Group in einer Regel verwendet, kann man nachfolgend mit <code>except</code> oder <code>other than</code> und einer Liste von Actions veranlassen, dass diese Actions nicht unter diese Regel fallen:
 
* Wenn man diese Action-Group in einer Regel verwendet, kann man nachfolgend mit <code>except</code> oder <code>other than</code> und einer Liste von Actions veranlassen, dass diese Actions nicht unter diese Regel fallen:
:<code>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]!'"
+
:<code>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]!'"</code>
 
* <code>with something incriminating</code> beschreibt näher, auf welche Objekte diese Regel zutrifft. Man kann das <code>with</code> durch <code>to</code> ersetzen oder ganz weglassen (je nachdem, wie es sich am Besten lesen lässt):
 
* <code>with something incriminating</code> beschreibt näher, auf welche Objekte diese Regel zutrifft. Man kann das <code>with</code> durch <code>to</code> ersetzen oder ganz weglassen (je nachdem, wie es sich am Besten lesen lässt):
 
:<code>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."</code>
 
:<code>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."</code>
Zeile 567: Zeile 574:
 
::<code>end repeat.</code>
 
::<code>end repeat.</code>
  
Beim Schließen des Buches werden der Anfangszustand wiederhergestellt, das heißt die ersten beiden Seiteinhalte werden in den Seitentext reingeladen.
+
Beim Schließen des Buches wird der Anfangszustand wiederhergestellt, das heißt die ersten beiden Seiteinhalte werden jeweils in den Seitentext hinein geladen.
 +
 
 +
= Kind of Values: Values durch Tabellen definieren=
 +
In der [[Benutzer:Andyk/Mitschriften/PSI_06_12_08_Inform7_Einführung|I7-Einführung]] ist das Grundkonzept schon vorgestellt. Was dort noch nicht erwähnt ist: Man kann die einzelnen Values auch in einer Tabelle angeben:
 +
 
 +
<code>Tattoos are a kind of value. Some tattoos are defined by the Table of Designs.</code>
 +
 
 +
:<code>Table of Designs</code>
 +
:<code>tattoo</code>
 +
:<code>barbed wire</code>
 +
:<code>wings</code>
 +
 
 +
 
 +
:<code>Table of Designs (continued)</code>
 +
:<code>tattoo</code>
 +
:<code>Jean-Pierre 4-ever</code>
 +
 
 +
 
 +
Das hat den Vorteil, dass man - wenn man eine Extention schreibt - die Wahl der Tattoo-Motive dem IF-Entwickler, der die Extention benutzt, überlassen kann, ohne dass dieser an der Extention herumbasteln müsste.
 +
 
 +
= Aggregationen über Textausgaben und Texteingaben =
 +
* Wenn man im Text ein 'double quote' haben will, schreibt man: <code>say "Er fragte: 'Was?', und sein Blick durchbohrte mich.";</code>.
 +
* Wenn man im Text ein einfaches Apostroph haben will, schreibt man: <code>say "Im Hintergrund lief der Song von Rare[']n[']Tasty - Jamma ma.";</code>.
 +
* Zeilenumbruch: <code>say "A[line break]B[line break]C.";</code>
 +
* Automatischer Zeilenumbruch, wenn am Ende des Textes <code>!</code>, <code>?</code> oder <code>.</code> steht.
 +
* Text-Formatierung: <code>say "[bold type] -FETTER TEXT- [roman type] -NORMALER TEXT- [italic type] -KURSIVER TEXT- [roman type].";</code>
 +
* Wert einer Variable bzw. Name eines Objekts: <code>say "[the noun] is already open. It has [maximum page of the noun] Pages.";</code>
 +
 
 +
== Was ist 'Indexed Text'? ==
 +
Aus technisch-historischen Gründen (wenig Arbeitsspeicher) wurden Texte in Inform komprimiert. Alle Zeichenketten vom Typ 'text' sind also komprimiert. Das hat den Nachteil, dass man - wie das Tutorial sagt - reguläre Ausdrücke nur in der Version für arme Leute (a poor man's regex) bekommt. Nachträglich (Mangelnder Arbeitsspeicher ist in aktuellen Heimcomputern kein großes Thema mehr) hat man den Typ 'indexed text' hinzugefügt, der den Text unkomprimiert speichert. Diese Änderung bietet den Komfort (den man üblicherweise nur als Informatiker zu schätzen weiß *g*), reguläre Ausdrücke zu verwenden.
 +
 
 +
Zunächst einmal: Wie kann man Zeichenketten als 'indexed text' speichern?
 +
<code>Let T be indexed text;<br>Let T be "This is indexed text now.";</code>
 +
 
 +
Was kann man nun mit so einem indexed text anfangen? Das Tutorial beschreibt, dass man damit die Eingaben der Spielerin direkt abfangen, prüfen und manipulieren kann. Das wird im Vergleich mit normalen Text, wo der Zugang zu den Eingaben der Spielerin vermittelt ist, gezeigt.
 +
 
 +
== Spielereingaben abfangen ==
 +
 
 +
Mit normalen Text kann man die Eingaben der Spielerin folgendermaßen prüfen:
 +
:<code>if the player's command does not include "please/thanks", say "How rude!";</code>
 +
:<code>if the player's command includes "please/thanks", cut the matched text;</code>
 +
:<code>if the player's command includes "hi", replace the matched text with "hello";</code>
 +
:<code>if the player's command matches "hello world", say "You're a programmer, aren't you?";</code>
 +
:<code>if the player's command does not match "hello world", say "To code... perchance, to write?";</code>
 +
 
 +
Der Text nach includes bzw. matches ist ein Topic (vgl. das [[Benutzer:Andyk/Mitschriften/Technische_I7-Auseinandersetzungen#Ein_paar_Bemerkungen_zu_Understand|obige Kapitel zu Understandings]]) - dort wird die poor man's regex verwendet. Man kann den player's command text nun in einen indexed text umwandeln und darauf dann reguläre Ausdrücke anwenden:
 +
:<code>let N be indexed text;</code>
 +
:<code>let N be the player's command;</code>
 +
:<code>[...];</code>
 +
:<code>change the text of the player's command to N;</code>
 +
Die letzte Zeile schreibt also das, was man in <code>[...];</code> machen könnte, wieder zurück zum player's command. Im Tutorial wird beschrieben, dass diese Zeile nicht flexibel ist (auch das 'the' for text ist notwendig). Der einzige Parameter ist nach dem Wort 'to' anzugeben, in diesem Fall N. Der Rest muss genau so aussehen, damit es funktioniert.
 +
 
 +
Beispiel, was man in <code>[...];</code> machen könnte:
 +
<code>if N matches the regular expression "hello.?(world|w0rld|word|game|help)", case insensitively then let N be "help";</code>
 +
 
 +
== Weiterführendes über exzessive Zeichenmanipulation ==
 +
* Speicherrestriktionen bei indexed text beachten (vgl. [http://www.inform-fiction.org/I7/doc332.html I7-Doku Abschnitt 19.2])
 +
* Abschnitt über reguläre Ausdrücke bei indexed text (vgl. [http://www.inform-fiction.org/I7/doc336.html I7-Doku Abschnitt 19.6] und intelligente Ersetzungsmechanismen im [http://www.inform-fiction.org/I7/doc338.html Abschnitt 19.8])
 +
* Cheat-Sheet über reguläre Ausdrücke in [http://www.inform-fiction.org/I7/doc339.html I7-Doku Abschnitt 19.9]
 +
 
 +
 
 +
= Units : Zusammengesetzter Datentyp =
 +
Eine Unit ist ein spezieller Zahlen-Datentyp, bei dem man auf vorher definierte Teile zugreifen kann. Im Tutorial wird Geld als Kind of Value eingeführt, wobei dollar und cent als Parts definiert werden:
 +
 
 +
 
 +
<code><br>Money is a kind of value. $19.99 specifies some money with parts dollars (without leading zeros) and cents (optional, preamble optional).<br> My wallet is some money that varies. My wallet is usually $20.75. <br>A thing has some money called the price. The price of a thing is usually $5.<br>The price of Bob is $2.05.<br><br>say "[the dollars part of the price of Bob]";</code>
 +
 
 +
 
 +
Man kann nur Units der gleichen Art addieren/subtrahieren.
 +
Units können dann wie üblich in Understand-Topics verwendet werden:
 +
<code>Understand "donate [money]" as donating.<br>Donating is an action applying to some money.</code>
 +
 
 +
 
 +
Man kann auch nützliche Abkürzungen mit 'implies' definieren:
 +
<code>The verb to cost (it costs, they cost, it is costing) implies the price property.<br>The jeans cost $19.95.</code>
 +
 
 +
Der obige Code erstellt noch keine Relation. Dann müsste es so aussehen:
 +
 
 +
<code>Fanciness relates a thing (called X) to some money (called Y) when the price of X > Y. The verb to be fancier than implies the fanciness relation.</code>
 +
 
 +
<code>let L be the list of things fancier than $2.50;</code>
 +
<code>let B be the list of things fancier than the price of jeans;</code>
 +
 
 +
= Aktivitäten =
 +
Wurden in meinen bisherigen I7-Betrachtungen relativ wenig behandelt und kommen auch im Tutorial nicht wirklich vor. Doch ich finde, sie sind ein mächtiges Werkzeug, um die Standard-Welt von I7 zu verstehen und auch zu ändern (das meiste, was ich davon weiß, hab ich aus der  [http://www.inform-fiction.org/I7/chap17.html Dokumentation, Kapitel 17]). Darum also dieses Kapitel.
 +
 
 +
Im Unterschied zu Aktionen sind Aktivitäten nicht primär auf die Handlungsmöglichkeiten der Spielfigur orientiert, sondern an den Prozessen, die im Code vor sich gehen. Man kann durch zusätzliche Regeln zu Standard-Aktivitäten das Verhalten der I7-Welt verändern (diese Regeln plaziert man in eine der 3 Regelbücher, die für eine Aktivität angelegt werden).
 +
 
 +
== interessante Standard-Aktivitäten ==
 +
Es gibt für jede dieser Aktivitäten und auch für andere einen eigenen Abschnitt in der Dokumentation, der die Möglichkeiten genauer beschreibt und mit Beispielen veranschaulicht:
 +
 
 +
* Den Namen eines Dings ausgeben: [http://www.inform-fiction.org/I7/doc282.html printing the name of something]
 +
* Wenn im Raum mehrere identische Dinge liegen: [http://www.inform-fiction.org/I7/doc283.html Printing the plural name of something]
 +
* Falls bestimmte Aktionen nicht im Dunkeln ausgeführt werden können: [http://www.inform-fiction.org/I7/doc288.html Printing a refusal to act in the dark]
 +
* Wenn sich die Umgebung von hell auf dunkel ändert: [http://www.inform-fiction.org/I7/doc289.html Printing the announcement of darkness]
 +
* Wenn sich die Umgebung von dunkel auf hell ändert: [http://www.inform-fiction.org/I7/doc290.html Printing the announcement of light]
 +
* Wie soll ein Raum im Dunkeln heißen? (default: "Darkness"): [http://www.inform-fiction.org/I7/doc291.html Printing the name of a dark room]
 +
* Wie soll die Beschreibung eines dunklen Raums sein? [http://www.inform-fiction.org/I7/doc292.html Printing the description of a dark room]
 +
* Nützlich wenn man lange Raumnamen hat, die unschön in der Statusleiste sind: [http://www.inform-fiction.org/I7/doc282.html Constructing the status line]
 +
* Sehr interessant: Man kann dem Spieler Erscheinungen vortäuschen, mit denen er so interagieren kann, wie wenn sie wirklich gerade in der Welt wären. Eine andere möglichkeit mit dieser Aktivität ist, dass man in einen bestimmten Raum reinsehen, aber nichts darin anfassen kann: [http://www.inform-fiction.org/I7/doc299.html Deciding the scope of something]
 +
* Bei mehrdeutigen Befehlseingaben, die sich auf ein einziges Ding beziehen sollten: [http://www.inform-fiction.org/I7/doc301.html Asking which do you mean]
 +
* Man kann bestimmte Spielereingaben von vornherein verwerfen und ein Kommentar dazu abgeben: [http://www.inform-fiction.org/I7/doc303.html Reading a command] - dazu siehe auch "the player's command"
 +
* Wenn der Parser die Spiellereingabe nicht interpretieren kann (es gibt verschiedene Typen von Errors, die man verwenden kann, um witzige und für den Spieler motivierende oder informative Effekte herbeizuführen): [http://www.inform-fiction.org/I7/doc305.html Printing a parser error]
 +
* Beim Starten des Spiels wird ein "Banner Text" mit Release-Informationen, Titel des Spiels, Datum, etc. angezeigt: [http://www.inform-fiction.org/I7/doc307.html Printing the banner text]
 +
* Wenn die Spielerin stirbt, wird eine Traueranzeige mit Erreichbaren Punkten, etc. angezeigt: [http://www.inform-fiction.org/I7/doc308.html Printing the player's obituary]
 +
* Nachdem  das Spiel gewonnen ist, kann die Spielerin "AMUSING" auswählen und die Spielentwickler können Easter-Eggs des Spiels oder versteckte Items oder Danksagungen oder alternative Lösungswege unterbringen: [http://www.inform-fiction.org/I7/doc282.html Amusing a victorious player]
 +
 
 +
== Regelbücher zu Aktivitäten ==
 +
 
 +
Pro Aktivität werden 3 Regelbücher erstellt, die (nicht so wie bei den Regelbüchern der Aktionen) immer durchlaufen werden müssen:
 +
* '''Before''': Alle Regeln in diesem Regelbuch werden befolgt, bevor die Aktivität ausgeführt wird.
 +
* '''For''': Die spezifischste Regel in diesem Regelbuch wird befolgt. Es reicht im Prinzip aus, dieses Regelbuch zu verwenden.
 +
* '''After''': Hier werden wieder alle Regeln aus diesem Regelbuch befolgt.
 +
 
 +
== Definition und Aufruf neuer Aktivitäten ==
 +
Man kann sagen, dass es sehr praktisch für die Programmiererin ist, oft verwendete Abläufe einmal zu schreiben und öfter verwenden, genau so, wie das bei den Standard-Aktivitäten der Fall ist (das Paradebeispiel: ''Printing the name of something'' wird sehr oft aufgerufen). Dazu definiert man sich neue Aktivitäten, wobei man zwischen 2 Typen von Aktivitäten unterscheidet:
 +
* Aktivitäten, die sich auf ein bestimmmtes Ding/einen bestimmten Raum beziehen
 +
<code>Analysing something is an activity.</code>
 +
* Aktivitäten, die sich nicht auf ein bestimmtes Ding/einen bestimmten Raum beziehen
 +
<code>Assaying is an activity.</code>
 +
 
 +
Neue Aktivitäten kann man überall im Code mit "Carry out <Aktivität>" aufrufen, wobei sie erst etwas Nützliches tun, wenn Regeln definiert werden. Man kann im Rahmen einer Aktivität Variablen definieren, auf die die Regeln zugreifen können. Ein Beispiel dazu aus der [http://www.inform-fiction.org/I7/doc278.html Doku]:
 +
<!-- source lang="inform" enclose="div" --><code>
 +
Analysing something is an activity. The analysing activity has a text called first impression. Instead of examining something (called the sample), carry out the analysing activity with the sample.
 +
 
 +
 
 +
Before analysing: now the first impression is "unremarkable".
 +
 
 +
 
 +
Rule for analysing someone: now the first impression is "living tissue".
 +
 
 +
 
 +
After analysing something (called the sample):
 +
    say "Your professional opinion of [the sample] is that it is
 +
        [first impression]."
 +
</code><!-- /source -->
 +
 
 +
 
 +
Man kann, wenn man in speziellen Fällen nicht alle before-for-begin-Regeln durchlaufen will, eine Aktivität statt mit "carry out <activity> with <thing>" auch folgendermaßen aufrufen, um den Regel-Apparat zu unterlaufen:
 +
<!-- source lang="inform" --><code>
 +
begin the analysing activity with the pitchblende;
 +
...
 +
if handling the analysing activity with the pitchblende:
 +
    ...
 +
...
 +
end the analysing activity with the pitchblende;
 +
</code><!-- /source -->
 +
 
 +
 
 +
''"Too many works of interactive fiction betray their mechanical nature by making it visible that the general machinery being used does not quite seem natural for this or that situation. Activities enable us to add the many graceful touches which avoid that: which contribute nothing to a work, and also everything."''
 +
 
 +
= Ein paar zusätzliche Hinweise =
 +
* [http://www.ifwiki.org/index.php/Inform_7_for_Programmers/Part_5#Testing_Commands Liste von Debug-Befehlen] (alias God-Mode-Befehle ^^)
 +
* [http://www.ifwiki.org/index.php/Inform_7_for_Programmers/Part_5#Grammar_Gotchas Häufige Syntax-Fehler]
 +
* [http://www.inform-fiction.org/I7Downloads/Documents/Appendix-A.pdf Das Standard-Regel-Buch], falls man die Grundfesten der I7-Welt umstoßen möchte
 +
== Seine Programmierstrukturen relativieren ==
 +
I7 vermischt mehrere Programmierparadigmen miteinander. Man läuft Gefahr, eine Untermenge von I7-Möglichkeiten, welche man einem Paradigma zuordnen kann, überzustrapazieren, weil man von seiner Programmiererfahrung her kommend sich in diesem Paradigma mehr beheimatet fühlt. Anbei ein paar Hinweise, wo man aufpassen muss:
 +
 
 +
'''Regeln sind keine Funktionen:'''
 +
Wenn man Regeln verwendet, sollte man immer die Bedingungen ihrer Ausführung im Header mitdefinieren. Eine Ausnahme könnte sein, wenn man eine Regel in einem Regelbuch mit einer neuen Regel ersetzen will. Dann wird nämlich der Header der alten Regel verwendet.
 +
 
 +
Zwei weitere Hinweise diesbezüglich, einen über die richtige Verwendung von Rulebooks, einen anderen über das Korrekte abgrasen von Listen, kann man sich bei Gelegenheit [http://www.ifwiki.org/index.php/Inform_7_for_Programmers/Part_5#Paradigm_Leaning direkt im Tutorial] durchlesen.
 +
 
 +
== Hacking: Einsicht und Modifikation der I7-Tiefenstrukturen ==
 +
Mit I7 wird einem ja standardmäßig ein gewisses Framework (Standard-Regeln,Standard-Aktionen,Standard-Aktivitäten) mitgegeben, das man benutzen - aber auch modifizieren kann. Ein interessantes Werkzeug dafür sind Prozedurale Regeln (procedural rules); das sind Meta-Regeln, die zur Laufzeit die Regeln umstellen, außer Kraft setzen kann.
 +
 
 +
Man kann sich die Frage stellen, wenn man ein IF schreiben will, wo der Spieler zu bestimmten Zeitpunkten ein Geist ist. An dieser Stelle kommen Prozedurale Regeln zum Zug:
 +
<code>A procedural rule when the player is a ghost: ignore the can't walk through closed doors rule.</code>
 +
Ohne 'when'-Klausel würde die Nicht-durch-geschlossene-Türen-gehen-Regel immer ignoriert werden und das müsste man nicht zur Laufzeit machen, sondern könnte es schon fix einprogrammieren (was bezüglich Performance sinnvoller wäre), nämlich so:
 +
<code>The can't walk through closed doors rule is not listed in any rulebook.</code>
 +
 
 +
Man kann mit prozeduralen Regeln die Grundfesten des IF-Frameworks modifizieren. Dazu schaut man sich die folgenden Rulebooks an:
 +
* the action-processing rulebook
 +
* the specific action-processing rulebook
 +
* the visibility rulebook
 +
* the accessibility rulebook
 +
* the player's action awareness rulebook
 +
* the turn sequence rulebook
 +
 
 +
Im Tutorial werden zur Modifikation folgende prinzipiellen Möglichkeiten aufgelistet:
 +
 
 +
Zunächst jene Möglichkeiten, die man fix (man sagt: zur Compilerzeit) einprogrammieren kann:
 +
 
 +
 
 +
::<code>The <rule> is not listed in any rulebook.</code>
 +
 
 +
::<code>[...]; ignore <rule>;</code>
 +
 
 +
::<code>[...]; reinstate <rule>; [undoes Ignore]</code>
 +
 
 +
::<code>The <rule> is listed instead of the <second rule> in the <rulebook>;</code>
 +
 
 +
::<code>[...]; substitute <rule> for <second rule> ;</code>
 +
 
 +
::<code>[...]; restore the original <rule>;</code>
 +
 
 +
::<code>The <rule> is listed before/after the <second rule> in the <rulebook>;</code>
 +
 
 +
::<code>[...]; move <rule> to before/after <second rule> ;</code>
 +
 
 +
 
 +
Und nun Möglichkeiten, die meinem Verständnis nach zur Laufzeit geprüft werden:
 +
 
 +
 
 +
::<code>[...]; reject the result of <rule>; [some rulebooks, like Instead, have a default outcome]</code>
 +
 
 +
::<code>[...]; accept the result of <rule>; [undoes Reject]</code>
 +
 
 +
Man sollte beide Möglichkeiten prinzipiell nur in prozeduralen Regeln verwenden.
 +
 
 +
== Hacking: Ersetzen ganzer Sections ==
 +
Man kann benannte Sections von bestimmten Extentions ersetzen, wenn man weiß, was man tut:
 +
::<code>Chapter 2a (for use with Locksmith by Emily Short)</code>
 +
 
 +
::<code>Chapter 2b (for use without Locksmith by Emily Short)</code>
 +
 
 +
::<code>Section 6 - Hacked locking (in place of Section 1 - Regular locking in Locksmith by Emily Short)</code>
 +
 
 +
 
 +
Man kann sogar Sections aus der automatisch geladenen Extention, die die Standard Rules enthält, ersetzen:
 +
 
 +
::<code>Section 8 - My thing class (in place of Section SR1/3 - Things in the Standard Rules by Graham Nelson)</code>
 +
 
 +
 
 +
Das nur für den Fall, dass Platons Staat sich gravierend den Standard-Regeln widersetzen würde, obwohl ich mich wohl nur ungern an großflächige Ersetzungen der Standard-Regeln wagen würde.
 +
 
  
= Named Values ? =
 
<todo>
 
  
<div align="center">'''''3,3 of 5 TUTORIAL-PARTS studied. TO BE CONTINUED...'''''</div>
+
----
  
* Eventuell sollte ich diesen Einschub auf eine extra Seite geben und dann nur eine Referenz drauflegen.
+
Übrigens: Wenn man [http://www.google.at/search?hl=de&q=inform7&btnG=Suche&meta=lr%3Dlang_de "Inform7" im deutschsprachigen Google] eingibt, bekommt man einige Ergebnisse, die beim Philo-Wiki landen. --[[Benutzer:Andyk|Andyk]] 22:17, 3. Mär. 2009 (UTC)
* Übrigens: Wenn man [http://www.google.at/search?hl=de&q=inform7&btnG=Suche&meta=lr%3Dlang_de "Inform7" im deutschsprachigen Google] eingibt, bekommt man einige Ergebnisse, die beim Philo-Wiki landen. --[[Benutzer:Andyk|Andyk]] 18:54, 27. Feb. 2009 (UTC)
 

Aktuelle Version vom 4. Oktober 2016, 21:38 Uhr

<root> <div class='right_side_navigation' style='width:156px;position:fixed;bottom:50px;background-color:#efefef;border-color:#bbbbbb;border-width:1pt;border-style:solid;padding:1px 2px;font-size:8pt;text-align:center;filter:alpha(opacity=90);-moz-opacity: 0.9;opacity: 0.9;'> Navigation (PSI)<br> Hauptseite (alt)<br> Hauptseite (Endspurt)<br> recent changes<br> Alle Seiten

Development<br> Endspurt<br> Dev-Talk<br> ChangeLog<br> Repository<br> Global Mindset V4<br /> Szenariosammlung<br /> Projekt-Präsentation

</div><ignore><includeonly></ignore><ignore></includeonly></ignore></root>

Inhaltsverzeichnis

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 in den meisten Fällen beim Kompilieren einfach entfernt (manchmal sind sie aber relevant).
  • '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) bzw. Kinds (Klassen), die man als Variablen verwenden kann, 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.

UPDATE: "Die initial appearance wird auf den Befehl "look" hin ausgegeben, wenn das Ding sich im Raum befindet und der Spieler das Ding noch nie in der Hand hatte (wird über die property "handled" geregelt)". (Danke an H.A.L. für die Korrektur und für seine Demonstration diesbezüglich.)

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 man always 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 ist A 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:

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 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.";


  • UPDATE: H.A.L. weist darauf hin, dass man hier nicht nur say-Befehle sondern auch alle anderen Arten von Befehlen verwenden und so Code in Text einschmuggeln kann, was manchmal sehr nützlich ist, wie anhand einer kleinen IF über eine 1000-jährige Eiche gezeigt wird.

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 und RULES 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 noch Instead 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 oder rule 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) und anonymously 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 Befehl examine (thing) gehört, nämlich zu examining.
    • Nebenbemerkung: Man kann zum Beispiel mit understand "examine (book)" as reading die Zuordnung: Befehl <-> Action verändern.
  • 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-, das carry out- und das report-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 mit the 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 oder doing anything. Sie enthält alle Actions.
  • Wenn man diese Action-Group in einer Regel verwendet, kann man nachfolgend mit except oder other 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.

Kind of Values: Values durch Tabellen definieren

In der I7-Einführung ist das Grundkonzept schon vorgestellt. Was dort noch nicht erwähnt ist: Man kann die einzelnen Values auch in einer Tabelle angeben:

Tattoos are a kind of value. Some tattoos are defined by the Table of Designs.

Table of Designs
tattoo
barbed wire
wings


Table of Designs (continued)
tattoo
Jean-Pierre 4-ever


Das hat den Vorteil, dass man - wenn man eine Extention schreibt - die Wahl der Tattoo-Motive dem IF-Entwickler, der die Extention benutzt, überlassen kann, ohne dass dieser an der Extention herumbasteln müsste.

Aggregationen über Textausgaben und Texteingaben

  • Wenn man im Text ein 'double quote' haben will, schreibt man: say "Er fragte: 'Was?', und sein Blick durchbohrte mich.";.
  • Wenn man im Text ein einfaches Apostroph haben will, schreibt man: say "Im Hintergrund lief der Song von Rare[']n[']Tasty - Jamma ma.";.
  • Zeilenumbruch: say "A[line break]B[line break]C.";
  • Automatischer Zeilenumbruch, wenn am Ende des Textes !, ? oder . steht.
  • Text-Formatierung: say "[bold type] -FETTER TEXT- [roman type] -NORMALER TEXT- [italic type] -KURSIVER TEXT- [roman type].";
  • Wert einer Variable bzw. Name eines Objekts: say "[the noun] is already open. It has [maximum page of the noun] Pages.";

Was ist 'Indexed Text'?

Aus technisch-historischen Gründen (wenig Arbeitsspeicher) wurden Texte in Inform komprimiert. Alle Zeichenketten vom Typ 'text' sind also komprimiert. Das hat den Nachteil, dass man - wie das Tutorial sagt - reguläre Ausdrücke nur in der Version für arme Leute (a poor man's regex) bekommt. Nachträglich (Mangelnder Arbeitsspeicher ist in aktuellen Heimcomputern kein großes Thema mehr) hat man den Typ 'indexed text' hinzugefügt, der den Text unkomprimiert speichert. Diese Änderung bietet den Komfort (den man üblicherweise nur als Informatiker zu schätzen weiß *g*), reguläre Ausdrücke zu verwenden.

Zunächst einmal: Wie kann man Zeichenketten als 'indexed text' speichern? Let T be indexed text;
Let T be "This is indexed text now.";

Was kann man nun mit so einem indexed text anfangen? Das Tutorial beschreibt, dass man damit die Eingaben der Spielerin direkt abfangen, prüfen und manipulieren kann. Das wird im Vergleich mit normalen Text, wo der Zugang zu den Eingaben der Spielerin vermittelt ist, gezeigt.

Spielereingaben abfangen

Mit normalen Text kann man die Eingaben der Spielerin folgendermaßen prüfen:

if the player's command does not include "please/thanks", say "How rude!";
if the player's command includes "please/thanks", cut the matched text;
if the player's command includes "hi", replace the matched text with "hello";
if the player's command matches "hello world", say "You're a programmer, aren't you?";
if the player's command does not match "hello world", say "To code... perchance, to write?";

Der Text nach includes bzw. matches ist ein Topic (vgl. das obige Kapitel zu Understandings) - dort wird die poor man's regex verwendet. Man kann den player's command text nun in einen indexed text umwandeln und darauf dann reguläre Ausdrücke anwenden:

let N be indexed text;
let N be the player's command;
[...];
change the text of the player's command to N;

Die letzte Zeile schreibt also das, was man in [...]; machen könnte, wieder zurück zum player's command. Im Tutorial wird beschrieben, dass diese Zeile nicht flexibel ist (auch das 'the' for text ist notwendig). Der einzige Parameter ist nach dem Wort 'to' anzugeben, in diesem Fall N. Der Rest muss genau so aussehen, damit es funktioniert.

Beispiel, was man in [...]; machen könnte: if N matches the regular expression "hello.?(world|w0rld|word|game|help)", case insensitively then let N be "help";

Weiterführendes über exzessive Zeichenmanipulation


Units : Zusammengesetzter Datentyp

Eine Unit ist ein spezieller Zahlen-Datentyp, bei dem man auf vorher definierte Teile zugreifen kann. Im Tutorial wird Geld als Kind of Value eingeführt, wobei dollar und cent als Parts definiert werden:



Money is a kind of value. $19.99 specifies some money with parts dollars (without leading zeros) and cents (optional, preamble optional).
My wallet is some money that varies. My wallet is usually $20.75.
A thing has some money called the price. The price of a thing is usually $5.
The price of Bob is $2.05.

say "[the dollars part of the price of Bob]";


Man kann nur Units der gleichen Art addieren/subtrahieren. Units können dann wie üblich in Understand-Topics verwendet werden: Understand "donate [money]" as donating.
Donating is an action applying to some money.


Man kann auch nützliche Abkürzungen mit 'implies' definieren: The verb to cost (it costs, they cost, it is costing) implies the price property.
The jeans cost $19.95.

Der obige Code erstellt noch keine Relation. Dann müsste es so aussehen:

Fanciness relates a thing (called X) to some money (called Y) when the price of X > Y. The verb to be fancier than implies the fanciness relation.

let L be the list of things fancier than $2.50; let B be the list of things fancier than the price of jeans;

Aktivitäten

Wurden in meinen bisherigen I7-Betrachtungen relativ wenig behandelt und kommen auch im Tutorial nicht wirklich vor. Doch ich finde, sie sind ein mächtiges Werkzeug, um die Standard-Welt von I7 zu verstehen und auch zu ändern (das meiste, was ich davon weiß, hab ich aus der Dokumentation, Kapitel 17). Darum also dieses Kapitel.

Im Unterschied zu Aktionen sind Aktivitäten nicht primär auf die Handlungsmöglichkeiten der Spielfigur orientiert, sondern an den Prozessen, die im Code vor sich gehen. Man kann durch zusätzliche Regeln zu Standard-Aktivitäten das Verhalten der I7-Welt verändern (diese Regeln plaziert man in eine der 3 Regelbücher, die für eine Aktivität angelegt werden).

interessante Standard-Aktivitäten

Es gibt für jede dieser Aktivitäten und auch für andere einen eigenen Abschnitt in der Dokumentation, der die Möglichkeiten genauer beschreibt und mit Beispielen veranschaulicht:

Regelbücher zu Aktivitäten

Pro Aktivität werden 3 Regelbücher erstellt, die (nicht so wie bei den Regelbüchern der Aktionen) immer durchlaufen werden müssen:

  • Before: Alle Regeln in diesem Regelbuch werden befolgt, bevor die Aktivität ausgeführt wird.
  • For: Die spezifischste Regel in diesem Regelbuch wird befolgt. Es reicht im Prinzip aus, dieses Regelbuch zu verwenden.
  • After: Hier werden wieder alle Regeln aus diesem Regelbuch befolgt.

Definition und Aufruf neuer Aktivitäten

Man kann sagen, dass es sehr praktisch für die Programmiererin ist, oft verwendete Abläufe einmal zu schreiben und öfter verwenden, genau so, wie das bei den Standard-Aktivitäten der Fall ist (das Paradebeispiel: Printing the name of something wird sehr oft aufgerufen). Dazu definiert man sich neue Aktivitäten, wobei man zwischen 2 Typen von Aktivitäten unterscheidet:

  • Aktivitäten, die sich auf ein bestimmmtes Ding/einen bestimmten Raum beziehen

Analysing something is an activity.

  • Aktivitäten, die sich nicht auf ein bestimmtes Ding/einen bestimmten Raum beziehen

Assaying is an activity.

Neue Aktivitäten kann man überall im Code mit "Carry out <Aktivität>" aufrufen, wobei sie erst etwas Nützliches tun, wenn Regeln definiert werden. Man kann im Rahmen einer Aktivität Variablen definieren, auf die die Regeln zugreifen können. Ein Beispiel dazu aus der Doku: Analysing something is an activity. The analysing activity has a text called first impression. Instead of examining something (called the sample), carry out the analysing activity with the sample.


Before analysing: now the first impression is "unremarkable".


Rule for analysing someone: now the first impression is "living tissue".


After analysing something (called the sample):

   say "Your professional opinion of [the sample] is that it is 
       [first impression]." 


Man kann, wenn man in speziellen Fällen nicht alle before-for-begin-Regeln durchlaufen will, eine Aktivität statt mit "carry out <activity> with <thing>" auch folgendermaßen aufrufen, um den Regel-Apparat zu unterlaufen: begin the analysing activity with the pitchblende; ... if handling the analysing activity with the pitchblende:

   ... 

... end the analysing activity with the pitchblende;


"Too many works of interactive fiction betray their mechanical nature by making it visible that the general machinery being used does not quite seem natural for this or that situation. Activities enable us to add the many graceful touches which avoid that: which contribute nothing to a work, and also everything."

Ein paar zusätzliche Hinweise

Seine Programmierstrukturen relativieren

I7 vermischt mehrere Programmierparadigmen miteinander. Man läuft Gefahr, eine Untermenge von I7-Möglichkeiten, welche man einem Paradigma zuordnen kann, überzustrapazieren, weil man von seiner Programmiererfahrung her kommend sich in diesem Paradigma mehr beheimatet fühlt. Anbei ein paar Hinweise, wo man aufpassen muss:

Regeln sind keine Funktionen: Wenn man Regeln verwendet, sollte man immer die Bedingungen ihrer Ausführung im Header mitdefinieren. Eine Ausnahme könnte sein, wenn man eine Regel in einem Regelbuch mit einer neuen Regel ersetzen will. Dann wird nämlich der Header der alten Regel verwendet.

Zwei weitere Hinweise diesbezüglich, einen über die richtige Verwendung von Rulebooks, einen anderen über das Korrekte abgrasen von Listen, kann man sich bei Gelegenheit direkt im Tutorial durchlesen.

Hacking: Einsicht und Modifikation der I7-Tiefenstrukturen

Mit I7 wird einem ja standardmäßig ein gewisses Framework (Standard-Regeln,Standard-Aktionen,Standard-Aktivitäten) mitgegeben, das man benutzen - aber auch modifizieren kann. Ein interessantes Werkzeug dafür sind Prozedurale Regeln (procedural rules); das sind Meta-Regeln, die zur Laufzeit die Regeln umstellen, außer Kraft setzen kann.

Man kann sich die Frage stellen, wenn man ein IF schreiben will, wo der Spieler zu bestimmten Zeitpunkten ein Geist ist. An dieser Stelle kommen Prozedurale Regeln zum Zug: A procedural rule when the player is a ghost: ignore the can't walk through closed doors rule. Ohne 'when'-Klausel würde die Nicht-durch-geschlossene-Türen-gehen-Regel immer ignoriert werden und das müsste man nicht zur Laufzeit machen, sondern könnte es schon fix einprogrammieren (was bezüglich Performance sinnvoller wäre), nämlich so: The can't walk through closed doors rule is not listed in any rulebook.

Man kann mit prozeduralen Regeln die Grundfesten des IF-Frameworks modifizieren. Dazu schaut man sich die folgenden Rulebooks an:

  • the action-processing rulebook
  • the specific action-processing rulebook
  • the visibility rulebook
  • the accessibility rulebook
  • the player's action awareness rulebook
  • the turn sequence rulebook

Im Tutorial werden zur Modifikation folgende prinzipiellen Möglichkeiten aufgelistet:

Zunächst jene Möglichkeiten, die man fix (man sagt: zur Compilerzeit) einprogrammieren kann:


The <rule> is not listed in any rulebook.
[...]; ignore <rule>;
[...]; reinstate <rule>; [undoes Ignore]
The <rule> is listed instead of the <second rule> in the <rulebook>;
[...]; substitute <rule> for <second rule> ;
[...]; restore the original <rule>;
The <rule> is listed before/after the <second rule> in the <rulebook>;
[...]; move <rule> to before/after <second rule> ;


Und nun Möglichkeiten, die meinem Verständnis nach zur Laufzeit geprüft werden:


[...]; reject the result of <rule>; [some rulebooks, like Instead, have a default outcome]
[...]; accept the result of <rule>; [undoes Reject]

Man sollte beide Möglichkeiten prinzipiell nur in prozeduralen Regeln verwenden.

Hacking: Ersetzen ganzer Sections

Man kann benannte Sections von bestimmten Extentions ersetzen, wenn man weiß, was man tut:

Chapter 2a (for use with Locksmith by Emily Short)
Chapter 2b (for use without Locksmith by Emily Short)
Section 6 - Hacked locking (in place of Section 1 - Regular locking in Locksmith by Emily Short)


Man kann sogar Sections aus der automatisch geladenen Extention, die die Standard Rules enthält, ersetzen:

Section 8 - My thing class (in place of Section SR1/3 - Things in the Standard Rules by Graham Nelson)


Das nur für den Fall, dass Platons Staat sich gravierend den Standard-Regeln widersetzen würde, obwohl ich mich wohl nur ungern an großflächige Ersetzungen der Standard-Regeln wagen würde.



Übrigens: Wenn man "Inform7" im deutschsprachigen Google eingibt, bekommt man einige Ergebnisse, die beim Philo-Wiki landen. --Andyk 22:17, 3. Mär. 2009 (UTC)