IF-Forum

» IF-Forum - Autorencafé - Schreiben! - Speichern von Spielereingaben
AntwortenNeues ThemaNeue Umfrage

Speichern von Spielereingaben

Geschrieben um 19:35 am 11.07.2004 | Zitat | Editieren | Löschen
Clive
Mitglied
Bachelor Gumby
Beiträge: 60

Hi!

Ich stelle mal meine Frage wieder kurz und schmerzlos:

Wie kann man Inform dazu bringen, das Ergebnis von read buffer parse (also das, was der Spieler dann eingibt) in einer Variable zu speichern?

Oder geh ich die Sache völlig falsch an?

Bin natürlich wie immer über jede Hilfe dankbar!

Geschrieben um 20:33 am 11.07.2004 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

Zitat:

Oder geh ich die Sache völlig falsch an?

Kann sein, ich weiß jedoch nicht genau, was du willst.

Mit der Anweisung read buffer parse erhältst du das "Ergebnis", also den Wortlaut der Eingabe ja, und zwar im Byte-Feld buffer im in Abschnitt 2.5 im DM4 angegebenen Format: Das erste Byte (buffer->0) gibt die Maximal einzulesenden Zeichen an, es sollte also vor dem Aufruf von read auf einen passenden Wert gesetzt werden. Das zweite Byte, buffer->1, enthält die Anzahl der tatsächlich eingegebenen Zeichen. Ab buffer->2 stehen dann diese Zeichen im ZSCII-Format, sie können mit der Druckregel (char) ausgegeben werden:


[Buffer_ausgeben i;

  for (i=0: i < buffer->1: i++)

    print (char) buffer->(i+2);

];

Die Eingabe von read wird immer in Kleinbuchstaben konvertiert, so dass Annahmen über Großschreibung (erster Buchstabe oder vorhergehendes Zeichen ein Leerschritt) in diesen Code eingebaut werden müssten.

In der Form read buffer parse macht die Anweisung read noch etwas: Sie teilt die Eingabe in Wörter auf und versucht diese Wörter im internen Wörterbuch zu finden und legt diese Information auf dem Feld parse ab, wieder in einem etwas ungewöhnlichen Format, das in §2.5 beschrieben wird. Siehe hierzu das Beispiel am Ende des Abschnitts, bei dem nur die Wörter 'mary', 'had', 'a', 'little' und 'lamb' verstanden werden und das eine Kurzanalyse der Spielereingabe durchführt. (Die rudimentäre Satzanalyse wird weggelassen, wenn der zweite parameter von read null ist.)

Das Ergebnis in einer Variable abzulegen, geht nicht. Folgendes


Global Buffer_des_Todes

[Sprich_und_stirb;

    read Buffer_des_Todes 0;

    print "Du hast folgendes geschrieben: ",

      (string) Buffer_des_Todes, "!^^";

];

bitte nicht ausprobieren! Strings in Inform sind nicht wie Strings in anderen Programmiersprachen, weswegen es auch recht kompliziert ist, Teilstrings zu extrahieren, den ersten Buchstaben groß zu schreiben, usw.

Schlimmer noch, Inform kennt zwei String-Konzepte, die beide String heißen. Die am häufigsten vorkommende Variante des Strings sind Texte in Gänsefüßchen, zum Beispiel:


    print "Zwei Boxkämpfer jagen Eva quer durch Sylt.";

    Reiseziel = "Guatemala";

    Ungeziefer.short_name = "Kellerasseln";

All diese Texte gehören zur Metaklasse String, die Variablen enthalten eine packed address, eine Adresse im Hochspeicher des z-Codes. An dieser Adresse wird der String in komprimierter Form abgelegt, man kann auf diesen String in der Regel nur auf eine Art zugreifen: Mit der Druckregel (string). Wenn eine message an eine Objekteigenschaft gesandt wird, die einen String enthält, kann Inform die Metaklasse herausfinden und wandelt dann diese message in ein print (string) um.

(Der Hochspeicher ist der einzige Teil des z-Codes, der 64k überschreiten kann. Damit man auf diese Adressen mit 16-Bit-Zahlen zugreifen kann, ist die packed address nicht die tatsächliche Adresse, sie muss mit vier multipliziert werden, um die tatsächliche Adresse zu erhalten. Die Adressierung von Routinen funktioniert genauso, eine z5-Datei kann bis zu 256k = 4*64k groß werden, alles, was über der 64k-Marke liegt sind Routinen und Strings.)

Da der String erstens komprimiert, also codiert, ist und zweitens außerhalb des direkt zugreifbaren Speichers liegt, kann man etwas wie das folgende nicht machen:


   Ungeziefer.short_name[0] = 'T';

