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.


FILE: súbor ako pole

Ako sa to píše

Action!
BYTE ARRAY meno=FILE "súbor"
BYTE ARRAY meno=FILE "súbor" odkiaľ koľko

Prekladač 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:

Action!
;@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()
RETURN
action26 m-file.act --sim
Action! 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

Action!
BYTE ARRAY meno=PACK FILE "súbor"
BYTE ARRAY meno=PACK [čísla]
Action!
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:

Action!
;@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
RETURN
action26 m-pack.act --sim
Unpacked bytes: 240
########################################
#                                      #
#                                      #
#          ******************          #
#                                      #
########################################

Ako to funguje

S voľbou --verbose prekladač povie, čo spravil:

action26: PACK packed: ZX02, 240 -> 23 bytes

240 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

Action!
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:

Action!
;@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.")
RETURN
action26 m-texts.act --sim
You 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.ptx
action26: rooms.txt -> rooms.ptx (3 text(s), 68 -> 60 bytes, 13 pair(s) in the dictionary)

V programe:

Action!
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.pt2

Formát 2 robí dve veci inak:

V programe sa používajú rutiny s dvojkou na konci:

Action!
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ýstupzbalí súbor (spôsob vyberie sám)
… --algo rle / zx02 / storedpredpíše spôsob
… --columns 40dáta sú obrázok so 40 bajtmi na riadok – skúsi baliť po stĺpcoch
action26 --unpack vstup výstuprozbalí späť
action26 --pack-text vstup výstupzbalí riadky textového súboru
action26 --pack-text2 vstup výstupto isté vo formáte 2 – pri mnohých textoch menej miesta
action26 --pack frame.dat frame.pak
action26: 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 neexistujeerror ACT203
cieľ pre Unpack je menší ako rozbalené dátaprepíše sa pamäť za ním
Print na zbalený textvypíš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 bajtovchyba 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

  1. Zmeň obsah motto.txt a prelož m-file.act znova. Musel si meniť program?
  2. Prelož m-pack.act s --verbose a potom s PACK RLE FILE …. Ktorý spôsob dal menšie dáta?
  3. Pridaj do m-texts.act ďalšie tri vety o miestnostiach a sleduj vo --verbose, ako sa mení pomer.

Zhrnutie

Podrobnejšie: lekcie 38 až 45 v examples/modern/.

Späť: 38. Skrytá pamäť · Ďalej: 40. Hráči a strely