IF-Forum

» IF-Forum - Autorencafé - Schreiben! - Flexible Erweiterungen der name-Property
AntwortenNeues ThemaNeue Umfrage

Flexible Erweiterungen der name-Property

Geschrieben um 20:06 am 10.04.2006 | Zitat | Editieren | Löschen
ChristianB
Mitglied
Retired Gumby
Beiträge: 1062

Hallo, Inform-/deform-Spezialisten, ich habe zwei Objekte und ein Problem:



  with  name 'zaun' 'bauzaun' 'absperrung' 'f.'

             'brett' 'n.' 'bretter' 'p.',

        changing_gender,

   has  male transparent scenery;

   

Object -> -> hole "Loch im Zaun"

  with  name 'loch' 'guckloch' 'oeffnung' 'f.',

        changing_gender,

   has  neuter scenery;```

Ich möchte gern, dass man das Loch im Zaun auch mit LOCH IM [IN DEM] ZAUN, OEFFNUNG IM [IN DEM] BAUZAUN (also mit allen möglichen Synonymen) ansprechen kann und trotzdem der changing_gender noch funktioniert. Ich habe schon versucht, mit parse_name etwas in der Richtung zu machen, hab’s aber nicht so flexibel hinbekommen.

Gibt es eine einfache Möglichkeit, so etwas zu programmieren, wenn ja: wie macht man das? Ich habe gesehen, dass Martin etwas Ähnliches beim Plan fürs Deformuseum realisiert hat, aber ganz verstanden habe ich die Methode (noch) nicht.

Danke und Grüße,

CB
Geschrieben um 00:07 am 11.04.2006 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

Hmmm. Ich hatte ja gedacht, das ginge so:


Object -> -> hole "Loch im Zaun"

  with  name 'loch' 'guckloch' 'oeffnung' 'f.',

        parse_name [ n wd wstart;

            wstart = wn;

            ! Normales Vokabular überprüfen

            wd = NextWord();

            while (WordInProperty(wd, self, name)) {

                wd = NextWord();

                n++;

            }

            if (n == 0) return 0;

            if (wd == 'in') {

                ! Artikel und so überlesen

                Descriptors();

                ! Dann prüfen, ob danach eine Wortfolge kommt, die

                ! auf den Zaun passt.

                if (NounDomain(location, actor, NOUN_TOKEN) == fence)

                    return wn - wstart;

            }

            return n;

        ],

        changing_gender,

   has  neuter scenery;

Die parse_name des Lochs überprüft zunächst das Vokabular des Lochs selbst. Wenn das nächste Wort 'in' ist, wird das Vokabular des Bauzauns überprüft. Clever!, dachte ich. War es aber wohl nicht, denn beim Aufrufen einer Token-Parse-Routine aus einer anderen wird wohl einiges kaputtgeschrieben. So kommt es ab und an zu den Inference-Meldungen in Klammern, obwohl doch eigentlich alles klar ist. Außerdem wird der changing gender nicht richtig erkannt.

Dabei wäre das doch echt schön gewesen: Man hätte sogar dem Bauzaun eine parse_name verpassen können, und trotzdem hätte es funktioniert.

Also, nächster Versuch:


Object -> -> hole "Loch im Zaun"

  with  name 'loch' 'guckloch' 'oeffnung' 'f.',

        parse_name [ n m wd wstart;

            wstart = wn;

            ! Normales Vokabular überprüfen

            wd = NextWord();

            while (WordInProperty(wd, self, name)) {

                wd = NextWord();

                n++;

            }

            if (n == 0) return 0;

            if (wd == 'in') {

                ! Artikel und so überlesen

                Descriptors();

                ! Vokabular des Zauns überprüfen

                wd = NextWord();

                while (WordInProperty(wd, fence, name)) {

                    wd = NextWord();

                    m++;

                }

                if (m) return wn - wstart; ! (Loch + Zaun + 'in')

            }

            return n;

        ],

        changing_gender,

   has  neuter scenery;

Hier wird einfach in einer zweiten Schleife das Vokabular des zauns geprüft. Etwas umständlich vielleicht, aber es klappt. Eine parse_name des Zauns ist nun nicht mehr drin. Außerdem muss ich die Descriptors() von Hand parsen, denn es heißt ja eigentlich 'in dem zaun', wie du schon festgestellt hast. (Daran hätte ich gewiss erst einmal gesucht, wenn du es nicht schon erwähnt hättest - so Sachen übersehe ich gerne.)

Der changing_gender wird übrigens in WordInProperty gesetzt - allerdings immer nur für das Objekt, dessen Vokabeln geprüft werden. Das heißt in der zweiten Schleife wird nur der changing_gender vom Zaun gesetzt, und der des Lochs bzw. der Öffnung bleibt bestehen.

ChristianB:

Ich habe gesehen, dass Martin etwas Ähnliches beim Plan fürs Deformuseum realisiert hat, aber ganz verstanden habe ich die Methode (noch) nicht.

Dort habe ich mit der parse_name nur festgestellt, ob die Vorder- , die Rückseite oder der Hinweis angesprochen wurde. Die komischen Bedingungen à la


    while (WordInProperty(wd, self, name)

       || ((flag = true) == 0)

       || WordInProperty(wd, self, back_name)) { ... }

sind nur enstanden, weil ich etwas faul war: Wenn das Wort in name ist, ist die Bedingung, die aus verketteten Oder-Verknüpfungen besteht, bereits erfüllt: Da nur ein Glied der Kette wahr sein muss, werden die anderen nicht mehr geprüft. Danach kommt eine Bedingung, die immer falsch ist und damit der Auswertung des letzten Glieds erzwingt. Diese Bedingung, die zweite meine ich, hat jedoch einen Nebeneffekt: Die Flagge flag wird auf true gesetzt.

Auf diese weise spare ich mir verschachtelte if-else-Abfragen oder das Belegen einer Flagge. Das klappt aber nur, weil die Flagge flag temporär ist, denn sie wird ja auch auf true gesetzt, wenn alle WordInProperty()s fehlschlagen.

Man hätte den Code (vielleicht - nicht getestet) auch so schreiben können:


    parse_name [n wd vorder rueck;

        self.back_flag = false;

        wd = NextWord();

        while (vorder = WordInProperty(wd, self, name)

            || rueck = WordInProperty(wd, self, back_name)) {

            self.back_flag = rueck;

            n++; wd = NextWord();

        }

        return n;

    ],

Sobald nur einmal ein Wort des Rückseitenvokabulars angegeben wurde, bleibt die back_flag gesetzt. Wenn danach Vorderseitenvokabular benutzt wird, wird die zweite Zuweisung in der Oder-Veknüpfung nicht ausgeführt, rueck behält seinen Wert.

Geschrieben um 17:22 am 11.04.2006 | Zitat | Editieren | Löschen
ChristianB
Mitglied
Retired Gumby
Beiträge: 1062

Heidewitzka, Herr Kapitän! Deine zweite Lösung ist genau das, was ich gesucht habe, danke dafür. Die erste Variante hat aber auch Unterhaltungswert, zumindest im Kontext meines Codes; der Parser hat allerlei lustige Fragen gestellt.

Tja, und jetzt weiß ich auch, dass ich in Sachen Deformuseums-Plan keinen Plan hatte. Wieder viel gelernt.

Danke nochmal und viele Grüße,

CB

Geschrieben um 12:52 am 13.04.2006 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

ChristianB:

Die erste Variante hat aber auch Unterhaltungswert, zumindest im Kontext meines Codes; der Parser hat allerlei lustige Fragen gestellt.

Tja, die ganzen Parserroutinen machen halt nicht immer nur das, was sie sollen, sondern oft noch mehr. Es werden Flaggen abgelegt, ob und welche Descriptors für welches Token passen, ein Hilfsfeld wird mit möglichen Treffern vollgeschrieben. Daher ist es wohl keine gute Idee, diese Routinen aus einer parse_name herau aufzurufen.

Ich haben den Code für Phrasen nach dem Schema "Objekt, Präposition, Objekt" erweitert, so dass man nun auch Objekte mit parse_name als zweites Objekt aufrufen kann. Der Code akzeptiert bis zu drei alternative Präpositionen:


    ! Normales Vokabular überprüfen

    wd = NextWord();

    while (WordInProperty(wd, obj, name)) {

        wd = NextWord();

        n++;

    }

    ! Kein Treffer, wenn das erste Objekt nicht genannt wird

    if (n == 0) return 0;

    ! Optionales Attribut parsen

    if (wd == prep1 or prep2 or prep3) {

        ! Artikel und so überlesen

        desc = wn;

        Descriptors();

        desc = wn - desc;

       

        if (obj2 provides parse_name) {

            ! Wenn obj2 eine parse_name-Routine hat, aufrufen und prüfen

            m = obj2.parse_name();

            if (m == 0) return n;

            if (m > 0) return n + 1 + desc + m;

            m = 0;

        }

        ! Vokabular des Zauns überprüfen

        while (Refers(obj2, wn + m)) m++;

        if (m) return n + 1 + desc + m;

    }

    return n;

];

Nun kann man lustige Verschachtelungen machen (was aber auch heißt, dass man prima Endlosschleifen bauen kann):


Object -> fence "Bauzaun@03"

  with  name 'zaun' 'bauzaun' 'absperrung' 'f.'

             'brett' 'n.' 'bretter' 'p.',

        parse_name [;

            return ParseAttributeClause(self, const_site, 'um', 'neben', 'fuer');

        ],

        changing_gender,

   has  male transparent scenery;

Object -> fence2 "Gartenzaun@03"

  with  name 'zaun' 'gartenzaun' 'absperrung' 'f.'

             'brett' 'n.' 'bretter' 'p.',

        parse_name [;

            return ParseAttributeClause(self, garden, 'um', 'neben', 'fuer');

        ],

        changing_gender,

   has  male transparent scenery;

Object -> -> hole "Loch im Bauzaun"

  with  name 'loch' 'guckloch' 'oeffnung' 'f.',

        parse_name [;

            return ParseAttributeClause(self, fence, 'in');

        ],

        changing_gender,

   has  neuter scenery;

Object -> -> hole2 "Loch im Gartenzaun"

  with  name 'loch' 'guckloch' 'oeffnung' 'f.',

        parse_name [;

            return ParseAttributeClause(self, fence2, 'in');

        ],

        changing_gender,

   has  neuter scenery;

Das erkennt Sachen wie:


>u loch

Was meinst du, das Loch im Bauzaun oder das Loch im Gartenzaun?

>u loch im gartenzaun

Du siehst nichts Besonderes an dem Loch im Gartenzaun.

>u loch im zaun um die baustelle

Du siehst nichts Besonderes an dem Loch im Bauzaun.

Aber:


Was meinst du, den Bauzaun oder den Gartenzaun?

>zaun um den garten

Ich habe nur Folgendes verstanden: den Gartenzaun betrachten.

(Hier heißt die zu parsende Phrase "zaun um den garten zaun", das klappt noch nicht. Naja.)

Geschrieben um 01:32 am 15.04.2006 | Zitat | Editieren | Löschen
ChristianB
Mitglied
Retired Gumby
Beiträge: 1062

Klasse, Martin! Mit ParseAttributeClause hast du ja ein leckeres Fass aufgemacht. Wenn die Routine am Ende mal so funktionieren könnte, dass der Parser alles schluckt und versteht, dann wäre das sicher eine große Erweiterung der bisherigen Möglichkeiten – zumindest ich würde es als echten Luxus empfinden.

Und doch schwindelt’s mir angesichts der Fülle von Kombinationen, die sich aus einem solchen Konstrukt ergeben. Wie soll eine Disambiguisierung da funktionieren, zumal verschachtelt?



[Echo: "u loch in dem zaun"]

Was meinst du, das Loch im Bauzaun oder das Loch im Gartenzaun?

>loch im zaun```

