Landscape generator Basic
Pokušenie prepísať generátor krajiny do Basicu bolo veľké a tak som opäť naštartoval emulátor a moje snaženie Vám priblížim v tomto článku.
Ako prvé som použil presne ten istý systém, ako v generátore krajiny v assembleri, teda posúvanie dát v poli. Výhody Basicu sa prejavili naplno a program bežal takmer na prvé napísanie. Problém bol ale v rýchlosti, krajina sa vygenerovala za niečo viac ako tri a pol minúty. Program vlastne väčšinu času nerobil nič iné, ako v slučke posúval vygenerované dáta. V assembleri to moc nevadí, ale v Basicu je to prinajmenšom lamerina. Preto bolo treba zobrať do ruky pero a papier a trošku popremýšľať (au, aj keď až tak hrozné to nebolo).
Takže ak sa chceme zbaviť presúvania dát, treba ich generovať na správne miesta v poli. Vypíšme si teda indexy prvých generovaných dát a pohľadajme nejaké súvislosti.
0: 0 256 1: 128 2: 64 192 3: 32 96 160 224 4: 16 48 80 112 144 176 208 240
Na začiatku riadka je číslo iterácie. Nultá iterácia je inicializácia poľa, kde vygenerujeme krajné body. Potom v každej ďalšej iterácii vygenerujeme bodov. Prvý bod iterácie má index a každý ďalší bod má index zväčšený o .
Na vygenerovanie bodu ale potrebujeme aj predchádzajúce body. Ak x je index bodu, ktorý chceme vygenerovať, potom prvý bod získame ako a druhý ako .
Všimnite si ešte, že pri inicializácii generujeme body na indexy 0 a 256 (resp. v Basicu na 1 a 257). Je to preto, lebo potrebujeme aby vzdialenosť od oboch predchádzajúcich bodov bola rovnaká. Predstavte si napr. pole o štyroch prvkov:
0 1 2 3
Ktorý prvok je v strede? Snáď je to zrozumiteľné. V skutočnosti o nič nejde, vygenerujeme len o jeden bod viac.
Tak a teraz k samotnému programu. Tu je:
20 DEF FN a(q,w,e)=q+(w-q)/2+175*RND/(2^e) 110 DIM x(257): LET x(1)=RND*175: LET x(257)=RND*175 200 FOR i=0 TO 7 210 FOR z=0 TO 2^i-1 220 LET l=256/(2^i): LET m=l/2+z*l+1 230 LET x(m) =FN a(x(m-l/2),x(m+l/2), i+1) 233 IF x(m)<0 THEN LET x(m)=0 235 IF x(m)>175 THEN LET x(m)=175 237 PLOT m-1,0: DRAW 0,x(m) 240 NEXT z 250 PRINT AT 0,0;i 260 NEXT i 280 PAUSE 0 281 RUN
Na riadku 20 si zadefinujem funkciu a, ktorá má parametre q - prvý bod, w - druhý bod, e - iterácia. Ak sa Vám zdajú generované krajinky moc uletené k okrajom, tak skúste prepísať funkciu na:
20 DEF FN a(q,w,e)=q+(w-q)/2+175*RND/(2^(e+1))
Na riadku 110 prebehne naša nultá iterácia a potom už nasledujú cykly iterácie a prechodu prvkov v iterácii. Zápis matematických funkcií nesedí s teóriou vyššie, pretože Basic indexuje pole od 1 a číslovanie iterácií som zvolil od 0. Na riadku 237 sa práve vygenerovaná hodnota hneď vykreslí, takže je vidieť, ako algoritmus funguje.
Update: Opäť som to prehliadol. Vo funkcii, ktorá počíta nové hodnoty sa negenerujú záporné čísla. Treba to opraviť takto:
20 DEF FN a(q,w,e)=q+(w-q)/2+(1-2*RND)*175*RND/(2^e)
land2.tap - tapka s programom.
land3.tap - tapka s patchom od ub880d
mikezt (2012-02-16):
Paráda, vďaka. Pridal som tapku s tvojím patchom na koniec článku.
ub880d (2012-02-15 19.52):
skus aplikovat tento diff, vykresli to za menej ako polovicu casu: ------->
8------ 1c1,3
1 DEF FN t()=PEEK 23672+256*PEEK 23673+PEEK 23674
> 10 LET t1=FN t()
> 20 DEF FN a(q,w,e)=q+(w-q)/2+175*(1-2*RND)/(2*e) 3a6
> 205 LET f=2^i: LET l=128/f
5,6c8,9
220 LET m=l+2*z*l+1
> 230 LET x(m)=FN a(x(m-l),x(m+l),f)
12a16
> 270 PRINT FN t()-t1 -------8