Programátoři z pekel zde za šat a stravu programují čipová pseuda. Nyní s favicon!

Programujeme v BASICu: Seriózní programy (1)

Podívám-li se na těch zhruba dvacet let, po které mám ZX Spectrum, byla to pro mě vždycky pouze nepracovní platforma. Nemám na mysli práci ve smyslu zdroje obživy, ale prostě jen jakoukoliv seriózní činnost, která nezahrnuje paření všeho možného, sledování dem a poslouchání chiptunes. Nikdy jsem na Spectru nepsal dlouhé a kvalitně formátované texty ani jsem je netisknul na tiskárně. Nezakládal jsem databáze. Neprogramoval ve Forthu ba ani Pascalu. Neprováděl sofistikované výpočty. Až Dex mi svým článkem otevřel oči a já se to teď pokusím napravit. Konec programování bezduchých hříček, pojďme na to seriózně!

Vzdor většinovému názoru, já považuju dobu, v níž si každý musel svůj specifický program vytvořit sám, za lepší. Dotyčný odborník věděl nejlépe, co má jeho program dělat a jen musel zjistit, jak počítač donutit, aby to dělal. Komunikace specialista-počítač pak byla čiště formální a případné mýlky končily ihned chybovou hláškou. Pořízení programu stálo jen odborníkův čas, nikoliv jeho peníze. Dnes si specialista musí nechat software vytvořit programátorem, může si nechat customizovat pro své potřeby software obecnější nebo použije software zcela standardní a přizpůsobí se mu. Pořízení takového software ho stojí vždycky peníze i čas, protože v prvním případě musí zkusit vysvětlit programátorovi co má program dělat, v druhém customizátorovi jak ho potřebuje upravit a ve všech třech se musí s programem učit zacházet.

Nechme ale současnost současností a pojďme tam, kde si každý mohl užitečný program naprogramovat sám. Pokusím se vám v několika následujících článcích ukázat sadu algoritmů pracujících v Sinclair BASICu s geografickými daty a na nich postupně postavíme několik funkčních programů.


