39. Dáta zo súboru a kompresia: FILE, PACK, Unpack, zbalené texty
Rozšírenie action26; programy začínajú riadkom ;@modern (kapitola 35).
Na čo to je
Hra potrebuje obrázky, mapy úrovní a texty. Prepisovať ich do zdrojáka ako čísla v hranatých zátvorkách je otrava. A keď ich je veľa, do pamäte Atari sa nezmestia.
FILEvloží do programu obsah súboru tak, ako je.PACKho vloží zbalený (komprimovaný) – zaberie menej a program si ho za behu rozbalí.- Zbalené texty šetria miesto pri hrách s množstvom textu.
FILE: súbor ako pole
Ako sa to píše
BYTE ARRAY meno=FILE "súbor"
BYTE ARRAY meno=FILE "súbor" odkiaľ koľkoPrekladač súbor prečíta pri preklade a jeho bajty sa stanú počiatočnými hodnotami poľa. Nepovinné čísla vyberú len časť súboru: od ktorého bajtu a koľko bajtov.
Súbor sa hľadá ako pri INCLUDE – vedľa zdrojáka a v priečinkoch z voľby -I.
Celý program
Súbor examples/motto.txt obsahuje jeden riadok textu ukončený znakom ~:
Action! is fast, small and readable.~Súbor examples/m-file.act:
;@modern
; FILE: the bytes of a file become part of the program
BYTE ARRAY motto=FILE "motto.txt"
PROC Main()
PrintU(motto, '~) ; the text in the file ends with ~
PutE()
RETURNaction26 m-file.act --simAction! is fast, small and readable.Ako to funguje
Po preklade je text súčasťou programu – na Atari už súbor motto.txt netreba. Pole motto má toľko prvkov, koľko mal súbor bajtov. Vypisuje sa cez PrintU (kapitola 36), lebo to nie je reťazec s dĺžkovým bajtom.
Najčastejšie sa takto vkladajú obrázky: BYTE ARRAY picture=FILE "title.mic" a potom MoveBlock do pamäte obrazovky.
PACK a Unpack: zbalené dáta
Ako sa to píše
BYTE ARRAY meno=PACK FILE "súbor"
BYTE ARRAY meno=PACK [čísla]veľkosť=Unpack(meno, kam)PACK pred zdrojom dát povie prekladaču, aby ich uložil zbalené. Unpack ich za behu rozbalí na adresu kam a vráti, koľko bajtov rozbalil. Cieľ musí mať miesto na celé rozbalené dáta.
Spôsob balenia vyberie prekladač sám – ten, s ktorým je celý program najmenší. Dá sa aj predpísať: PACK RLE … alebo PACK ZX02 ….
Celý program
Súbor frame.dat má 240 bajtov: šesť riadkov po 40 znakov, ktoré tvoria rám.
Súbor examples/m-pack.act:
;@modern
; PACK: data stored packed, unpacked when the program runs
BYTE ARRAY packed=PACK FILE "frame.dat" ; 240 bytes: 6 rows of 40
BYTE ARRAY picture(240)
PROC Main()
CARD size, i
size=Unpack(packed, picture)
Print("Unpacked bytes: ")
PrintCE(size)
FOR i=0 TO size-1
DO
Put(picture(i))
IF i MOD 40=39 THEN
PutE()
FI
OD
RETURNaction26 m-pack.act --simUnpacked bytes: 240
########################################
# #
# #
# ****************** #
# #
########################################Ako to funguje
S voľbou --verbose prekladač povie, čo spravil:
action26: PACK packed: ZX02, 240 -> 23 bytes240 bajtov sa zbalilo do 23. Dáta s dlhými úsekmi rovnakých bajtov – a také sú obrázky aj mapy – sa balia veľmi dobre.
Kedy sa to oplatí. K zbaleným dátam sa do programu pribalí rozbaľovacia rutina (asi 140 až 470 bajtov podľa spôsobu balenia). Pri 240 bajtoch dát je teda program so PACK v skutočnosti väčší ako s obyčajným FILE. Pri obrázku cez celú obrazovku je to naopak: 7680 bajtov sa zbalí na niekoľko stoviek. Prekladač to pri automatickom výbere počíta – keď sa balenie neoplatí, uloží dáta nezbalené.
Zbalené texty
Na čo to je
Textová hra má desiatky viet, v ktorých sa opakujú tie isté slová. Zbalené texty ukladajú najčastejšie dvojice znakov do spoločného slovníka a v textoch ich nahrádzajú jedným bajtom.
Ako sa to píše
CHAR ARRAY meno=PACK "text"
PrintPacked(meno) ; vypíše
PrintPackedE(meno) ; vypíše a ukončí riadok
PrintPackedE("text") ; text priamo vo volaní sa zbalí tiež
UnpackText(meno, reťazec) ; rozbalí do obyčajného reťazca
Celý program
Súbor examples/m-texts.act:
;@modern
; Packed texts: the words that repeat are stored once
CHAR ARRAY hall=PACK "You are in the hall of an old house. There is a door to the north."
CHAR ARRAY kitchen=PACK "You are in the kitchen of an old house. There is a door to the south."
PROC Main()
CHAR ARRAY plain(100)
PrintPackedE(hall)
PrintPackedE(kitchen)
PrintPackedE("You are in the garden of an old house. There is a door to the west.")
UnpackText(hall, plain) ; into an ordinary string
Print("The first text has ")
PrintB(plain(0))
PrintE(" characters.")
RETURNaction26 m-texts.act --simYou are in the hall of an old house. There is a door to the north.
You are in the kitchen of an old house. There is a door to the south.
You are in the garden of an old house. There is a door to the west.
The first text has 66 characters.Ako to funguje
S --verbose:
action26: PACK texts: 3 text(s), 205 -> 121 bytes with the dictionary of 40 pair(s)Tri vety majú spolu 205 znakov a zaberú 121 bajtov vrátane slovníka. Čím viac textov a čím viac sa v nich slová opakujú, tým väčšia úspora.
Zbalený text nie je reťazec Action!: Print, SCompare ani indexovanie s ním nefungujú. Vypisuje sa rutinami PrintPacked…; keď ho potrebuješ ako reťazec, rozbaľ ho cez UnpackText.
Texty v samostatnom súbore
Texty hry sa pohodlnejšie píšu do obyčajného textového súboru, jeden text na riadok. Zbalí ho nástroj:
action26 --pack-text rooms.txt rooms.ptxaction26: rooms.txt -> rooms.ptx (3 text(s), 68 -> 60 bytes, 13 pair(s) in the dictionary)V programe:
BYTE ARRAY rooms=FILE "rooms.ptx"
UsePackedTexts(rooms) ; odteraz platí slovník tohto súboru
PrintPackedE(PackedText(rooms, 2)) ; text číslo 2 (číslujú sa od 0)
UsePackedTexts(0) prepne späť na slovník textov napísaných v programe.
Formát 2: menej miesta pri mnohých textoch
Hra s celými stovkami textov ušetrí ešte viac, keď ich zbalí vo formáte 2:
action26 --pack-text2 rooms.txt rooms.pt2Formát 2 robí dve veci inak:
- Kód dostanú len znaky, ktoré v textoch naozaj sú. Ostatné kódy idú na dvojice – a čím viac dvojíc, tým kratšie texty.
- Súbor si nepamätá miesto každého textu, len každého šestnásteho. Ostatné nájde tak, že preskočí najviac 15 textov pred hľadaným.
V programe sa používajú rutiny s dvojkou na konci:
BYTE ARRAY rooms=FILE "rooms.pt2"
UsePackedTexts2(rooms) ; odteraz platia texty tohto súboru
PrintPackedE(PackedText2(rooms, 2)) ; text číslo 2
UsePackedTexts2(0) prepne späť na texty napísané v programe. UsePackedTexts2 vezme aj súbor z obyčajného --pack-text; pre ten ostáva PackedText.
Kedy sa to oplatí? Rutiny formátu 2 sú o asi 200 bajtov väčšie a tabuľka znakov tiež niečo stojí, takže pár krátkych viet (ako v rooms.txt hore) vyjde vo formáte 2 dokonca väčších. Pri textoch celej hry je to naopak – napríklad 814 textov hry Ataristův protiútok zaberie 24 814 bajtov namiesto 26 726, o 7 % menej.
Nástroje na príkazovom riadku
Dáta sa dajú zbaliť aj mimo programu – napríklad súbor, ktorý si program načíta z diskety:
| Príkaz | Čo robí |
|---|---|
action26 --pack vstup výstup | zbalí súbor (spôsob vyberie sám) |
… --algo rle / zx02 / stored | predpíše spôsob |
… --columns 40 | dáta sú obrázok so 40 bajtmi na riadok – skúsi baliť po stĺpcoch |
action26 --unpack vstup výstup | rozbalí späť |
action26 --pack-text vstup výstup | zbalí riadky textového súboru |
action26 --pack-text2 vstup výstup | to isté vo formáte 2 – pri mnohých textoch menej miesta |
action26 --pack frame.dat frame.pakaction26: frame.dat -> frame.pak (RLE+, rows of 40, 240 -> 15 bytes, 6%)Takto zbalený súbor rozbalí na Atari tá istá rutina Unpack, keď ho program načíta do pamäte.
Keď meno výstupu končí na .w8p, vznikne súbor vo formáte W8P – formát obrázkov z programu mic2w8p, používaný v niektorých hrách. Na Atari ho rozbalia rutiny UnpackW8P(súbor, kam, najviac) z pamäte a UnpackW8PD(kanál, kam, najviac) z otvoreného súboru.
Prehľad rutín
| Rutina | Čo robí |
|---|---|
Unpack(zbalené, kam) | rozbalí dáta z PACK alebo z --pack; vráti veľkosť |
UnpackRLE(zbalené, kam), UnpackZX02(zbalené, kam) | to isté pre jeden konkrétny spôsob balenia – menší program |
PackRLE(odkiaľ, koľko, kam) | zbalí pamäť priamo na Atari; vráti dĺžku |
PrintPacked(text), PrintPackedE(text) | vypíše zbalený text |
PrintPackedD(kanál, text), PrintPackedDE(…) | to isté na kanál |
UnpackText(text, reťazec) | rozbalí zbalený text do reťazca |
UsePackedTexts(súbor), PackedText(súbor, číslo) | texty zo súboru z --pack-text |
UsePackedTexts2(súbor), PackedText2(súbor, číslo) | texty zo súboru z --pack-text2 |
UnpackW8P(…), UnpackW8PD(…) | súbory W8P |
Časté chyby
| Čo sa stalo | Čo sa stane |
|---|---|
súbor pre FILE neexistuje | error ACT203 |
cieľ pre Unpack je menší ako rozbalené dáta | prepíše sa pamäť za ním |
Print na zbalený text | vypíše nezmysel |
Unpack na dáta, ktoré nie sú zbalené | Err: 105, ak nesedí hlavička; inak program zapíše nezmysly kamkoľvek |
| zbalený text dlhší ako 255 bajtov | chyba prekladu – rozdeľ ho |
súbor z --pack-text2 s UsePackedTexts a PackedText (alebo naopak) | vypíše nezmysel alebo nič – k formátu 2 patria rutiny s dvojkou |
zdroj a cieľ Unpack sa prekrývajú | poškodené dáta |
Vyskúšaj si
- Zmeň obsah
motto.txta preložm-file.actznova. Musel si meniť program? - Prelož
m-pack.acts--verbosea potom sPACK RLE FILE …. Ktorý spôsob dal menšie dáta? - Pridaj do
m-texts.actďalšie tri vety o miestnostiach a sleduj vo--verbose, ako sa mení pomer.
Zhrnutie
=FILE "súbor"vloží bajty súboru do poľa pri preklade.=PACK …ich vloží zbalené;Unpack(pole, kam)ich rozbalí.- Balenie sa oplatí pri väčších dátach – rozbaľovacia rutina tiež niečo zaberá.
CHAR ARRAY t=PACK "text"je zbalený text; vypisuje sa cezPrintPacked….--pack,--unpacka--pack-textrobia to isté so súbormi na PC;--pack-text2zbalí veľa textov tesnejšie.
Podrobnejšie: lekcie 38 až 45 v examples/modern/.
Späť: 38. Skrytá pamäť · Ďalej: 40. Hráči a strely