Ein fieser Spieler, der so etwas versucht! Denn das führt in die Endlosschleife (zumindest macht der Interpreter nicht weiter). Aber das hattest du ja schon prognostiziert.

Nach U LOCH lautet die große Frage doch: Welches Loch in welchem Zaun meinst du? Und das ginge theoretisch unendlich weiter: Welches Loch in welchem Zaun um welches Beet auf welcher Seite des Klostergartens etc… Eieiei.

Spannend, das Thema, finde ich. Sehr spannend. Aber leider kann ich nur zuschauen und nichts Sinnvolles an Programmierung in dieser Hinsicht beitragen. Der Parser ist eben nur ein flüchtiger Bekannter von mir. Ich habe ihm gerade schon mal eine kleine Buchstabensuppe geköchelt, aber die hat er gar nicht gut vertragen. Hmm.
Geschrieben um 15:10 am 18.04.2006 | Zitat | Editieren | Löschen
ChristianB
Mitglied
Retired Gumby
Beiträge: 1062

Ich hab gerade mal mein Spiel durchgeschaut... ParseAttributeClause kommt jetzt einige Male (auf weniger mehrdeutigen Baustellen, als im Beispiel) zum Einsatz. Sehr hübsch, wie ich finde.

Geschrieben um 10:48 am 19.04.2006 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

