Hallo Besucher, der Thread wurde 12k mal aufgerufen und enthält 78 Antworten

letzter Beitrag von syshack am

Daten in DATA-Zeilen ändern?

  • Ich grüble gerade darüber nach, ob es mit vertretbarem Aufwand möglich sein könnte, Daten in DATA-Zeilen zu ändern.
    Die Idee dabei ist, zu Beginn eines Programms Daten aus den DATA-Zeilen in ein Array zu laden und dieses dann für den Programmablauf zu benutzen. Allerdings möchte ich ungern mit einem zu großen Array arbeiten, weil das ja auch Speicher frisst. Aber dann müsste man die nicht gebrauchten Bereiche jeweils mit den aktuellen Änderungen in die DATA-Zeilen zurückschreiben, um sie bei Bedarf erneut einzulesen. Wer kann mir dazu was erzählen? ^^

  • Ich würde sagen nein, nicht mit "vertretbarem" Aufwand. Direkt im Speicher wird schwierig, weil die DATA Zeile "as is" in PETSCII abgelegt ist.
    Wenn es um Zahlen geht könnte man diese von vorneherein mit führenden Nullen ablegen um an festen Indices modifizieren zu können, etwa sowas hier:

    Code
    1. 10 data001,002,015,004
    2. 20 fori=1to4
    3. 30 reada
    4. 40 a=a+1:n$=str$(a)
    5. 50 p$="":forj=0to3-len(n$):p$=p$+"0":next
    6. 60 p$=p$+right$(n$,len(n$)-1)
    7. 70 forj=1to3:poke2049+4*i+j,asc(mid$(p$,j,1)):next
    8. 80 next

    Das ist aber wohl alles andere als effizient -- und die Berechnung der Indices wird ungleich komplizierter sobald man mehr als eine DATA Zeile hat. Ich würde davon abraten.


    Die einzige andere Möglichkeit, die mir hier noch einfällt, ist die Modifikation im Direktmodus durchführen zu lassen (geänderte DATA Zeilen auf den Bildschirm schreiben und den Tastaturpuffer mit <HOME>, <ENTER> usw "füttern"). Das ist aber ein hässlicher Hack und verlässt zwischenzeitlich das Programm.

  • Hier das Unterprogramm String-Copy.
    Damit kann kann man einen String c$ an eine Adresse a kopieren.


    Die Stringadresse kann man mit dima,c$:a=peek(34+(c$<""))+peek(35+(c$<""))*256: berechnen.


    30 :rem---string-copy(c$,a)
    31 :poke782,peek(35+(c$<"")):poke781,peek(34+(c$<"")):poke780,len(c$)
    32 :poke54,a/256:poke53,a-peek(54)*256:sys46728:return


    Schönen Gruß.

  • Also: selbstmodifizierenden Basic-Code zu schreiben sist alles andere als trivial (Vorsicht, hierzu hat Beetlejuice bestimmt eine Meinung. Den echten Namen nenne ich besser nicht). EDIT zu spät, er ist schon da....


    Beim auslesen von DATAs mittels Read bleibt der Lesezeiger jeweils auf dem letzten eingelesenen Wert stehen. Bei vorsichtiger Programmierung kannst Du später genau an dieser Stelle weiter auslesen.


    Benötigst Du aber die Möglichkeit, bestimmte DATA-Zeilen später erneut auszulesen oder an genau definierten Stellen DATAs auszulesen, würde sich ggfs. eine Basicerweiterumg anbieten, die Befehle beherrscht wie RESTORE n, wobei n die Zeile angibt, auf die der DATA Lesezeiger weisen soll.


    Aufgrund Deiner kurzen Beschreibung ist es recht schwammig, was Du genau erreichen willst. Es ist aber wahrscheinlich, dass Du mit dem DATA/READ-Konzept hier den falschen Ansatz verfolgst für den Zweck, den Du erreichen willst. Als intelektuelles Denkspiel ist es aber interessant, darüber nachzudenken.

  • Wenn man die Data´s in ein Feld eingelesen hat, z.B.
    mit
    dima$(90):fori=1to90:reada$(i):next:


    hat man die Stringpointer auf die Data-Elemente und kann dann auch darauf zugreifen.


    Data-Zeilen-Änderung ist natürlich Selbstmodifikation, das ist natürlich klar.


    Ansonsten kann man mit Super-7 die Zeilenadresse feststellen und damit dann die Zeiger auf die Data-Elemente berechnen.


    Schönen Gruß.

  • zu Beginn eines Programms Daten aus den DATA-Zeilen in ein Array zu laden und dieses dann für den Programmablauf zu benutzen. Allerdings möchte ich ungern mit einem zu großen Array arbeiten, weil das ja auch Speicher frisst. Aber dann müsste man die nicht gebrauchten Bereiche jeweils mit den aktuellen Änderungen in die DATA-Zeilen zurückschreiben, um sie bei Bedarf erneut einzulesen.

    Falls es bei den Daten um Strings geht, gilt: Das "Laden in ein Array" verbraucht keinen zusätzlichen Speicher, denn die Pointer im Array werden direkt auf die DATA-Zeilen verbogen. Erst bei Änderungen werden die Strings neu im Speicher angelegt.
    Ansonsten stimme ich meinen Vorrednern zu: Beschreib Dein Vorhaben mal genauer, dann kann man evtl. mehr sagen.

  • Ich grüble gerade darüber nach, ob es mit vertretbarem Aufwand möglich sein könnte, Daten in DATA-Zeilen zu ändern.
    Die Idee dabei ist, zu Beginn eines Programms Daten aus den DATA-Zeilen in ein Array zu laden und dieses dann für den Programmablauf zu benutzen. Allerdings möchte ich ungern mit einem zu großen Array arbeiten, weil das ja auch Speicher frisst. Aber dann müsste man die nicht gebrauchten Bereiche jeweils mit den aktuellen Änderungen in die DATA-Zeilen zurückschreiben, um sie bei Bedarf erneut einzulesen. Wer kann mir dazu was erzählen? ^^

    Sind diese Daten denn überhaupt Strings, wie oben vermutet wurde? Es wäre wirklich interessant zu wissen, welcher Art diese Daten sind und um welchen Datentyp es sich bei dem Array handelt (Float, Integer, String). Wenn es numerische Werte sind, die das Array "frisst", dann kann vielleicht ein Wechsel von Float- auf Integer-Arrays (z.B. A() -> A%() ) die entscheidende Einsparung bringen, die vielleicht das DATA-Zeilengeschubse erst gar nicht notwendig macht.


    Brauchst du die DATA-Darstellung, weil du den Zustand der Daten so mit dem Programm jederzeit abspeichern können möchtest?


    Wenn nicht, wäre ich eher geneigt, z.B. für Array (numerisches) den Speicherort zu ermitteln und den Adressbereich insgesamt in einen freien (ab $C000) oder reservierten Bereich (vom BASIC-RAM-Top abzwacken) mit dem BASIC-Blockcopy zu kopieren und von dort wieder zu restaurieren. Für diese Dinge gibt es die entsprechenden Routinen per SYS aufrufbar (einfach 3x Beetlejuice rufen ... :whistling: ).


    Die DATA-Aufbewahrung kostet auch auch üblicherweise Raum im BASIC-Speicher. Da ist es nicht immer gesagt, dass es dort weniger braucht, als in Array-Elementen gespeichert.
    Aber es ist schwer das zu erörtern, wenn nicht klar ist, was du genau machen möchtest, wie die Randbedingungen sind. ;) Da wären wir wieder bei Posting #2.

  • Die Idee dabei ist, zu Beginn eines Programms Daten aus den DATA-Zeilen in ein Array zu laden und dieses dann für den Programmablauf zu benutzen.

    Ersetze "DATA-Zeilen" durch "Datei" - dann kannst Du auch eine geänderte Fassung deiner Daten (unter anderem Dateinamen) wegschreiben, und die an Stelle der ursprünglichen Daten-(SEQ-)Datei nutzen. Zu Beginn schreibst Du einmal die Daten aus den originalen DATA-Zeilen in die SEQ-Datei rein.


    Braucht nur eine gescheite Eingaberoutine, damit das ganze nicht auf Kommata und anderen Zeichen ausrutscht. GET# geht natürlich auch, ist aber langsam.


    (Obwohl: alles was sich in DATA-Zeilen unterbringen läßt, *müßte* sich eigentlich auch von INPUT# wieder einlesen lassen. In DATA-Zeilen muß man ja Daten mit "," und ":" in Anführungszeichen setzen sofern sie Teil eines Datums sind ... führende und abschließende Anführungszeichen werden aus dem gleichen Grund bei String-READs großzügig ignoriert - nichts anderes als was eben auch bei INPUT# passiert ...)

  • (Obwohl: alles was sich in DATA-Zeilen unterbringen läßt, *müßte* sich eigentlich auch von INPUT# wieder einlesen lassen. In DATA-Zeilen muß man ja Daten mit "," und ":" in Anführungszeichen setzen sofern sie Teil eines Datums sind ... führende und abschließende Anführungszeichen werden aus dem gleichen Grund bei String-READs großzügig ignoriert - nichts anderes als was eben auch bei INPUT# passiert ...)

    Man muss die Anführungszeichen glaub ich dann auch explizit im Datenstrom haben, also etwa rausschreiben mit PRINT#1,CHR$(34);VAL$;CHR$(34)

  • Ich würde die Daten ja auch in eine separate Datei speichern, aber mit programmiertem Direktmodus und einem recycelten DATA-Zeilen-Generator sollte das fast genauso gut klappen. Nachteil: Auf die Daten muß mit PEEK und POKE zugegriffen werden, weil die Eingabe einer Zeile die Variablen löscht. Also entweder das Array nach 49152 ff. poken oder direkt auf das BASIC-Array verzichten.

  • Was genau hast du denn vor?

    Das weiß ich noch gar nicht. Ich grüble mehr so allgemein nach in Richtung Textadventure oder Dungeoncrawler...

    Wieviel Bytes werden denn für die Daten benötigt?

    Weiß ich nicht...

    Spielt Geschwindigkeit bei deinem
    Programmvorhaben eine Rolle?

    Eine untergeordnete, würde ich vermuten.

    ersetze "DATA-Zeilen" durch "Datei" - dann kannst Du auch eine geänderte Fassung deiner Daten (unter anderem Dateinamen) wegschreiben, und die an Stelle der ursprünglichen Daten-(SEQ-)Datei nutzen.

    Also mit Zugriff auf die Diskette? Interessiert mich auch, aber weniger in diesem Zusammenhang...



    Pro Sting hast du 3 Byte Speicherverbrauch

    Es gibt ja nur einen Sting. Und der geht auch schon auf die 70 zu... ^^

  • Naja, die Idee war halt, die Ausgangsdaten der Strings und Variablen in den Arrays am Anfang aus den Data-Zeilen einzulesen, aber ich meine, es ist nicht so gut, wenn Arrays so riesig sind, oder? Darum war meine Überlegung, das Array kleiner zu dimensionieren, so dass es quasi einen Ausschnitt der virtuellen Welt repräsentiert, die ich schaffen möchte, quasi wie eine Lupe auf einem Stadtplan. Wenn sich der Spieler bewegt, wird also immer nur der relevante Teil in das "RAM" geladen, um ein weiteres Bild zu bemühen...
    Sind aber ohnehin alles noch sehr prinzipielle Überlegungen...

  • ich meine, es ist nicht so gut, wenn Arrays so riesig sind, oder?

    Warum?


    Bei großen String-Arrays hat man in der Tat das Problem, dass dann die Garbage Collection ewig lange dauert, aber wenn man dieses Problem hat, lädt man einen entsprechenden GC-Patch und gut. Es bringt nichts, stattdessen $Dinge komplizierter als nötig zu machen.

  • Kommt ja auch drauf an wie gross die Spielwelt, Texte, Wortschatz werden soll.Schau dir mal den Kurs aus der 64'er an, den ich weiter
    oben erwähnt hab. Also die Idee Datazeilen während des Ablaufs zu erstellen würde ich mir in diesem Fall aus dem Kopf schlagen.
    Zumal wenn du das im programmierten Direktmodus machen würdest alle Variablen gelöscht würden. Mit Poke wirds dann auch nicht
    besser. Je nach größe würde ich die Daten halt in eine Datei auslagern und vom Programm aus nachladen. Texte kannste du z.B.
    auch gut in ne relative Datei packen. Siehe dazu auch den Adventure Kurs ich glaub 64'er SH 6/86.

  • Naja, die Idee war halt, die Ausgangsdaten der Strings und Variablen in den Arrays am Anfang aus den Data-Zeilen einzulesen, aber ich meine, es ist nicht so gut, wenn Arrays so riesig sind, oder?

    Ganz grob gesehen funktioniert Basic ja tatsächlich so, Programm + "RAM" für Variablen.


    Zahlenvariablen belegen ein bisschen Platz, sobald man sie das erste mal verwendet, ein paar Bytes am Stück für den Namen und die Zahle selber. Die Länge bleibt immer gleich, und die Position der Variablen im Speicher bleibt auch immer gleich.
    Strings können ihre Länge ändern und sind deshalb zweigeteilt: Wie bei Zahlen ein fester Teil mit dem Namen und einem Zeiger, dazu ein variabler Teil, der am Ende des RAMs Speicher frisst.


    Soweit passt Deine Idee also gut, Speicher sparen zu wollen.
    Allerdings hat Basic schon eine Verbesserung eingebaut: Bei Befehlen wie A$="Hallo" oder Read A$ ist der String schon perfekt im Programmspeicher enthalten. Der Zeiger in der Variablen zeigt dann ins Programm, der eigentliche Inhalt des String frisst dann keinen Speicher. So gesehen braucht das komplette String-Array auch nur billige 3 Bytes je String, Teuer wird es erst, wenn Du den String veränderst, dann muss Platz im RAM genommen werden.


    Für das RAM-Sparen durch Speichern in Data-Zeilen kann ich mir verschiedene biffige Lösungen vorstellen, je nachdem, was Dein Programm im Detail machen soll.
    -Beliebige einzelne Zeichen verändern? Dann das komplette Array lesen, von BIF ein 2. Integer-Array mit den Zeigern füllen lassen und dann einzelne Ascii-Werte Poken. Würde mich nicht mal wundern, wenn das schneller als per String-Operationen ginge.
    -Oder größere Änderungen querbeet, die sich ganz gut mit String-Ops darstellen lassen? Dann erstmal ganz normal einen String bearbeiten und von BIF an eine Array-Position zurückschreiben lassen.
    -Oder brauchst Du gar nicht alles auf einmal, sonder Screen für Screen würde reichen? Könnte die einzelnen Änderungen dann einfacher und Schneller machen.
    -Ein "Restore {Zeilennummer}" dürfte dann hilfreich sein, wird BIF Dir raussuchen können. Damit könntest Du dann einen Screen ab einer bestimmten Datazeile laden. Schreiben dann auf einem der genannten Wege.
    -Oder doch einen ganzen Screen im Block zurückschreiben lassen? Wird sich mit dem Restore und einem 2. Array machen lassen.


    Falls Dein Programm aber so groß wird, dass Du Dir Sorgen um Speicherplatz machen musst, dann wären Assembler-Hilfen gut. Ein Binärfile ans Programm gehängt oder Nachgeladen spart viel Overhead in Data-Zeilen und kann auch noch bequem 12KB oder mehr Extra-Speicher schaffen, und diverse Sorgen zum Adressieren der richtigen Strings würden auch wegfallen