Die Strings in doppelten Anführungszeichen sind statisch! (Ausnahme siehe unten...)

Die zweite Art von Strings, die nur in besonderen Fällen gebraucht wird, ist ein Byte-Feld, das eine Folge von Zeichen im ZSCII-Format enthält. Wie genau die Länge dieses Strings bezeichnet wird, muss der Autor selbst festlegen, es gibt mehrere Möglichkeiten, einen String mit n Zeichen im String str abzulegen:

  • Nullterminierte Strings: str->0 bis str->(n-1) enthalten die Zeichen. Als Endmarker wird in str->n eine Null geschrieben. Dies wird in Inform nicht verwendet, C und Java organisieren ihre Strings so.
  • Ein vorangehendes Länge-Bit: str->0 enthält die Länge n, die Einträge str->1 bis str->n enthalten die Zeichen. Felder, die in Inform mit "Array string" definiert werden, haben dieses Format, Strings in Pascal funktionieren ebenso. Diese Strings sind natürlich auf 255 Zeichen beschränkt.
  • Ein vorhergehendes Länge-Wort: str-->0 (Doppelpfeil!) enthält die Länge n, die größer als 255 sein kann. Die Einträge str->2 bis str->(n+1) enthalten die Zeichen. Dies ist das Format von buffer (wenn man nach dem Lesen str->0 = 0 setzt), das auch bei anderen Gelegenheiten von der z-Maschine verwendet wird, siehe unten. Ich glaube, das neue Inform 6.3 verfügt über die Direktive "Array buffer", um Felder in diesem Format zu erzeugen, bin mir aber nicht sicher.

Ich habe oben gesagt, dass Strings in doppelten Anführungszeichen statisch sind. Und ich habe gesagt, dass es eine Ausnahme gibt: Arrays, die bei ihrer Definition nur einen Eintrag, nämlich einen String in Gänsefüßchen, haben, werden als String-Arrays mit den passenden Zeichen als Inhalt definiert. Folgende Definitionen sind gleichwertig:


Array a string "Hans";

Array b string 4                   ! Länge

               'H' 'a' 'n' 's';    !Inhalt

Ich habe auch gesagt, dass man statische Strings nicht manipulieren kann. Stimmt. Mann kann sie aber in ein Hilfsfeld ausgeben lassen, und sie dann manipulieren:


Array aux string 240;

[ Chinatown x i c;

    @output_stream 3 aux;

    print "Drei Chinesen mit dem Kontrabass...";

    @output_stream -3;

    for (i=0: i < aux-->0: i++) {

      c = aux->(i+2);

      if (c == 'a' or 'e' or 'i' or 'o' or 'u')

        print (char) x; else print (char) c;

    }

];

Kompliziert? Ja und Nein. Man muss nur wissen, wann man es mit welchem String zu tun hat. Wenn (metaclass(x)==String), dann kann man ihn mit (string) x ausgeben. Bei Eingaben, die natürlich dynamisch und Zeichen für Zeichen abrufbar sein müssen, muss man die Texte auf Feldern ablegen. Die interne Verwendung des Bezeichners "String" und die von verschiedenen Opcodes produzierten Formate für Feldinhalte tragen allerdings zur Verwirrung bei.

Geschrieben um 00:16 am 12.07.2004 | Zitat | Editieren | Löschen
Clive
Mitglied
Bachelor Gumby
Beiträge: 60

Ah, danke!


Array aux string 240;

[ Chinatown x i c;

    @output_stream 3 aux;

    print "Drei Chinesen mit dem Kontrabass...";

    @output_stream -3;

    for (i=0: i < aux-->0: i++) {

      c = aux->(i+2);

      if (c == 'a' or 'e' or 'i' or 'o' or 'u')

        print (char) x; else print (char) c;

    }

];

Das war glaub ich im Wesentlichen das, was ich gesucht habe. Wenn ich das richtig verstehe, kann man die Variable c im oberen Beispiel, falls sie als Global deklariert wird, auch im übrigen Spiel verwenden, oder?

Praktisch so:


Array aux string 240;

Global c = 0;

[ FrageRoutine i;

    aux->0 = 237;

    read aux 0;

    for (i=0: i < aux->1: i++) {

      c = aux->(i+2);

    }

];

[ Main;

    print "^Gib deinen Namen ein:";

    FrageRoutine();

    print "^^Du hast als deinen Namen ", (char) c, " eingegeben.^^";

];

Unschön? Der Spielername würde immer klein ausgegeben, aber das ist erstmal auch unwichtig.