ChristianB:

Ein fieser Spieler, der so etwas versucht!

Oje! Das ist echt der Super-GAU: Der Parser hängt den Interpreter komplett auf.

Hier muss gewiss eine zusätzliche Abfrage hinein, ob gerade die Antwort auf eine Frage des Parsers untersucht wird. (Gewiss kann man das feststellen, ich vermute allerdings, dass diese Information in einer ganz und gar nicht offensichtlichen Variable abgelegt ist.)

Die Abfrage müsste nicht nur den tödlichen Bug umgehen, sondern auch zusätzliche Dinge parsen, um die Antorten auf die Parserfragen verstehen zu können. Diese Antwort wird ja vor die Originalangabe geschrieben, so dass die Parse-Routine nicht mehr funktioniert. Außerdem könnten Antworten auf "Welches Loch?" ja so lauten: "Das im Bauzaun".

ChristianB:

Nach U LOCH lautet die große Frage doch: Welches Loch in welchem Zaun meinst du? Und das ginge theoretisch unendlich weiter: Welches Loch in welchem Zaun um welches Beet auf welcher Seite des Klostergartens etc? Eieiei.

Das kann man ja noch beliebig weiterspinnen. Eigentlich sind die Objekte ja eindeutig zugeordnet:

Zitat:

Auf dem Tisch siehst du eine große Schale. In der großen Schale ist etwas Obst (ein Apfel und zwei Orangen).

