| Geschrieben um 20:06 am 10.04.2006 | Zitat | Editieren | Löschen | |
Mitglied Prof Gumby Beiträge: 569 | <td valign="top"><div class="post"><p>Hallo, Inform-/deform-Spezialisten, ich habe zwei Objekte und ein Problem:</p> <p>“`Object -> fence “Bauzaun”</p> <p> with name ‘zaun’ ‘bauzaun’ ‘absperrung’ ‘f.’</p> <p> ‘brett’ ‘n.’ ‘bretter’ ‘p.’,</p> <p> changing_gender,</p> <p> has male transparent scenery;</p> <p> </p> <p>Object -> -> hole “Loch im Zaun”</p> <p> with name ‘loch’ ‘guckloch’ ‘oeffnung’ ‘f.’,</p> <p> changing_gender,</p> <p> has neuter scenery;“`</p> <p>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<em>gender noch funktioniert. Ich habe schon versucht, mit parse</em>name etwas in der Richtung zu machen, habs aber nicht so flexibel hinbekommen.</p> <p>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.</p> <p>Danke und Grüße,</p> <p>CB</p> </div></td> |
| Geschrieben um 00:07 am 11.04.2006 | Zitat | Editieren | Löschen | |
Mitglied Retired Gumby Beiträge: 707 | <td valign="top"><div class="post"><p>Hmmm. Ich hatte ja gedacht, das ginge so:</p> <p>“`</p> <p>Object -> -> hole “Loch im Zaun”</p> <p> with name ‘loch’ ‘guckloch’ ‘oeffnung’ ‘f.’,</p> <p> parse_name [ n wd wstart;</p> <p> wstart = wn;</p> <p> ! Normales Vokabular überprüfen</p> <p> wd = NextWord();</p> <p> while (WordInProperty(wd, self, name)) {</p> <p> wd = NextWord();</p> <p> n++;</p> <p> }</p> <p> if (n == 0) return 0;</p> <p> if (wd == ‘in’) {</p> <p> ! Artikel und so überlesen</p> <p> Descriptors();</p> <p> ! Dann prüfen, ob danach eine Wortfolge kommt, die</p> <p> ! auf den Zaun passt.</p> <p> if (NounDomain(location, actor, NOUN_TOKEN) == fence)</p> <p> return wn - wstart;</p> <p> }</p> <p> return n;</p> <p> ],</p> <p> changing_gender,</p> <p> has neuter scenery;</p> <p>“`</p> <p>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.</p> <p>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.</p> <p>Also, nächster Versuch:</p> <p>“`</p> <p>Object -> -> hole “Loch im Zaun”</p> <p> with name ‘loch’ ‘guckloch’ ‘oeffnung’ ‘f.’,</p> <p> parse_name [ n m wd wstart;</p> <p> wstart = wn;</p> <p> ! Normales Vokabular überprüfen</p> <p> wd = NextWord();</p> <p> while (WordInProperty(wd, self, name)) {</p> <p> wd = NextWord();</p> <p> n++;</p> <p> }</p> <p> if (n == 0) return 0;</p> <p> if (wd == ‘in’) {</p> <p> ! Artikel und so überlesen</p> <p> Descriptors();</p> <p> ! Vokabular des Zauns überprüfen</p> <p> wd = NextWord();</p> <p> while (WordInProperty(wd, fence, name)) {</p> <p> wd = NextWord();</p> <p> m++;</p> <p> }</p> <p> if (m) return wn - wstart; ! (Loch + Zaun + ‘in’)</p> <p> }</p> <p> return n;</p> <p> ],</p> <p> changing_gender,</p> <p> has neuter scenery;</p> <p>“`</p> <p>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.)</p> <p>Der changing<em>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</em>gender vom Zaun gesetzt, und der des Lochs bzw. der Öffnung bleibt bestehen.</p> <p><strong>ChristianB:</strong></p> <blockquote> <p>Ich habe gesehen, dass Martin etwas Ähnliches beim Plan fürs Deformuseum realisiert hat, aber ganz verstanden habe ich die Methode (noch) nicht. </p> </blockquote> <p>Dort habe ich mit der parse_name nur festgestellt, ob die Vorder- , die Rückseite oder der Hinweis angesprochen wurde. Die komischen Bedingungen à la</p> <p>“`</p> <p> while (WordInProperty(wd, self, name)</p> <p> || ((flag = true) == 0)</p> <p> || WordInProperty(wd, self, back_name)) { … }</p> <p>“`</p> <p>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.</p> <p>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.</p> <p>Man hätte den Code (vielleicht - nicht getestet) auch so schreiben können:</p> <p>“`</p> <p> parse_name [n wd vorder rueck;</p> <p> self.back_flag = false;</p> <p> wd = NextWord();</p> <p> while (vorder = WordInProperty(wd, self, name)</p> <p> || rueck = WordInProperty(wd, self, back_name)) {</p> <p> self.back_flag = rueck;</p> <p> n++; wd = NextWord();</p> <p> }</p> <p> return n;</p> <p> ],</p> <p>“`</p> <p>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.</p> </div></td> |
| Geschrieben um 17:22 am 11.04.2006 | Zitat | Editieren | Löschen | |
Mitglied Prof Gumby Beiträge: 569 | 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 | |
Mitglied Retired Gumby Beiträge: 707 | <td valign="top"><div class="post"><p><strong>ChristianB:</strong></p> <blockquote> <p>Die erste Variante hat aber auch Unterhaltungswert, zumindest im Kontext meines Codes; der Parser hat allerlei lustige Fragen gestellt.</p> </blockquote> <p>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.</p> <p>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:</p> <p>“`[ ParseAttributeClause obj obj2 prep1 prep2 prep3 n m wd desc;</p> <p> ! Normales Vokabular überprüfen</p> <p> wd = NextWord();</p> <p> while (WordInProperty(wd, obj, name)) {</p> <p> wd = NextWord();</p> <p> n++;</p> <p> }</p> <p> ! Kein Treffer, wenn das erste Objekt nicht genannt wird</p> <p> if (n == 0) return 0;</p> <p> ! Optionales Attribut parsen</p> <p> if (wd == prep1 or prep2 or prep3) {</p> <p> ! Artikel und so überlesen</p> <p> desc = wn;</p> <p> Descriptors();</p> <p> desc = wn - desc;</p> <p> </p> <p> if (obj2 provides parse_name) {</p> <p> ! Wenn obj2 eine parse_name-Routine hat, aufrufen und prüfen</p> <p> m = obj2.parse_name();</p> <p> if (m == 0) return n;</p> <p> if (m > 0) return n + 1 + desc + m;</p> <p> m = 0;</p> <p> }</p> <p> ! Vokabular des Zauns überprüfen</p> <p> while (Refers(obj2, wn + m)) m++;</p> <p> if (m) return n + 1 + desc + m;</p> <p> }</p> <p> return n;</p> <p>];</p> <p>“`</p> <p>Nun kann man lustige Verschachtelungen machen (was aber auch heißt, dass man prima Endlosschleifen bauen kann):</p> <p>“`</p> <p>Object -> fence “Bauzaun@03”</p> <p> with name ‘zaun’ ‘bauzaun’ ‘absperrung’ ‘f.’</p> <p> ‘brett’ ‘n.’ ‘bretter’ ‘p.’,</p> <p> parse_name [;</p> <p> return ParseAttributeClause(self, const_site, ‘um’, ‘neben’, ‘fuer’);</p> <p> ],</p> <p> changing_gender,</p> <p> has male transparent scenery;</p> <p>Object -> fence2 “Gartenzaun@03”</p> <p> with name ‘zaun’ ‘gartenzaun’ ‘absperrung’ ‘f.’</p> <p> ‘brett’ ‘n.’ ‘bretter’ ‘p.’,</p> <p> parse_name [;</p> <p> return ParseAttributeClause(self, garden, ‘um’, ‘neben’, ‘fuer’);</p> <p> ],</p> <p> changing_gender,</p> <p> has male transparent scenery;</p> <p>Object -> -> hole “Loch im Bauzaun”</p> <p> with name ‘loch’ ‘guckloch’ ‘oeffnung’ ‘f.’,</p> <p> parse_name [;</p> <p> return ParseAttributeClause(self, fence, ‘in’);</p> <p> ],</p> <p> changing_gender,</p> <p> has neuter scenery;</p> <p>Object -> -> hole2 “Loch im Gartenzaun”</p> <p> with name ‘loch’ ‘guckloch’ ‘oeffnung’ ‘f.’,</p> <p> parse_name [;</p> <p> return ParseAttributeClause(self, fence2, ‘in’);</p> <p> ],</p> <p> changing_gender,</p> <p> has neuter scenery;</p> <p>“`</p> <p>Das erkennt Sachen wie:</p> <p>“`</p> <blockquote> <p>u loch</p> </blockquote> <p>Was meinst du, das Loch im Bauzaun oder das Loch im Gartenzaun?</p> <blockquote> <p>u loch im gartenzaun</p> </blockquote> <p>Du siehst nichts Besonderes an dem Loch im Gartenzaun.</p> <blockquote> <p>u loch im zaun um die baustelle</p> </blockquote> <p>Du siehst nichts Besonderes an dem Loch im Bauzaun.</p> <p>“`</p> <p>Aber:</p> <p>“`>u zaun</p> <p>Was meinst du, den Bauzaun oder den Gartenzaun?</p> <blockquote> <p>zaun um den garten</p> </blockquote> <p>Ich habe nur Folgendes verstanden: den Gartenzaun betrachten.</p> <p>“`</p> <p>(Hier heißt die zu parsende Phrase “zaun um den garten zaun”, das klappt noch nicht. Naja.)</p> </div></td> |
| Geschrieben um 01:32 am 15.04.2006 | Zitat | Editieren | Löschen | |
Mitglied Prof Gumby Beiträge: 569 | 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 schwindelts mir angesichts der Fülle von Kombinationen, die sich aus einem solchen Konstrukt ergeben. Wie soll eine Disambiguisierung da funktionieren, zumal verschachtelt? “`>u loch im zaun [Echo: “u loch in dem zaun”] Was meinst du, das Loch im Bauzaun oder das Loch im Gartenzaun?
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 | |
Mitglied Prof Gumby Beiträge: 569 | 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 | |
Mitglied Retired Gumby Beiträge: 707 | ChristianB:
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:
Das kann man ja noch beliebig weiterspinnen. Eigentlich sind die Objekte ja eindeutig zugeordnet: Zitat:
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 | |
Mitglied Prof Gumby Beiträge: 569 | Ja, das Ganze führt wohl zu weit. Um eine kohärente Geschichte zu erzählen muss der Spieler eigentlich nicht
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 | |
Mitglied Retired Gumby Beiträge: 707 | ChristianB:
He, he. Vor allem, wenn dadurch das Verhältnis von Eingabe zu Ausgabe stark ins Ungleichgewicht kommt: Zitat:
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. |