atarionline.pl MAD-Pascal - Początki - Forum Atarum

Jeśli chcesz wziąć udział w dyskusjach na forum - zaloguj się. Jeżeli nie masz loginu - poproś o członkostwo.

  • :
  • :

Vanilla 1.1.4 jest produktem Lussumo. Więcej informacji: Dokumentacja, Forum.

    • 1: CommentAuthorzbyti
    • CommentTime6 Nov 2019
     
    @archieil no to dopisuję to do nieistniejącej jeszcze listy w dziale #NiceToHave ;)
    • 2:
       
      CommentAuthorjhusak
    • CommentTime6 Nov 2019
     
    Co do deflate/gzip to jest Zopfli, Fox poleca. Sporo mniejsze pliki, ale czasu to one się kompresują... Jak się jest na krawędzi, to jak znalazł.
    ->link<-
    • 3: CommentAuthorzbyti
    • CommentTime6 Nov 2019 zmieniony
     
    @jhusak dzięki za podpowiedź :)

    DEFLATE dla wielu randomowych ciągów jakie sprawdzałem złożonych 1225 zer i jedynek zawsze się mieści w 256 bajtach.

    Czas kompresji nie jest istotny bo robię to na PC. Bardziej interesuje mnie czas dekompresji na A8 by QR renderował się z tego w miarę płynnie.

    Nie używam datamatrix z MP bo interesują mnie np. ascii-art w utf-8 po szybkości generowane do QR. Najwygodniej to robić na grzybie a wyniki renderować na A8.

    Moja prymitywna implementacja pakera buja się dla 1225 ciągu od 278-306 bajtów i nie zapowiada się bym zmieścił się w długości stringa bez czegoś bardziej zaawansowanego.

    Zobaczę co w praktyce mogę z tym zrobić ;)
    • 4: CommentAuthortebe
    • CommentTime6 Nov 2019
     
    w nowej wersji MP będzie PChar, nie ma ograniczeń STRING-a
    • 5: CommentAuthorzbyti
    • CommentTime6 Nov 2019 zmieniony
     
    @tebe to czekam na nową wersję :]

    Tymczasem poradziłem sobie z moim problemem :D Zszedłem na sztywno do 245 bajtów. Zadanie było proste, no ale jak się najpierw pisze a później myśli...

    -----------------------------------------------------------

    [TUTEK DLA POCZĄTKUJĄCYCH]

    Teoria: Lempel–Ziv–Welch ->link<-

    Jeżeli będę używał kodu QR w matrycy 35x35 to będę miał ciąg 1225 znaków. Przy 5-bit słowie potrzebuję słownika z 32 pozycjami, wtedy 1225 / 5 = 245 i mieszczę się w stringu ;)

    dictionary:

    '00000', '*' // 0
    '00001', 'b' // 1
    '00010', 'c' // 2
    '00011', 'd' // 3
    '00100', 'e' // 4
    '00101', 'f' // 5
    '00110', 'g' // 6
    '00111', 'h' // 7
    '01000', 'i' // 8
    '01001', 'j' // 9
    '01010', 'k' // 10
    '01011', 'l' // 11
    '01100', 'm' // 12
    '01101', 'n' // 13
    '01110', 'o' // 14
    '01111', 'p' // 15
    '10000', 'q' // 16
    '10001', 'r' // 17
    '10010', 's' // 18
    '10011', 't' // 19
    '10100', 'u' // 20
    '10101', 'v' // 21
    '10110', 'w' // 22
    '10111', 'x' // 23
    '11000', 'y' // 24
    '11001', 'z' // 25
    '11010', 'A' // 26
    '11011', 'B' // 27
    '11100', 'C' // 28
    '11101', 'D' // 29
    '11110', 'E' // 30
    '11111', '!' // 31

    source size 1225:

    1011111000011110011011110100001101101100101000111110000010000110111001001001010000111100101101111001010000011101100010111101110001110000100101110000100100000011010010101110110010001011110110011101010101000000001101110111001111110010010011111110111100000001001010001010101001010111011010100011000010100111100110101001000101101011110101000011110001001011110001001011100111100001011111111011100010100110101111100111010010010000111101000101010111000100000001001101011110001011111000010011000100100100101010011110010101111111101001011110000000111101011100000100010001010011010011010100100110111011110110100100011110000111001110000010011010011010011100001100110101010101010001011011101111100010101110100011001000000111001011100100010100101111110010111111010010101000110001001010110010000111101110110111101101000011100100011100001111011010000010001010110000001110011001010101110100111111001100011111000000011010010011011110101100000100000100001100010001000100100001111110011000100110110111101011011110011101011001000111010011111101111100110001001100011011010111111000111110110110010110001101000000111101000000101111110100000010010010010001101011011110011000011001001011111010101010001000011111000101001001111011000011001000100100001


    output size 245:

    xypgEqBmupqinzeuhsBzihmlBryjocidjlwixwovi*BxhCspDC*srksxniykpgurnpkdysEexhqx!ofgxzAjbDcvyqcnpc!bgesktzl!uxqdACcekngutoEAiEdtqjuAodgvkrnBCkDdebzoiuxCxDfiyswipoBBioiChwqivqhgkxj!ghybutpl*qimirehCytnDnCDmrApBCytdnpy!nsyA*Eqf!icjennCyms!kuiprjhwdejb [END]

    DEFLATE przy tym ciągu znaków osiąga identyczny wynik, do sprawdzenia ->link<-

    -----------------------------------------------------------

    To teraz piszę w MP depacker dla A8 :)
    • 6: CommentAuthorzbyti
    • CommentTime6 Nov 2019 zmieniony
     
    No to mam już depacker z rysowaniem QR ze skompresowanego stringa. Zostawię kod dla tych, których to może kiedyś zainteresować bo zaczną naukę od tego wątku ;)

    Tutaj wszystko do tej pory było bardziej zaawansowane niż moje wprawki ;)

    Panów ekspertów poproszę o ew. uwagi co i jak zrobiliby by działało to szybciej - ale proszę o sam pas bez asm ;)

    Ja sobie teraz to wszystko zparametryzuję by było bardziej uniwersalne i wyrzucę kod do unit.
    • 7: CommentAuthortebe
    • CommentTime6 Nov 2019
     
    w depack można skrócić sekwencję CASE

    'b'..'z': begin
    v:=ord(qr[i0]) - ord('a');
    binLine := binStr(v, 5);
    end;


    ->link<-
    • 8: CommentAuthortebe
    • CommentTime6 Nov 2019
     
    jeśli binLine zastąpić typem BYTE

    for i0 := 1 to 245 do begin

    case qr[i0] of
    '!' : binLine := %11111;
    '*' : binLine := %00000;
    'b'..'z': binLine := ord(qr[i0]) - ord('a');
    'A'..'E': binLine := ord(qr[i0]) - 39;
    end;

    for i1 := 0 to 4 do begin

    if (binLine and %10000 <> 0) then PutPixel(x,y);

    binLine:=binLine shl 1;

    x := x + 1;

    if (x = 35) then begin
    x := 0;
    y := y +1;
    end;
    end;

    end;
    • 9: CommentAuthorzbyti
    • CommentTime6 Nov 2019
     
    @tebe dziękuję! Tak to ja się mogę uczyć! ;)

    Jutro sobie to ogarnę a później przeczytam od dechy do dechy dokumentację MP żeby więcej kojarzyć bo już zaczynam trochę czuć pisanie w Mad Pascalu, więc nastał czas na uzupełnienie braków teoretycznych :]
    • 10: CommentAuthorMADRAFi
    • CommentTime6 Nov 2019
     
    Tak z ciekawosci do czego ten QR code bedziesz uzywal?
    • 11: CommentAuthorzbyti
    • CommentTime6 Nov 2019 zmieniony
     
    @MADRAFi chcę zrobić coś na kształt quizu (ale taki na myślenie raczej niż wiedzę leksykalną) i gry tekstowej z historyjką obrazkową na ASCII/UTF-8. Czasem by przejść do następnego ekranu trzeba będzie podać prawidłowe rozwiązanie jako kombinację klawiszy i / lub wpisanie odpowiedzi.

    Uzasadnię to jakoś fabularnie dlaczego A8 komunikuje się z nami za pomocą QR. Więc czytasz historię/polecenia komórką a odpwiadasz na klawiaturze A8.

    Coś w ten deseń ;)

    A by QR nie zajmowały tragicznie dużo miejsca potrzebowałem je spakować jakoś :]
    • 12: CommentAuthorzbyti
    • CommentTime7 Nov 2019 zmieniony
     
    Zaproponowane przez @tebe zakresy dla 'case' sporo skróciły program a przejście na BYTE go mocno przyspieszyło! Dzięki :)

    Sprytna sztuczka by nie iterować się po stringu a wiedzieć czy zapalić punkt! :)

    Dzięki Tobie będę teraz zwracał DUŻĄ uwagę podczas pisania programów na kosztowność operacji na poszczególnych typach danych :)

    Ta wersja programu działa tak szybko jak wcześniejsza z niespakowaną tablicą stringów! Na oko, wygląda tak jakbym nie miał narzutu związanego z rozpakowaniem QR Code. Można to sprawdzić uruchamiając stary kod hello_qr_v2.pas (dla wygody i porównania jest on w załączniku, ale, że to dublet na serwerze to ma dodatkową dwójkę w nazwie pliku) :]

    program depacker;
    uses crt, fastgraph;

    var qrCode: string = 'PPPPPPPAcfhOibHKgApLNEkCeMKfEkkgKKfElOoKkfHKJeeLNAcFkFibPPmIOpPDdKnknbDffCpGnEkJJJODFNCEOHJNaEbfphEopIGanGcGaMMDDeFJNijGIJedGPGNmoFpnHADFJODCfNFBMpMkkNccPCFfCLGNNCpdBOLOOCJKPpBldNdaDPOmjPoLAdoFBkhHKOEAojEkemDaNElkCppJElFbJplHKifJApAcBldLNPPPPPPP';
    i0, i1, x, y, dicLA, dicCA, qrBlock : byte;

    begin
    InitGraph(5);
    SetColor(1);

    // the 5-bit dictionary has 16 capital letters 'A'..'P'
    // and 16 lowercasers 'a'..'p'
    dicLA := ord('a');
    dicCA := ord('A') - 16; // second half of dictionary

    // point coordinates
    x := 0;
    y := 0;

    for i0 := 1 to 245 do begin
    case qrCode[i0] of
    'a'..'p': qrBlock := ord(qrCode[i0]) - dicLA;
    'A'..'P': qrBlock := ord(qrCode[i0]) - dicCA;
    end;
    for i1 := 1 to 5 do begin
    if (qrBlock and %10000 <> 0) then PutPixel(x,y);
    qrBlock := qrBlock shl 1;
    x := x + 1;
    if (x = 35) then begin
    x := 0;
    y := y + 1;
    end;
    end;
    end;
    ReadKey;
    end.
    • 13: CommentAuthorzbyti
    • CommentTime7 Nov 2019 zmieniony
     
    Pomyślałem, że być może faktycznie pojawią się tu kiedyś początkujący programiści i będą chcieli obczaić na szybko na czym polega trick @tebe, który tak bardzo przyspieszył mój program.

    Ja miałem już dwa razy ochotę zacząć programować w Mad Pascalu ale wbijając na ten wątek i zaczynając lekturę od DLI oraz widząc same wstawki ASM olałem temat.

    Dla takich osób kod i jego krótkie omówienie.

    -------------------------------------------------------------

    Zamiast tak jak ja porównywać do string, uderzając po indeksie za pomocą iteratora pętli for @tebe zrobił wash & go przesuwając sobie bitowo wartość bloku (typu BYTE) w lewo sprawdzając czy wciąż ma do zapalenia punkt, robiąc logiczne "and %10000".

    program shl_example;
    uses crt;

    var v, i : byte;

    begin
    v := %01001;
    writeln('Hello ATARI!');

    for i := 1 to 5 do begin
    writeln('');
    write(binStr(v, 5));
    if (v and %10000 <> 0) then
    write(' --> Bingo ', binStr((v and %10000), 5))
    ;
    v := v shl 1;
    end;

    ReadKey;
    end.
    • 14: CommentAuthorzbyti
    • CommentTime7 Nov 2019 zmieniony
     
    Korzystając z nowych zdobyczy wiedzy i pomysłu @tebe poprawiłem Compressor który używam do pakowania QR dla A8 na PC.

    Teraz nie ma tylu niepotrzebnych operacji na stringach jak w poprzedniej wersji.

    Jak zwykle z mojej strony pytanie o to co jeszcze mógłbym ulepszyć / skrócić etc.

    {$H+}

    program Compressor;

    var qrCode : string = '1111111111111111111111111111111111110000000100010100111111100100000001101111101000110100000111111011111011010001010100100010011100110100010110100010100101000110110101101000101101000101111110011101101001010001011011111010110010010000100110111110110000000101010101010101010100000001111111111101100110001111001111111111001100011110100110101010011010000110011001010010110010011111011001101101000101011001110011100111110100111010111101100101010011110101111100111101000001010000001001010111100111101000111001111110001011000000011011011000010101100000011100111001001110011001001010111001111010100001001101101100011001001000001110110111111011011101011000111010101011110110110111100001001110101110011111010011100100010111101101011000111100011111110001010010101110100010000101111110010101010010110010110111011011101111011001001111000111000111110110111111011110100101100111010111110111110001010110001111101000110000010011111111111001100010011111101110110111000000011011101010110001010100011110111110101111010100100000111001001101000101000100011001001100000111011010001011010101001001111011111100110100010111010100001110010111101011101111101001000001011100110000011111000000010100010101100011110111110111111111111111111111111111111111111';
    qrBlock : string = '%';
    i : smallint = 1;
    dicLA, dicCA : byte;
    letterCode, error : byte;

    begin
    // the 5-bit dictionary has 16 capital letters 'A'..'P' and 16 lowercasers 'a'..'p'
    dicLA := ord('a');
    dicCA := ord('A') - 16; // second half of dictionary

    repeat
    qrBlock := qrBlock + copy(qrCode, i, 5);
    val(qrBlock, letterCode, error);

    if (letterCode > 15) then
    write(chr(letterCode + dicCA))
    else
    write(chr(letterCode + dicLA))
    ;

    qrBlock := '%';
    i := i + 5;
    until i = 1226;

    writeln(' [END]');
    end.
    • 15: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    Czas na małe podsumowanie tego jak ewoluował kod i jak dzięki pomocy @tebe i @bocianu stawał się bardziej zwięzły i wydajniejszy.

    Do pomiaru czasu renderingu (mam nadzieję poprawnie) użyłem z biblioteki sysutils funkcji GetTickCount.

    Kod QR składa się 1225 punktów.

    Pobierałem licznik na początku pętli i na jej końcu po czym wyświetlałem różnicę.

    uses sysutils;
    var start, stop : cardinal;

    begin
    start := GetTickCount;
    << LOOP >>
    stop := GetTickCount;
    writeln(stop - start);
    end.

    Na ilustracji poniżej od lewej mamy następujące wersje (tak jak powstawały. 2a jest na osobnym obrazku):

    1. QR nie jest spakowany. Składowany jest w jednowymiarowej tablicy typu string. Tablica ma 35 elementów, każdy składający się z 35 znaków.
    Czas: 6

    2. QR nie jest spakowany. Składowany jest w dwuwymiarowej tablicy typu byte. Tablica jest matrycą 35 na 35 elementów.
    Czas: 29

    2a. QR nie jest spakowany. Składowany jest w dwuwymiarowej tablicy typu byte. Tablica jest matrycą 35 na 35 elementów. Dodano dyrektywę przyspieszająca operacje mnożenia.
    Czas: 18
    //Dyrektywa
    {$f $a0} // fastmul at page $a0 ($a000)

    3. QR spakowany. Składowany jest w zmiennej typu string o długości 245 znaków. Funkcja rozpakowująca operuje na bloku QR o typie string.
    Czas: 10

    4. QR spakowany. Składowany jest w zmiennej typu string o długości 245 znaków. Funkcja rozpakowująca operuje na bloku QR o typie byte.
    Czas: 7
    • 16: CommentAuthortebe
    • CommentTime8 Nov 2019
     
    gratulacja :) szybko się uczysz
    • 17: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    @tebe dziękuję za słowa zachęty :)

    Jeszcze w temacie dodam, że sprawdziłem czy 32 znaki od 'A' w wersji na PC i A8 dadzą tą samą wartość ord i zrezygnowałem z "dwuczęściowego słownika" na rzecz postępujących po sobie znaków.

    Wszystko bangla :]

    {$H+}

    program Compressor;

    var qrCode : string = '1111111111111111111111111111111111110000000100010100111111100100000001101111101000110100000111111011111011010001010100100010011100110100010110100010100101000110110101101000101101000101111110011101101001010001011011111010110010010000100110111110110000000101010101010101010100000001111111111101100110001111001111111111001100011110100110101010011010000110011001010010110010011111011001101101000101011001110011100111110100111010111101100101010011110101111100111101000001010000001001010111100111101000111001111110001011000000011011011000010101100000011100111001001110011001001010111001111010100001001101101100011001001000001110110111111011011101011000111010101011110110110111100001001110101110011111010011100100010111101101011000111100011111110001010010101110100010000101111110010101010010110010110111011011101111011001001111000111000111110110111111011110100101100111010111110111110001010110001111101000110000010011111111111001100010011111101110110111000000011011101010110001010100011110111110101111010100100000111001001101000101000100011001001100000111011010001011010101001001111011111100110100010111010100001110010111101011101111101001000001011100110000011111000000010100010101100011110111110111111111111111111111111111111111111';
    qrBlock : string = '%';
    dicFirstLetter : byte;
    letterCode, error : byte;
    i : smallint = 1;

    begin
    dicFirstLetter := ord('A');

    repeat
    qrBlock := qrBlock + copy(qrCode, i, 5);
    val(qrBlock, letterCode, error);
    write(chr(letterCode + dicFirstLetter));
    qrBlock := '%';
    i := i + 5;
    until i = 1226;

    writeln(' [END]');
    end.

    program depacker;
    uses crt, fastgraph;

    var qrCode : string = '```````QCFH_IBX[GQP\^UKSE[FUKKG[[FUL_O[KFX[ZEE\^QCVKVIB``MY_P`TD[NKNBTFFSPWNUKZZZ_TV^SU_XZ^AUBFPHUOPYWANWCWA]]TTEVZ^IJWYZEDW`W^MOVPNXQTVZ_TSF^VR]P]KK^CC`SVFS\W^^SPDR_\__SZ[`PRLD^DAT`_MJ`O\QDOVRKHX[_UQOJUKEMTA^ULKSPPZULVBZPLX[IFZQPQCRLD\^```````';
    i0, i1, x, y : byte;
    dicFirstLetter, qrBlock : byte;
    begin
    InitGraph(5);
    SetColor(1);

    x := 0;
    y := 0;

    dicFirstLetter := ord('A');

    for i0 := 1 to 245 do begin
    qrBlock := ord(qrCode[i0]) - dicFirstLetter;
    for i1 := 1 to 5 do begin
    if (qrBlock and %10000 <> 0) then PutPixel(x,y);
    qrBlock := qrBlock shl 1;
    x := x + 1;
    if (x = 35) then begin
    x := 0;
    y := y + 1;
    end;
    end;
    end;

    ReadKey;
    end.
    • 18: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    Oczywiście z powyższym można eksperymentować.

    Gdyby nie problem, ze zgodnością znaków między systemami to można by przy powyższym rozwiązaniu zrobić:

    dicFirstLetter := 0;
    qrBlock := qrBlock + copy(qrCode, i, 8);
    if (qrBlock and %10000000 <> 0) then PutPixel(x,y);

    czyli zastosować 8-bit słowo do pakowania :)

    Ja na ten moment zacząłem stosować 6-bit.

    Kompresja kodu QR tą metodą, składającego się z 1225 znaków daje kompresję odpowiednio do N-bit słowa:

    5-bit daje 245 znaków ; wymagany słownik: 32 znaki
    6-bit daje 205 znaków ; wymagany słownik: 64 znaki
    7-bit daje 175 znaków ; wymagany słownik: 128 znaki
    8-bit daje 154 znaków ; wymagany słownik: 256 znaki

    Oczywiście by liczby były całkowite czasem musimy dokleić parę zer do kodu QR. Np. dla 8-bit słowa musimy zrobić ze 1225 znaków 1232 itd. W związku z tym, że na końcu doklejamy zera funkcja rysująca je pominie i nie jest to problem.
    • 19: CommentAuthormono
    • CommentTime8 Nov 2019
     
    O jakiej zgodności piszesz? ATASCII jest zgodne z ASCII w ramach znaków alfanumerycznych i interpunkcyjnych.
    • 20: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    @mono nie mam potrzeby korzystać z większego słowa niż 6-bit. Problem pewnie można obejść ale ja wyrzucam sobie za pomocą chr do pliku i mam kompresję. Nie mam ambicji pisania dodatkowego kodu w tej sprawie. No chyba, że załatwia to jakiś "one liner" ;)

    W skrócie. Przy 7-bit słowie gdzie potrzebuję 128 znaków do zakodowania informacji Compressor

    // tutaj iteracja do 1225 ze skokiem 7
    dicFirstChar := 0; // można zacząć od innego znaku
    write(chr(letterCode + dicFirstChar));

    wypluwa mi na konsolę linuxa kody które nie są przez nią rozpoznawalne, przez co nie mogę ich wygodnie używać do rozkodowania w MP na A8.

    Na zrzucie masz "dzikie kody" przy 7-bi a na drugim poprawne przy 6-bit.
    • 21: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    Może inaczej...

    Na PC za pomocą Free Pascal uruchamiam poniższy kod:

    program znaki;
    var i : byte;

    begin
    for i := 0 to 255 do write(chr(i));
    end.

    daje on taki wynik jak na obrazku.

    Czyli sensownych znaków mam 95 a potrzebuję 128 dla 7-bit.

    !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

    Starczy tych 95 znaków na 6-bit słownik i mnie to urządza :)

    Ergo. Do budowania słownika na PC mogę wygodnie korzystać tylko ze znaków jakie wypluje ta pętla:

    program znaki;
    var i : byte;

    begin
    for i := 33 to 126 do write(chr(i));
    end.

    W dokumentacji Mad Pascala widzę coś takiego:

    zapis kodami ATASCII:
    'a'
    'fds'
    'W'
    #65#32#65
    #$9b

    Ale nie o to chodzi bym zastępował 7 czy 8 znaków trzema (np. #00) tylko 1 inaczej nie spakuje tego 8 razy tylko 8/3 razy :D
    • 22: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    Mam do Was pytanie :)

    Pobrałem starożytną książkę "Understanding Atari Graphics" i na ten moment doczytałem, że czyszczenie ekranu to reset lub przejście do tryby 0.

    Czy za nim się przedrę przez tę książkę ktoś mi podpowie jak czyścić ekran w trybie graficznym bez "mrugania"?

    Czy mam robić jakiś bufor i się przełączać? Napisać jaką procedurę czyszczącą ekran? Jak jest właściwa droga?

    Nie widzę w MD niczego takiego w graph / fastgraph.

    Na ten moment podejrzałem jak to jest w przykładach z Cube zamieszczonych z MP i tam po prostu zamazuje się rysując drugi raz to samo kolorem 0.

    Jakie jest koszerne podejście do tematu?

    Jakby ktoś chciał manipulować moim kodem to zamieszczam. Program ma 3 ekrany.

    EDIT: chyba najszybciej była by jakaś wstawka w asm... spróbuję coś tam zrobić za pomocą poke według tego "cuś" poniżej.

    SCREEN PEEK(88)+PEEK(89)*256
    OFFSET (40 x row #) + column #
    LOCATION = SCREEN + OFFSET

    So if you want to plot a purple pixel at character location (2,2) you do a POKE SCREEN + 82, 85.
    The luminance is set by the background color register 712.

    ->link<-
    • 23: CommentAuthortebe
    • CommentTime8 Nov 2019 zmieniony
     
    najpewniej jeszcze raz initgraph i OS go wyczyści, albo

    bmp_adr:=dpeek(88);   // adres pamięci obrazu
    fillchar(pointer(bmp_adr), 192*40, 0);


    można czyścić mniej, linia ma najczęściej 40 bajtów długości
    • 24: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    @tebe dzięki za szybką odpowiedź!

    W takim razie implementuję według Twoich sugestii :)

    EDIT: Dokładnie o to mi chodziło! Jr. THX :D

    procedure cls;
    begin
    fillchar(pointer(bmpAdr), 40*40, 0);
    ClrScr;
    end;
    • 25: CommentAuthormono
    • CommentTime8 Nov 2019
     
    Zdaje się, że wyplucie kodu 125 przez "S:" powoduje skasowanie ekranu (nie mam pewności).

    Co do mapowania Twojego słownika, to przyszła mi taka myśl do głowy. Jeśli potrzebujesz mieć tylko 32 znaki a nie zależy Ci żeby A było kodem 0, to można po prostu zrobić zwykłego AND #$3F co da Ci górną połówkę tabeli ASCII (duże i małe litery z innymi znakami). Czyli
    qrBlock := qrCode[i0] and $3F

    Pewnie będzie też ciut szybsze.
    • 26: CommentAuthorzbyti
    • CommentTime8 Nov 2019 zmieniony
     
    @mono dzięki za poszerzenie mojej wiedzy :)

    Zrezygnowałem już z dzielenia słownika, po prostu zauważając, że generalnie chodzi o wartość liczbową znaku przypisuję od pojedynczego cudzysłowu + 1 w górę, by mi nie rozcinało stringa podczas kompilacji.

    Paker i Compressor zaczynają od:

    dicFirstChar          : byte = 40;

    Na A8 nie wypluwam już znaków tylko biorę ich wartość liczbową więc nic się nie psuje. Zobacz ostatni zamieszczony kod w załączniku, są tam 3 różne QRy, lub odpal .xex

    Obecnie pracuję na maksymalnym (w mojej crossowej) metodzie słowniku 6-bitowym czyli zadowalam się 64 znakami. Wynik kompresji 1/6 jest zadowalający ;)

    EDIT: przy okazji odkryłem organoleptycznie to co pewnie jest w dowolnej dokumentacji ( np. tej od @tebe ->link<- ) o trybie tekstowym, ale wrzucę:

    write(chr(i)); // spowoduje dla i

    i = 125 // kasuje ekran
    i = 156 // kasuje linie
    i = 160 // kursor (inwersja spacji)
    i = 253 // dźwięk systemowy

    Także @mono miałeś rację co do 125 tyle, że na A8 ja na ekran tych znaków nie rzucam :)
    • 27: CommentAuthorzbyti
    • CommentTime9 Nov 2019 zmieniony
     
    Benchmark z którego może narodzi się szybsze rysowanie QR Code a może nie bo logika zapalania punktów pochłonie oszczędności? ;)

    Pierwszy obrazek, to zapalanie za pomocą dpoke po 4 punkty. Tu będzie narzut by połączyć 4-bity w 8-bit. Wydaje się, że nawet z taka dodatkową logiką powinno być szybciej.

    Drugi obrazek to przypadek QR Code ze wszystkimi zapalonymi punktami, rysowane w 2 pętlach po punkcie.

    Wszelkie sugestie mile widziane :)
    • 28: CommentAuthorzbyti
    • CommentTime9 Nov 2019 zmieniony
     
    Próbuję pójść powyższym tropem ale zaczyny to wymagać za dużo kombinowania.

    dpoke(bmpAdr + x , qrBlock);

    Rysuje w trochę nie do końca jasny dla mnie sposób. Ale pewnie gdzieś mogę doczytać jak za pomocą 8-bit zapalić jeden z 4 punktów z odpowiednim kolorem lub wszystkie 4.

    Na razie zadowalam się modyfikowaniem qrBlock := %10101010 by zapalić jeden z 4 punktów.

    Dane standardowo rozpakowują się do 6-bit liczby, więc biorę dwie takie liczb i składam w jedną 12-bitową, po czym rozbijam ją na 3 liczby 4-bit i z każdej robię 8-bit.

    Jeszcze bym to przebolał ale offset komplikuje to do reszty.

    Chyba najlepiej będzie jak zrobię 4-bit bufor przez który będę przepuszczał qrBlock i wtedy zadziała obecny offset oraz odpadnie składanie i rozbijanie liczb :]

    Poniżej kod rysujący pierwsze 24 piksele koszmarną metodą.

    for i2 := 2 to 3 do begin
    threeCodes := %000000000000;
    threeCodes := threeCodes or (ord(qrCode[i2]) - dicFirstChar);
    threeCodes := threeCodes shl 6;
    threeCodes := threeCodes or (ord(qrCode[i2 + 1]) - dicFirstChar);
    for i0 := 1 to 3 do begin
    for i1 := 1 to 4 do begin
    if (threeCodes and %100000000000 = 0) then begin
    qrBlock := qrBlock shl 2;
    qrBlock := qrBlock or %10;
    end else begin
    qrBlock := qrBlock shl 2;
    end;
    threeCodes := threeCodes shl 1;
    end;
    dpoke(bmpAdr + x, qrBlock);
    qrBlock := 0;
    x := x + 1;
    end;
    end;

    Na ten moment usprawniłem stary kod i jest tick mniej bo nie rysuję ramki.

    W ciągu QR Code na pierwszym miejscu przesyłem sobie z Compressora wyliczony offset więc to już też odpada po stronie depackera.
    • 29: CommentAuthorzbyti
    • CommentTime9 Nov 2019 zmieniony
     
    Korzystając z podpowiedzi @tebe rozbudowałem "czyszczenie ekranu" by działało w wybranym miejscu. Oczywiście najszybciej działa samo fillchar po całości.

    Czasem jednak przydaje się wyczyścić czy zamalować prostokąt o wymiarach x *4 * y.

    Niedogodnością jest, że bok x jest w pikselach wielokrotnością 4.

    Poniżej kod dla trybu 7. Z ręki dla innego trybu zmieniamy po prostu 40, może to w przyszłości zparametryzuję. A jak rozgryzę to zapalanie punktów to zrobię rysowanie co do piksela.

    InitGraph(7);
    bmpAdr := dpeek(88);

    procedure cls(x, y, rX, rY, color: byte);
    var i0 : byte;
    i2 : word;
    bmpAdrXY : word;
    begin
    i2 := 0;
    bmpAdrXY := bmpAdr + x + (40 * y);
    for i0 := 1 to rY do begin
    fillchar(pointer(bmpAdrXY + i2), rX, color);
    i2 := i2 + 40;
    end;
    end;

    Przydaje mi się także jako robienie tła pod QR ;)
    Koszt rysowania: 1 tick.
    • 30: CommentAuthortebe
    • CommentTime9 Nov 2019 zmieniony
     
    jeśli chcesz pozbyć się SetPixel i realizować zapalanie bitów to najlepiej skorzystać z trybów które wyświetlają bajt jako 8 oddzielnych pikseli, tryb 8 (HiRes) ale też tryb 6, który ma proporcjonalny piksel jak tryb 7 ale tylko 2 kolory

    w trybie 6 linia ma 20 bajtów szerokości, 20 * 8 = 160 pikseli

    tOra: array [0..7] of byte = ($80,$40,$20,$10,$08,$04,$02,$01);

    ...
    ...

    InitGraph(6);

    for x:=0 to 52 do begin
    k:=dpeek(88) + x shr 3;
    v:=peek(k);
    poke(k, v or tOra[x and 7]);
    end;


    pozycję poziomą X dzielisz /8 aby uzyskać bajt, następnie obliczasz resztę z takiego dzielenia 'X mod 8' aby uzyskać informację o bicie który masz zapalić w bajcie

    'X mod 8' można zastąpić 'X and 7' która to operacja jest znacznie szybsza
    • 31: CommentAuthorzbyti
    • CommentTime9 Nov 2019 zmieniony
     
    @tebe o widzisz! Tej informacji potrzebowałem. Brak znajomości Atari jest mi kulą u nogi ale dzięki takim podpowiedziom chyba to w końcu ogarnę :)

    Już siadam do implementacji! :)

    Dzięki ( ̚‿̚ )

    EDIT: zrobiłem te rysowanie za pomocą dpoke i 4-bit buforem. Nic nie uzyskałem na prędkości, bo dodatkowe operacje na danych je pochłonęły, 4 ticks tak samo jak przy PutPixel.
    • 32: CommentAuthorzbyti
    • CommentTime10 Nov 2019 zmieniony
     
    Dobra... Olać QR-y. Czas zacząć pisać program dla którego w ogóle uczę się Mad Pascala.

    Zaczynam trochę od d... strony ale jak będę miał szachownicę i poruszające się figury to wtedy chętniej będę implementował silnik.

    Tak wiem, że hardcorowi programiści piszą silnik, testują w wierszu poleceń a później podpinają GUI no ale ja nie jestem hardcorem ;P

    Na początek narysowałem szachownicę najszybciej jak potrafię, korzystając ze wskazówki że mod można zastąpić and. Faktycznie 30% przyspieszenia :)

    Gdy rysowałem w trybie 8 za pomocą wbudowanych procedur kwadraty (a właściwie to użyłem samej implementacji wypełnionego kwadratu) to trwało to dość długo bo aż 223 ticki. Szybsza procedura wyświetla się w 28 ticków z czego chyba 10 idzie na samą ramkę wbudowanym rectangle.

    -----------------------------------------------------------

    ROAD MAP

    1. procedura wyśetlająca figury
    2. poruszanie figurami.
    3. generator losowych posunięć
    4. sprawdzanie poprawności posunięć

    Na razie takie cele.

    -----------------------------------------------------------

    program chessboard;
    uses crt, fastgraph;

    var bmpAdr : word;

    procedure drawBoard;
    var i1b, i2b, i3b, color, modLine : byte;
    x, y : smallint;
    begin
    modLine := 0;
    y := 280; // x * 40
    for i3b := 1 to 8 do begin
    for i2b := 1 to 22 do begin
    x := 1;
    for i1b := 1 to 8 do begin
    color := $ff;
    if (i1b and %1 <> modLine) then color := 0;
    dpoke(bmpAdr + y + x, color);
    dpoke(bmpAdr + y + x + 1, color);
    dpoke(bmpAdr + y + x + 2, color);
    x := x + 3;
    end;
    y := y + 40;
    end;
    if (i3b and %1 = 0) then modLine := 0
    else modLine := 1;
    end;
    rectangle(7, 7, 40 * 5, (22 * 8) + 7);
    end;

    begin
    InitGraph(8 + 16);
    SetColor(1);
    TextBackground($ff);
    bmpAdr := dpeek(88);

    drawBoard;
    readkey;
    end.

    {$f $a0} // fastmul at page $a0 ($a000)

    program slow_chessboard;
    uses crt, fastgraph;

    var i1b, i2b, x, y : byte;
    i1i, a : integer;
    bmpAdr : word;

    begin
    InitGraph(8);
    SetColor(1);
    TextBackground(0);
    bmpAdr := dpeek(88);

    x := 20;
    y := 0;
    a := 19;

    rectangle(x, y, x + ((1 + a) * 8), y + (a * 8));
    for i1b := 1 to 4 do begin
    for i2b := 0 to 3 do begin
    for i1i := (a * i2b * 2) + y to a * ((i2b * 2) + 1) + y do hline(0 + x, a + x, i1i);
    for i1i := a * ((i2b * 2) + 1) + y to a * ((i2b * 2) + 2) + y do hline(a + 1 + x, (a * 2) + 1 + x, i1i);
    end;
    x := 2 * (a + 1) + x;
    end;
    end.
    • 33:
       
      CommentAuthorbocianu
    • CommentTime11 Nov 2019
     
    jesteś pewny, że chcesz GUI robić w trybie graficznym?
    myślę, że do szachów spokojnie wystarczy tryb znakowy.
    z plusów wymienię tylko kilka:
    - dużo szybsze operacje na obrazie.
    - dużo mniej zajętej pamięci.

    przemyśl ;)
    • 34: CommentAuthorstc
    • CommentTime11 Nov 2019
     
    Proponuje wygenerować własny zestaw znaków.
    Zrobić plansze w graphisc 0 aka antic 2.
    Ta sama rozdzielczość, a rysowanie szachownicy bardzo przyśpieszy.
    Bardzo fajnie się czyta postępy w projekcie, kibicuje za szachownicą w pełnym 3D ;) w czystym assemblerze.
    Taki zapał i to liczenie szybkości wykonywania programu, że w przysłości bardzo możliwe, że będziesz pisał w samym assemblerze! Polecam , gdy chcesz i wiesz, że pascal już nie daje rady :)
    Lubie turową wojnę ,ale tylko gdy zawiera "mgłę wojny" tzw wielkie gry wojenne coś w stylu "His Dark Majesty".
    Trzymam kciuki, za tydzeń znów będę oddawał się lekturze zmagań!!!
    • 35: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    @bocianu & @stc oczywiście, że skorzystam z Waszych rad. Moje wybory podyktowane są często brakiem doświadczenia a już na pewno nieznajomością możliwości A8.

    Mam nadzieję dzięki Wam i temu projektowi sporo się nauczyć :)

    @stc plan faktycznie jest taki by napisać szachy w Mad Pascalu najpierw. Ogarnąć algorytmy, bebechy Atari etc. a później przepisać to w MADAS już z opcją "pernament brain". Ale czy dotrę aż tak daleko?

    Na ten moment mam pytanie. Jak uniknąć na przyszłość, będąc niedoświadczonym, takich pułapek w jaką wpadłem dziś? ;)

    Powinienem samemu przydzielać pamięć? Jak ją zapełnia MP? Np. więcej informacji tego typu:

    Niezaincjowany wskaźnik najczęściej będzie miał adres $0000, należy zadbać aby przed jego wykorzystaniem zaincjować go adresem odpowiedniej zmiennej.

    Podczas rysowania pionka nie mogłem zrozumieć dlaczego jak korzystałem z tablicy 2D, powiększając wiersz dodawaniem to wszystko było ok, a jak zrobiłem pętlę z mnożeniem to działy się cuda.

    Po jakiejś chwili dotarło do mnie, że dołączone dyrektywą procedury szybkiego mnożenia nadpisują dane albo na odwrót.

    Jak sobie organizować dane? Jakieś dobre praktyki?

    PS 1. W ogóle mam zamiar unikać mnożeń jak ognia ;) Drugi zrzut ekranu pokazuje wynik po zastąpieniu 2 mnożeń dodawaniami.

    PS 2. Dla kawału spakowałem i wrzuciłem tego samego pionka do mojej procedury rysującej QR w trybie 7. Pion też ma 24x24 ale render pomija niezapalone punkty.

    {$f $a0} // fastmul at page $a0 ($a000)
    // poszło dopiero przy $70

    program benchmark;
    uses crt, fastgraph, sysutils;

    var x, y, r : byte;
    k, v : word;
    bmpAdr : word;
    start, stop : cardinal;
    pawn: array [0..23, 0..23] of byte = (
    // $80, $40, $20, $10, $08, $04, $02, $01
    ...
    );

    begin
    //192 rows of 320 dots in the full screen mode.
    InitGraph(8);
    SetColor(1);
    SetBKColor(82);
    TextBackground(80);
    bmpAdr := dpeek(88);

    start := GetTickCount;
    for r := 0 to 7 do begin
    for y := 0 to 23 do begin
    for x := 0 to 23 do begin
    k := bmpAdr + (3 * r) + (y * 40) + x shr 3;
    v := peek(k);
    poke(k, v or pawn[y][x and %11111]);
    end;
    end;
    end;
    stop := GetTickCount;

    writeln('drawing time: ', stop - start);
    ReadKey;

    end.
    • 36: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    Przy większej ilości plików na których trenuję i trzymam w jednym folderze trochę mi się zabałaganiło więc zmodyfikowałem skrypty @bocianu.

    Może się komuś przydadzą te modyfikacje?

    compile.sh
    #!/bin/bash
    mp $1.pas -o
    if [ -f $1.a65 ]; then
    [ ! -d "output" ] && mkdir output
    mv $1.a65 output/
    fi

    build.sh
    #!/bin/bash
    if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
    fi

    mp $1.pas -o

    if [ -f "$1.a65" ]; then
    [ ! -d "output" ] && mkdir output
    mv $1.a65 output/
    cd output
    mads $1.a65 -x -i:/home/zbyti/Programs/MadPascal/base -o:$1.xex
    cd ..
    else
    exit 1
    fi

    if [ ! -z "$2" ]; then
    atari800 output/$1.xex
    fi

    Skrypt buildrun.sh zastąpiłem wywołaniem:
    build.sh code run
    • 37: CommentAuthorilmenit
    • CommentTime11 Nov 2019
     
    Ten mój tool może pomóc zrobić dump zestawu znaków z innych programów szachowych na Atari:
    ->link<-
    • 38: CommentAuthorzbyti
    • CommentTime11 Nov 2019
     
    @ilmenit Dzięki!

    Jedyny zestaw szachowy jaki mi się podoba na A8 ma Colossus 3/4.

    Spróbuję go "wyrypać" tym narzędziem :)
    • 39: CommentAuthorilmenit
    • CommentTime11 Nov 2019
     
    Jak widzę z grafiką kombinowali też tu: ->link<-
    • 40: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    @ilmenit tak, czytałem już kiedyś ten wątek. O ile pamiętam jest tam tyle sztuczek z kolorowaniem, że CPU nie miało by kiedy grać w szachy :D

    Chyba, że czegoś nie załapałem? A może źle pamiętam... ;)

    Dobrze, że mi przpomniałeś, całkiem prosto mogę zrobić "dither for the black squares" a fajnie wygląda :)
    • 41: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    Wprowadziłem jeszcze kilka modyfikacji i aktualnie (według tutka @bocianu) pracuję już w Geany.

    Wygodniej jest mi posługiwać się nazwami plików bez opuszczania rozszerzenia *.pas

    compile.sh
    #!/bin/bash
    if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
    fi

    /home/zbyti/Programs/bin/mp $1 -o
    name=${1::-4}
    fileAsm="${name}.a65"

    if [ -f $fileAsm ]; then
    [ ! -d "output" ] && mkdir output
    mv $fileAsm output/
    fi

    build.sh
    #!/bin/bash
    if [ -z "$1" ]; then
    echo -e "\nPlease call '$0 <argument>' to run this command!\n"
    exit 1
    fi

    /home/zbyti/Programs/bin/mp $1 -o
    name=${1::-4}
    fileAsm="${name}.a65"

    if [ -f $fileAsm ]; then
    [ ! -d "output" ] && mkdir output
    mv $fileAsm output/
    cd output
    /home/zbyti/Programs/bin/mads $fileAsm -x -i:/home/zbyti/Programs/MadPascal/base -o:$name.xex
    cd ..
    else
    exit 1
    fi

    if [ ! -z "$2" ]; then
    atari800 output/$name.xex
    fi

    Geany
    Compile MP  [F8] /home/zbyti/Programs/bin/compile.sh "%f"
    Compile FPC [F9] fpc "%f"
    Execute MP [F5] /home/zbyti/Programs/bin/build.sh "%f" run
    Execute FPC [ ] "./%e"
    • 42: CommentAuthorilmenit
    • CommentTime11 Nov 2019
     
    Przy sposobności, zerknij na źródła mojego "Small Reversi" - pisane w C, ale wiele z tego może Ci się przydać do szachów.
    ->link<-
    Różnica jest głównie taka, ze w Reversi ruch zmienia wiele elementów na planszy, zaś w szachach porusza się jedna figura, więc nie trzeba w drzewie przeszukiwań trzymać całej planszy.
    • 43: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    @ilmenit na pewno zerknę! Fajnie, że podrzucasz swoje materiały :)

    Niestety nie umiem grać w Reversi. Pewnie musiał bym najpierw nauczyć się tej gry by zrozumieć Twój kod.

    Co do szachów i braku potrzeby trzymania w drzewie przeszukiwań całej planszy to pozwolę się nie zgodzić ;) Ale w szczegóły wdam się dopiero jak zacznę implementację.

    EDIT:

    main.c:

    // Those weights are chosen by genetic algorithm and then a bit tuned by me

    @ilmenit powiesz coś więcej? ;) W sensie jak Ci szła implementacja :)
    • 44:
       
      CommentAuthorIRATA4
    • CommentTime11 Nov 2019
     
    @zbyti wybierasz się na SV ?
    • 45: CommentAuthorzbyti
    • CommentTime11 Nov 2019
     
    @IRATA4 niestety nie :( najszybciej pojadę na edycję 2020 :)
    • 46: CommentAuthorMADRAFi
    • CommentTime11 Nov 2019
     
    ja bym zdecydowal sie na tryb textowy, zbudowal wlasny zestaw znakow. Nie znaczy to ze to jest najlepze rozwiazanie pod wzgledem wygldu :)
    • 47: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    @MADRAFi no to skoro każdy praktyk tak radzi to co ja się będę sprzeczał ;)

    No ale to kolejna rzecz jaką muszę ogarnąć przed rozpoczęciem właściwych pracy.

    Z drugiej strony to wciąż jeszcze zabawa i nauka języka więc im więcej napiszę pobocznych rzeczy z tym większym sensem rozpocznę pisanie właściwych.

    OK. Jutro się nauczę podmieniać znak na swój zestaw i wyświetlić jakąś szachownicę. Spróbuję zacząć korzystać z MadStrap.

    EDIT: aaa... jednak najpierw skończę opcję na grafice którą zacząłem ;)
    • 48: CommentAuthormono
    • CommentTime11 Nov 2019 zmieniony
     
    Obawiam się źe przy bierkach 3x3 będziesz musiał użyć 12*2*3*3=216 znaków, co nie zmieści Ci się w generatorze znaków (128 znaków max). Do tego chciałbyś pewnie po prawej stronie szachownicy malować jakieś informacje, więc przydałyby się litery i cyfry + kilka znaków interpunkcyjnych.
    Proponuję użyć 3 generatorów znaków, bo wtedy dla wszystkich bierek będziesz musiał zdefiniować 72 znaki w każdym generatorze. Zostanie Ci 56 znaków na duże litery (26), małe litery (26), cyfry (10) i 10 znaków interpunkcyjnych.
    Przypisanie generatorów do wierszy ekranu (zmiana adresu generatora na DLI):
    0 -+
    1 +- wiersz 8 szachownicy
    2 -+
    0 -+
    1 +- wiersz 7 szachownicy
    2 -+
    ...
    0 -+
    1 +- wiersz 1 szachownicy
    2 -+

    Zakładając umownie, że bierka definiowana jest znakami:
    ABC
    DEF
    GHI

    generator 0 zawiera definicje znaków dla ABC, generator 1 dla znaków DEF, generator 2 dla GHI. I tak dla każdej bierki.
    A,D i G mogą być pod tymi samymi kodami znaków w każdym generatorze (np. 0), B, E i H to samo (np. 1), G,H i I też (np. 2). Wtedy umieszczenie bierki polega na wpisaniu do pamięci ekranu w kolejnych wierszach:
    012
    012
    012
    • 49: CommentAuthorzbyti
    • CommentTime11 Nov 2019 zmieniony
     
    @mono to jednak mogę to robić dalej na grafice? Teraz bierki zajmują mi tyle:

    chessmanPawnW : string = '@((((((((((((((((((((()H((+X((+X(()H((+X((/`((/`((+X(()H(()H((+X((+X((Gf((Gf(';
    chessmanPawnB : string = '@((((((((((((((((()H((*8((,0((,0((*8((,0((0,((0,((,0((*8((*8((,0((D6((H)((H)(';

    Nowa kratka szachownicy ma 24x19 (Colossus też nie ma proporcjonalnej).

    Tą samą procedurą co rysuję mogę je kasować więc opcję poruszania się po szachownicy graficznie mam już rozwiązaną.

    Colossus 3 też wiele szybciej nie rysuje stołu a jest w czystym asm.

    Chcę ogarnąć na początek ten program bez DLI itp.
    • 50: CommentAuthormono
    • CommentTime11 Nov 2019 zmieniony
     
    To Twój wybór. Dane potrzebne do malowania planszy w trybie tekstowym to:
    - 40*24=960 bajtów na pamięć ekranu
    - 8*128*3=3072 bajty na pamięć generatorów,
    - 32 bajty na displaylist,
    - z 50 bajtów na kod przerwań DLI.
    Sumarycznie między 4064 a 4100 bajtów.
    Jeśli zrobisz to w trybie 8 OS to ekran zajmie 40*192=7680, displaylist 202 - sumarycznie 7882 bajty.

    Edit: Pewnie prototyp lepiej zrobić prostszą metodą, czyli malować w grafice. A jak się nie zmieścisz docelowo w pamięci, to wtedy optymalizuj. Bo przecież w szachach najważniejszy jest engine szachowy a nie jakaś tam wizualizacja :)