Auf einer Anrichte steht eine kleine Schale. In der kleinen Schale ist etwas Öl.

Jetzt müsste man doch eigentlich sagen können "die Schale mit dem Obst" oder "die Schale auf der Anrichte". Da man die Schalen woanders hinstellen kann und Dinge hineinlegen und herausnehmen kann, ändern sich natürlich die Phrasen, mit denen man sie ansprechen kann. Die Information, was der Parser erkennen soll, ist aber immer da. (Die Schale ist ein Behälter, also soll sie 'mit' und eine Angabe zu ihren Kindern verstehen. Sie steht auch auf einer Ablage, also soll 'auf' und eine Angabe zur Ablage verstanden werden. Allerdings bleibt eine 'Obstschale' auch eine 'Obstschale', wenn kein Obst mehr darin ist.)

Trotzdem wird man die Schalen auch 'klein' und 'groß' nennen können, damit man sie unterscheiden kann, wenn sie leer oder am selben Ort sind. Die Angabe des Orts oder des Inhalts ist nur, wie du schon sagtest, Luxus. Ich muss mir nicht merken, dass das rote feine Pulver in der milchigen Phiole, das gelbe grobe Pulver in der schwarzen Phiole und das Granulat in der grünen Phiole ist, sondern sage einfach "nimm die Phiole mit dem Granulat". (In so einem Spiel würde man aber wohl eh sagen "nimm alles" :-)

