mike na hračke

som spektrista

Landscape generator Basic

2012-02-15 od mikezt

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 2^(i-1) bodov. Prvý bod iterácie má index 256/2^(i-1) a každý ďalší bod má index zväčšený o 256/2^i.

Na vygenerovanie bodu ale potrebujeme aj predchádzajúce body. Ak x je index bodu, ktorý chceme vygenerovať, potom prvý bod získame ako x-256/2^(i-1) a druhý ako x+256/2^(i-1).

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




- 1 = jedna

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

mikezt (2012-02-16):

Paráda, vďaka. Pridal som tapku s tvojím patchom na koniec článku.