Import dat
Základním kamenem libovolného užitečného programu jsou data. Data jsou kvantifikované „něco“, co chceme ze světa mimo počítač dostat do počítače, nějakým způsobem zpracovat a opět prezentovat do světa mimo počítač – zobrazením na obrazovce, tiskem, hvízdáním na beeper, atd.
Nemá smysl řešit, jak by se asi geografická data do ZX Spectra dostala v 80.letech. Tehdy je složitě pořizovali pouze geodeti a něco jako GPS na úrovni dnešních čipů v mobilech neměla ani mocná lidová armáda. Oprostíme se i od moderních XML vymyšleností a použijeme starý dobrý formát CSV, tedy čárkou oddělené hodnoty. Předpokládaný soubor s daty obsahuje na každém řádku nejdříve číslo udávající zeměpisnou šířku (osa sever-jih) a za ním čárkou oddělenou zeměpisnou délku (osa východ-západ). Řádek je ukončen znakem s ASCII kódem 10 (LF), soubor pak končí znakem s kódem 35 (#). Není problém takový soubor vytvořit na vícebitu konverzí z GPX i v prostinkém textovém editoru a mřížku na konec doplnit ručně. Soubor na Spectru nahrajeme od adresy 49152 a zpracovat jej můžeme následujícím programem:

1000 DIM p(2,512)
1010 PRINT AT 0,0;"Nactene body:"
1020 LET m=49152: LET i=1
1030 LET a$=""
1040 LET b=PEEK (m): IF b<>44 THEN LET a$=a$+CHR$ (b): LET m=m+1: GO TO 1040
1050 LET p(1,i)=VAL (a$): LET a$="": LET m=m+1
1060 LET b=PEEK (m): IF b<>10 THEN LET a$=a$+CHR$ (b): LET m=m+1: GO TO 1060
1070 LET p(2,i)=VAL (a$): LET m=m+1
1080 PRINT AT 0,14;i
1090 IF PEEK (m)<>35 THEN LET i=i+1: GO TO 1030

Jak asi patrno, program jde bajt po bajtu od adresy 49152, načítá do textové proměnné znaky dokud nenarazí na čárku respektive na konec řádku, v textové podobě načtené číslo konvertuje do floatu prostřednictvím funkce VAL a výsledek uloží do dvourozměrného pole p(). Vše se opakuje tak dlouho dokud se nedojde na konec souboru (#). Pro soubor, který je na konci článku odkazovaný jako ukázkový, trvá import zhruba 2m 20s, není to tedy zrovna rychlovka a vyplatí se po prvním zpracování data uložit prostřednictvím SAVE "p" DATA p().


Hledání rohů
Data jsou úspěšně načtena a abychom je mohli zobrazit, je třeba vhodně zobrazit zeměpisné souřadnice do grafických souřadnic. Prvním krokem je nalezení rohů zobrazované oblasti, tedy minimální a maximální zeměpisné šířky a délky. Projdeme prvky tedy načteného pole a tyto čtyři hodnoty najdeme.
Následně už pak není složité převést rozsah (xmax-xmin) do 256 bodů horizontálního rozlišení obrazovky a rozsah (ymax-ymin) do 176 bodů vertikálního rozlišení:

1100 PRINT AT 1,0;"Hledani rohu:"
1110 LET ymin=p(1,1): LET xmin=p(2,1): LET ymax=0: LET xmax=0
1120 FOR a=1 TO i
1130 IF p(1,a) > ymax THEN LET ymax=p(1,a)
1140 IF p(2,a) > xmax THEN LET xmax=p(2,a)
1150 IF p(1,a) < ymin THEN LET ymin=p(1,a) 1160 IF p(2,a) < xmin THEN LET xmin=p(2,a) 1170 PRINT AT 1,14;a 1180 NEXT a 1190 PRINT "Levy spodni: ";ymin;", ";xmin 1200 PRINT "Pravy horni: ";ymax;", ";xmax 1210 LET rx=xmax-xmin: LET ry=ymax-ymin 1220 LET rx=253/rx: LET ry=173/ry


Vizualizace dat
Co dělat s geografickými daty, než je zobrazit a to nejlépe v podobě mapy? Nic lepšího mě nenapadá, pojďme na to rovnou:

1300 PRINT "Stisknete cokoliv pro pokracovani": PAUSE 0: CLS
1310 FOR a=1 TO i-1
1315 PLOT 1+(p(2,a)-xmin)*rx, 1+(p(1,a)-ymin)*ry
1320 DRAW rx*(p(2,a+1)-p(2,a)),ry*(p(1,a+1)-p(1,a))
1330 NEXT a

Zde upozorním na věc, které si bystrý čtenář jistě povšiml: v předminulém odstavci píšu o 256 resp. 176 bodech a řádek 1220 počítá s čísly 253 resp. 173. Důvodem je rozdíl v tom, jak Sinclair BASIC kreslí body a čáry. Zatím co souřadnice bodu (příkaz PLOT) se zadávají absolutně, čára (příkaz DRAW) se zadává relativně - kreslí se z aktuálního bodu do bodu vzdáleného x pixelů horizontálně a y pixelů vertikálně. Pokud převádíme body zadané pomocí floatových čísel do bodů určených celočíselně, může někde dojít k zaokrouhlovací chybě. Pokud budeme kreslit trasu mezi 135 body (tolik jich je v níže linkovaném souboru), chyba se neustále kumuluje a výsledná trasa pak může vypadat dosti jinak, než vypadala v reálu. Při vykreslování jsem problém vyřešil tak, že vždy nakreslím nejdříve bod a z něj čáru k dalšímu bodu - nekreslím celou trasu pouze pomocí příkazu DRAW z jednoho počátečního bodu. Vznikne tím občas jednopixelová chyba, která je sice viditelná, ale trasa ve výsledku vypadá mnohem lépe (zkuste si to, kód si upravte a sami uvidíte). Jeden pixel po obvodu jsem pak nechal právě pro takovéto zbloudilé špatně zaokrouhlené body (253+2=255 a 0-255=256 bodů, totéž platí pro druhou osu).


Hned příště si ukážeme, k čemu může být dnešní kód dobrý. Napovědět může už vzorový soubor s body, data v něm obsažená totiž budou použita minimálně ve třech dalších dílech. Tady je. Schválně, kdo první přepíše zdroják do Spectra či emulátoru a hodí do komentářů obrázek toho, co program nakreslil?