Ist das alles der Parser-Overkill? Vielleicht. Außerdem tauchen ja auch einige Probleme auf. Wie soll zum Beispiel eine Fehlermeldung lauten, wenn der Spieler "das Buch auf dem Küchentisch" sagt, Buch und Tisch zu sehen sind, aber das Buch nicht auf dem Tisch liegt? Es müsste wohl "Auf dem Tisch siehst du so etwas nicht" (oder "kein Buch") lauten, um den Spieler nicht mit der (sehr schwachen) Fehlermeldung "Du kannst so etwas hier nicht sehen" irre zu führen.

Wenn der Parser allerdings alle möglichen Objekte nach einer Präposition verstehen soll, wird es schwierig, Sätze wie "stelle Schüssel auf Tisch" oder gar "stelle die Schüssel auf der Anrichte auf den Tisch mit der Vase" zu parsen.

Sicherlich ein interessantes Thema. Aber nicht leicht zu realisieren. Und wenn es schon an kleinen Dingen scheitert und es Endlosschleifen gibt...

Geschrieben um 17:20 am 19.04.2006 | Zitat | Editieren | Löschen
ChristianB
Mitglied
Retired Gumby
Beiträge: 1062

Ja, das Ganze führt wohl zu weit. Um eine kohärente Geschichte zu erzählen muss der Spieler eigentlich nicht

> NIMM DAS JUWEL AUS DEM KOSOVO AUS DEM KLEINEN LOCH IM KÄSE VON DER BESCHAULICHEN ALM AUF DEM HÖCHSTEN BERG IM HOFFENTLICH IMMER NOCH NEUTRALEN TERRITORIUM DER SCHWEIZER EIDGENOSSEN

sagen können. Wie schön, dass wir immer noch über textbasierte Abenteuergeschichten reden. Welcher Spieler würde es tolerieren, solche Monsterphrasen eingeben zu müssen, um ein einzelnes Objekt zu identifizieren, auch wenn es toll wäre, wenn das ginge?

Aaaaber: Ich bin froh, dass mit ParseAttributeClause (behutsam und sinnvoll eingesetzt) jetzt das Loch im Käse vom [von dem] Loch im Kopf und dem Loch in der Socke unterschieden wird und ich auf so unschöne Synonyme wie „Käseloch“, „Kopfloch“, oder gar „Sockenloch“ verzichten kann. (Ich bin gar nicht so lochfixiert, das waren alles nur Beispiele!)

Flexibler als die im DM4 beschriebene Fliege im Bernstein (DM4, p. 209) ist es allemal.

Insofern konnte dem Mann geholfen werden, vielen Dank noch einmal.

Geschrieben um 17:39 am 19.04.2006 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

ChristianB:

Welcher Spieler würde es tolerieren, solche Monsterphrasen eingeben zu müssen, um ein einzelnes Objekt zu identifizieren, auch wenn es toll wäre, wenn das ginge?

He, he. Vor allem, wenn dadurch das Verhältnis von Eingabe zu Ausgabe stark ins Ungleichgewicht kommt:

Zitat:

nimm den Diamanten aus dem Kronschatz des Königs von Schweden von dem niedrigen Tisch aus gebeiztem Fichtenholz

In Ordnung.

Solche Monsterphrasen wird wohl niemand eingeben, aber es ist schön, wenn man zumindest zum Disambiguisieren solche Konstrukte verwenden kann. Für Genitive ("den Pass des Botschafters") kann ich mir so etwas auch vorstellen.

AntwortenNeues ThemaNeue Umfrage
Powered by Spam Board SVN © 2007 - 2021
Impressum / Datenschutz