Das nächste Fragezeichen ist sicher nicht weit entfernt, aber herzlichen Dank für solch eine ausführliche Antwort!

EDIT: Das funktioniert natürlich nicht, was ich jetzt auch gemerkt habe, weil c ja in einer Schleife steht und am Ende nur den Wert des letzten eingegebenen Zeichens annimmt.

Heißt das, für eine vollständige Ausgabe müsste jedes Mal wieder die Schleife durchlaufen lassen werden?

Geschrieben um 00:34 am 12.07.2004 | Zitat | Editieren | Löschen
Clive
Mitglied
Bachelor Gumby
Beiträge: 60

Array player_name string 63;

[ FrageRoutine req_array len;

    req_array->0 = len;

    read req_array 0; 

];

[ AusgabeRoutine req_array i c;

    for (i=0: i < req_array->1: i++) {

      c = req_array->(2+i);

      print (char) c;

    }

];

   

[ Main;

    print "^Gib deinen Namen ein:";

    FrageRoutine(player_name,60);

    print "^^Du hast als deinen Namen ~"; print (AusgabeRoutine) player_name; print "~ eingegeben.^^";

];

Das ist schon fast das, was ich haben wollte. ^^

Um mich an Groß- und Kleinschreibung zu versuchen bin ich heute aber schon zu müde.

Geschrieben um 12:51 am 21.07.2004 | Zitat | Editieren | Löschen
Kris
Mitglied
Dr Gumby
Beiträge: 181

Zitat:

Um mich an Groß- und Kleinschreibung zu versuchen bin ich heute aber schon zu müde.

Hi,

ich weiss nicht ob es noch aktuell ist,

aber du könntest das so lösen indem du den char-Wert des ersten Buchstabens (also den dritten Eintrag des Arrays) um 32 verkleinerst, so erhälst du automatisch den großen Buchstaben:



z = req_array -> 2;

z = z -32;

req_array -> 2 = z;

...```

Funktioniert natürlich nicht mit "ß" oder ähnlichen Zeichen, man könnte also erst noch prüfen ob der dritte Eintrag auch zwischen 97 und 122 liegt (also im normalen Buchstabenbereich).

Grüße

Kris
Geschrieben um 13:26 am 21.07.2004 | Zitat | Editieren | Löschen
Martin
Avatar
Mitglied
Prof Gumby
Beiträge: 634

Zitat:

Funktioniert natürlich nicht mit "ß" oder ähnlichen Zeichen, man könnte also erst noch prüfen ob der dritte Eintrag auch zwischen 97 und 122 liegt (also im normalen Buchstabenbereich).

Eine Variante, die alle Buchstaben groß schreibt, wenn sie nach einem Zeichen stehen, die kein Buchstabe sind, findet man in in Roger Firths Inform FAQ.

So werden "Paula-Henriette Meier", "George W. Bush", "Bad Oeynhausen", "M'Gladbach" usw. richtig ausgegeben.

Die Anpassung auf die deutschen Umlaute könnte wie folgt aussehen:


[ ist_dt_Zeichen x;

  if (x >= 'a' && x <= 'z') rtrue;

  if (x == '@:a' or '@:o' or '@:u' or '@ss') rtrue;

  rfalse;

];

[ Gross x;

  if (x >= 'a' && x <= 'z') return x - 32;

  if (x=='@:a') return '@:A';

  if (x=='@:o') return '@:O';

  if (x=='@:u') return '@:U';

  return x;

];

[ Ausgabe_Gross buf i c flg;

    for (i = 0,flg = true : i < buf-->0 : i++) {

        c = buf->(i+WORDSIZE);

        if (ist_dt_Zeichen(x)) {

            if (flg) c = Gross(c);

            flg = false;

        } else flg = true;

        print (char) c;

    }

];

Die in Rogers Beispiel verwendete Routine UpperCase ist in der englischen Lib 6/11 definiert und behandelt alle westeuropäischen Zeichen (ISO 8859-1) korrekt, die Routine Gross ist nur eine abgespeckte Version, genau wie ist_dt_Zeichen.

Geschrieben um 13:04 am 22.07.2004 | Zitat | Editieren | Löschen
Clive
Mitglied
Bachelor Gumby
Beiträge: 60

Hm, ich hatte es so ähnlich gelöst wie in Kris' Beispiel, aber war dann natürlich auf ein Wort (im Fall eines Spielernamens) beschränkt geblieben. Hatte mich damit auch vorerst begnügt, aber wenn ich Martins Beispiel so durchlese... wow. ^^

Das eröffnet ja ungeahnte Möglichkeiten. Danke!

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