80 x 50 Pixel im Textmodus malen

Es gibt 51 Antworten in diesem Thema, welches 17.542 mal aufgerufen wurde. Der letzte Beitrag (2. Januar 2021 um 15:35) ist von Ratte.

  • Mahlzeit,

    gelegentlich muss man mal Schwachsinn ausprobieren.

    Aus einer kleinen Langeweile im Urlaub entstanden.

    Eine Punktroutine für den Textmode Auflösung 80 x 50 Pixel.

    px=.. (0-79)

    py=.. (0-49)

    pm=.. 0 pixel löschen / 1 pixel setzen / 2 pixel invertieren / 3 pixel auslesen (ergebnis in pm 0/1)

    aufruf über

    gosub10000

    todo: test mit array de/codierung, mal sehen ob es noch schneller geht ... :D

    Im Anhang ist das Basic-Programm mit einem Benchmark (schwer übertrieben).

    In der Version wird die ursprüngliche Pixelroutine verwendet.

    Wenn im Listing die Zeile 10000 verändert wird (es reicht ein 10000 rem) springt die schnellere Routine an.

    Gruß

    Ratte

  • schnellere version faktor 6-8x

  • Schöne Idee! Das erste Programm sieht ja deutlich kürzer aus als das zweite, das zweite scheint tatsächlich wesentlich schneller zu sein. Leider aber auch fehlerhaft: wenn ich den ganzen Bildschirm zeilenweise fülle, erscheint bei der 2., 4. .6. usw. Zeile regelmäßige Fehlmuster. Muss mal eine eigene Version probieren. :wink:

    Irgendwo hatte ich mal eine Maschinenroutine dafür, und es gab mal ein "schnelles" Game of Live, ist aber schon lange her... Gab es zur Maschinenroutiene nicht mal einen Artikel in der 64'er?

  • wenn ich den ganzen Bildschirm zeilenweise fülle, erscheint bei der 2., 4. .6. usw. Zeile regelmäßige Fehlmuster.

    Ahhh ... schau an, dafür sind Foren gut.

    Bugs jagen ... Danke für den Hinweis.

    (Für ein "Gefällt mir" fehlt mir die Berechtigung .. bin zu neu hier)

    Mit der Pixelroutine wollte ich meinem Sohn etwas zum coden in die Hand geben.

    Aufgabenstellung wie ... mach mal eine Line-Funktion damit.

    Oder Kreise zeichen .. die Basics halt.

    :D

  • (Für ein "Gefällt mir" fehlt mir die Berechtigung .. bin zu neu hier)

    Papperlapapp. :smile:

    Mit der Pixelroutine wollte ich meinem Sohn etwas zum coden in die Hand geben.

    Damit kannst Du ihn locken? Cool!

    Aufgabenstellung wie ... mach mal eine Line-Funktion damit.

    Bresenham und so...^^

    Mich hats grad in den Fingern gejuckt, daher ist hier mal meine Version. Sie ist sogar etwas schneller als Deine. Allerdings muss ich 2 Felder vorinitialisieren, und ich kann nur Punkte setzen, nicht löschen oder abfragen. Die Variablen habe ich teilweise so wie Du genannt.

    Das geht sicher noch schneller, hier sind einige Basiccracks dabei. Bin mal gespannt, ob jemand schneller wird.

    Edit: Mist, in Zeile 100 soll eigentlich das Steuerzeichen für Bildschirm löschen rein. Habs eben mal per Hand im Code geändert.

  • Mittlerweile habe ich die Setz/Lösch/XOR/Abfrage ergänzt. Außerdem habe ich gemerkt, dass mein Programm nur schneller ist, wenn ab Zeile 12500 nicht durch zu viele ifs laufen muss. Dann ist es nämlich leider langsamer. Sorry für meine kühne Behauptung.

    Aber kürzer ist es allemal. Und für die Zeilen ab 12500 fällt mir vielleicht noch was ein.

  • Schöne Idee!

    So neu ist die Idee nicht. Im Band 13 der Commodore-Sachbuchreihe von 1984

    findet sich ein Beispiel dazu.

    Hier mal eine Version von mir, ohne If-Abfragen:


    Gruß,

    Neptun

  • Ich hab ja ´ne Schwäche für 80x50, wenn "eigene" Zeichen im Dot-Matrix-Look genutzt werden :)

    Bitte melde dich an, um diesen Link zu sehen.

  • Mit "schöne Idee" meinte ich auch nicht, dass die Idee neu ist, sondern einfach, das ich es schön finde, das Problem mal wieder auszupacken, anzugehen und Lösungswegen zu suchen.

    Deine Lösung ist jedenfalls schön kurz! Die Idee mit dem 2. Array hatte ich auch, und der Threadstarteter hatte es auf der Todo-Liste - ich denke, in Basic wird es nicht wesentlich schneller gehen. Dein Programm ließe sich noch um entsprechende Zeilen zum Löschen und XOR erweitern:

    Code
    3 n=vr+int(x/2)+c*int(y/2):poken,z(t(peek(n))and15-h((xand1)+2*(yand1))):return
    4 n=vr+int(x/2)+c*int(y/2):n1=t(peek(n)):n2=h((xand1)+2*(yand1))
    5 poken,z((n1orn2)-(n1andn2)):return
    6 n=vr+int(x/2)+c*int(y/2):n1=t(peek(n)):n2=h((xand1)+2*(yand1))
    7 n=-((n1andn2)=n2):return

    gosub3 ist löschen, gosub4 invertieren, und gosub6 abfragen. Das Ergebnis steht in der Variablen n.

  • Hier habe ich noch einen älteren Beitrag gefunden:

    Bitte melde dich an, um diesen Link zu sehen.

    Und hier noch eine Seite mit Blockgrafik in Maschinensprache:

    Bitte melde dich an, um diesen Link zu sehen.

  • Ich hätte jetzt nicht gedacht, dass es sooooo ein Interesse weckt.

    :)

    Aber warum nicht .... wollen wir nicht mal eine Competition daraus machen und den schnellsten Basic-Code für das Problem finden?

    :thumbsup:

    Zu der "IF-THEN Problematik" ... der Basic-Interpreter lässt es einen spüren, wenn die Bedingung erst am Ende eine langen Abfragekette eintrifft.

    Im zweiten Listing (die lange Version) ist es viel performanter, da ich zwei Sachen dafür eingebracht habe.

    - Das Zerlegen der Abfrage mehrmals in gleich große Teilstücke, was in Summe einen schnelleren Durchlauf ermöglicht.

    (Zeilen 10160-10260)

    - ON x GOTO ist das nächste an Zauberei ....

    Wenn ich ehrlich sein soll, dieses ist mein erster Code, wo ich den Befehl jemals verwendet habe.

    Der Befehl ist im Grunde ein TURBO-IF-THEN-GOTO, der Interpeter hat ab nur einen Token zu dekodieren.

    Man muss nur vorher x in das passende Format bringen.

    (Ich verwende es hier zum setzen löschen & invertieren ... der folgende GOTO-Befehl ist dann Parameter 3 RO (read only) und setzt pm auf 0 oder 1)

    When coding IS fun ... :P

  • Gerne kann man noch eine challenge draus machen, aber ich glaube, der Code von Neptun ganz ohne if ist der schnellste. Ich kann mir nicht vorstellen, dass es in Basic wesentlich besser geht.

    Die lange if-Abfrage hatte ich bei mir auch nochmal abgeändert. In meiner ersten Version sind es bis zu 16 Abfragen, also im Schnitt bei zufälligem Durchlauf 8 Abfragen. Durch Intervallschachtelungen lässt sich das auf immer genau 4 Abfragen ändern. Dadurch wird dieser Teil immerhin doppelt so schnell. Aber die Doppel-Array-Methode kommt ganz ohne if aus und ist damit noch um einiges schneller, verbraucht aber auch mehr Speicherplatz.

    Wenn der Zeichensatz anders aufgebaut wäre und die Zeichen in der richtigen Reihenfolge hintereinander stehen würden, bräuchte man gar kein Array und kein if.

  • Gerne kann man noch eine challenge draus machen, aber ich glaube, der Code von Neptun ganz ohne if ist der schnellste. Ich kann mir nicht vorstellen, dass es in Basic wesentlich besser geht.

    Ein bisschen schon. Da springt mein Optimierungsdrang schon etwas an ...

    Die Punkte im Einzelnen:

    • Array H(3) als Array H(1,1). Dann kann muss man den Index nicht umständlich mit Multiplikation errechnen, sondern kann direkt nur mittels AND 1 aus X oder Y ableiten. Der Interpreter kann mit den zwei Indizes schneller rechnen.
    • Die Errechnung von N kann zumindest bei der Y-Komponente mit AND MK (blendet Bit 0 aus) und halbiert den Wert nicht, weil er ohnehin mit C multipliziert wird, welcher dann nicht mehr 40 sein muss, sondern auf 20 reduziert werden kann. Man spart eine Division.
    • Die Initialisierung der Variablen wird mit den häufigst genutzten begonnen. DIM N,X,Y,... legt diese mehrfach in GOSUB 2 etc. verwendeten Variablen zuerst an und ergibt damit auch den schnellsten Zugriff.
    • Ein Array XR(15,15) hat die XOR-Funktion, die in Z 4 gebraucht wird als Tabelle abgebildet. Es braucht die Initialisierung dann halt länger, weil 256 Werte vorberechnet werden müssen. Ist halt nur notwendig, wenn die XOR-Funktion wirklich gebraucht wird.
    • Die Test-Funktion in Z 6 vermeidet die Variable N1 und macht alles in einer Zeile. Das Ergebnis (in Variable N) ist -1 (statt 1), wenn gesetzt und 0 wenn nicht. Das ist ist konsistent mit der sonstigen Konvention in BASIC für logische Ausdrücke (True/False).

    Es ist noch eine Zeitmessung fürs das Zeichnen des Koordinatenkreuzes inkludiert, um etwaige Verbesserungen zu messen.

    Die Laufzeit (fürs Kreuzzeichnen) reduziert sich von 5,27 s auf 4,63 s, das sind 12 % Ersparnis. Immerhin. Es ist gerade so viel, dass man "merkt", dass es schneller ist, wenn auch nicht bahnbrechend. ;)

  • 80 x 50 PIXEL-MODUS:

    Bitte melde dich an, um diesen Anhang zu sehen.

    Bitte melde dich an, um diesen Anhang zu sehen.

    Wieder mal ein Thema, daß nach einem 10-Zeiler ruft:
    Ob es die schnellste Lösungs ist, weiß ich nicht.
    Auf jeden Fall kann man damit farbig Printen.
    In Kombination mit dem Ketten-Poke kann Zeile 18 in jedem Fall noch optimiert werden.
    poke209,i,i/256,0:printa$(..)

    Schönen Gruß.

  • 80 x 50 Pixel:

    Bitte melde dich an, um diesen Anhang zu sehen.

    Hier hab ich noch mal eine gekürzte Poke-Version.
    Man kann das Problem also in circa 4-5 Zeilen und mit einem Feld lösen.

    Schönen Gruß.

  • Ich kann mich erinnern, dass das Zeichnen von 80x50 Punkten damals (1979) eines meiner ersten (sinnvollen) Assemblerprogramme war.

    Auf dem PET, lauffäufig im Kassettenpuffer. Von Hand assembliert, weil ich noch keinen Assembler hatte.

    Später folgte ein Game of Life in 80x50. Auch in Assembler.

  • Die Version von JeeK ist die bisher schnellste in Basic. Die zweite von BIF ist aber auch nur ein wenig langsamer.

    Die Version von Jeek lässt sich sicher auch in 10 Zeilen machen, wenn man auf Löschen/Invertieren/Abfragen und das Drumherum mit der Zeitmessung verzichtet.

    detlef: Ich meine mich an ein solchen Programm erinnern zu können, kann aber nirgendwo etwas finden. Hast Du Deine Version noch irgendwo?

    Es gibt ja auch ein Galaga, was im Textmodus mit diesen Zeichen arbeitet, das gibt es auch für den C64: Bitte melde dich an, um diesen Link zu sehen.