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

Programujeme v BASICu: Dialogové hry (3)

Když jsem přemýšlel nad pokračováním BASICového seriálu, došel jsem k poznání, že to musí být něco velkého, od posledního dílu už totiž uplynulo hodně vody. Smetl jsem ze stolu ideu vlastního klonu hry Chammurapi, protože mezopotámským vládcem se dnes nestanete ani omylem a místo toho se pustil do realizace simulátoru finančního světa.

Peníze se rozmnožují na kapitálových trzích.
–mikezt, 2005

V dobách, kdy ještě bylo ZX Spectrum mým jediným počítačem, jsem často hrával proximáckou hru Akcionář. Kdysi kdesi jsem četl, že se jedná jen o kompilovaný BASIC. Šlo-li to jednou, půjde to jistě znovu, a proto jsem se rozhodl zjednodušeně napodobit právě Akcionáře.


Malé intermezzo
Abych umlčel commodoristické nářky, že používám v BASICu příkazy, které jejich škatule neumí (jako je například exotický příkaz kreslící čáru či kružnici), rozhodl jsem se pořídit si emulátor této „nejpopulárnější osmibitové platformy“ a sepsat dnešní program na něm.
Ještě nikdy nebylo stráveno tolik času psaním tak mála řádků. Důvodů je hned několik:

  • blbý editor
  • blbý BASIC
  • blbá platforma
  • blbý emulátor

BASIC na C64 je dílem Microsoftu, i když to v něm zjevně nikde není uvedené. Programového nadávání na MS jsem dalek, obě dvě funkční věci v jejich historii uznávám, ale tento BASIC se k nim nemůže počítat ani náhodou. Už při editaci si člověk uvědomí, jak vysokou úroveň má editor na ZX Spectru.
Pokud jsem dobře pochopil dokumentaci, skládá se program z virtuálních řádků. Každý virtuální řádek jsou dva řádky obrazovky, celkem tedy 80 znaků. Přes tento počet vlak nejede, delší řádek prostě nezadáte. Rovnou můžeme vyřadit z repertoáru krásné konstrukce, v nichž se FOR cyklus píše do jednoho řádku, protože jeho obsah k sobě významově i funkčně patří.
Stejně na tom je i samotný jazyk. Před GOTO po IF je možno vynechat THEN, ovšem GOSUB už takovéto privilegium nemá. Ani u GOTO ani u GOSUB se mi nepodařilo skákat na výrazem vypočtenou hodnotu řádku, pouze na konstatu, alespoň tady jsou si příkazy rovny. Zvlášnosti příkazu TAB by zasloužily samostatný výzkumný grant, laboratoř a vědeckou skupinu. Nevím přesně – a nevěděl to ani dotazovaný Commodorista – jak to má fungovat a k čemu to má být, ale k formátování textového výstupu to vhodné rozhodně není. Nezbylo než si funkcionalitu, kterou jsem chtěl od TAB, nakonec pomocí SPC udělat sám.
Možná budu příliš extrémní, ale pokud je všeobecná programátorská averze k BASICu vyvolána tímhle zvěrstvem, pak ji plně chápu. Při psaní jsem soustavně měl pocit, jako by mi někdo přerazil obě ruce, zavázal oči a nechal psát program pouze po čichu. Jeden týden s C64 a už ho nechci nikdy vidět znovu.
Vraťme se ale zpátky k tématu.


1 print chr$(147)
10 dim trh(4,4):k=1:h=10000:dim akc(4):r=0.5
20 for m=0 to 3:akc(m)=0
30 for i=0 to 3:trh(m,i)=int(100*(10+i*10+(2-4*rnd(4))))/100:next i:next m
40 q=0:a=5:t=5:c=0
50 print "hotovost:";h;tab(30);"kolo:";k:print
60 print "majetek":gosub 9999
70 for m=0 to 3:d=len(str$(akc(m)))
80 print "akc";m;spc(8-d);akc(m);"ks";spc(3)
90 next m: print
100 print "informace o trzich":gosub 9999
110 for m=0 to 3:print tab(8+8*m);"akc";m;:next m:print:gosub 9999
120 for m=0 to 3:print "trh";m;
130 for i=0 to 3:print spc(7-len(str$(trh(m,i))));trh(m,i);:next i
140 print: next m:gosub 9999
200 print "1-koupit, 2-prodat, 3-nic, 0-konec"
210 input c
220 if c<0 or c>3 goto 210
230 if c=1 then gosub 1000
240 if c=2 then gosub 1100
250 if c=3 goto 300
260 if c=0 then gosub 9900
300 x=int(8*rnd(32))
310 print
320 if x=0 then gosub 2100
330 if x=2 then gosub 2200
340 if x=4 then gosub 2300
350 if x=6 then gosub 2400
360 gosub 2000
990 if (k-int(k/10)*10)=0 then h=h-4000:print "probehlo zuctovani poplatku."
995 if h<=0 then print "zbankrotoval jsi, nemas zadne penize.": goto  9900
999 print:k=k+1: goto 40
1000 rem nakup akcii
1010 gosub 9100: gosub 9150
1020 gosub 9200
1030 if q*trh(t,a)> h then print "nemas dostatek penez":goto 1020
1040 akc(a)=akc(a)+q: h=h-q*trh(t,a)
1050 return
1100 rem prodej akcii
1110 gosub 9100: gosub 9150
1120 gosub 9200
1130 if q>akc(a) then print "tolik akcii nemas!": goto 1120
1140 akc(a)=akc(a)-q:h=h+trh(t,a)*q
1150 return
2000 rem sub normalni vyvoj trhu
2010 for m=0 to 3: for i=0 to 3
2020 trh(m,i)=int(100*(trh(m,i)+(0.5-rnd(64))))/100
2030 if trh(m,i)<=0 then gosub 3000
2040 next i: next m
2050 return
2100 rem sub krize jedne spolecnosti
2110 i=int(4*rnd(24))
2120 print "odhaleny podvody ve spolecnosti";i;"."
2130 print "ceny akcii prudce klesaji."
2140 b=10*rnd(80)
2150 for m=0 to 3: trh(m,i)=int(100*(trh(m,i)-b))/100:next m
2160 return
2200 rem sub rust jedne spolecnosti
2210 i=int(4*rnd(24))
2220 print "novy produkt spolecnosti";i;"je trhak."
2230 print "ceny akcii prudce stoupaji."
2240 b=10*rnd(80)
2250 for m=0 to 3: trh(m,i)=int(100*(trh(m,i)+b))/100:next m
2260 return
2300 rem sub recese na jednom trhu
2310 m=int(4*rnd(24))
2320 print "ekonomika trhu ";m;"upadla do recese."
2330 print "ceny vsech akcii na trhu prudce klesaji."
2340 b=10*rnd(80)
2350 for i=0 to 3: trh(m,i)=int(100*(trh(m,i)-b))/100:next i
2360 return
2400 rem sub konjunktura na jednom trhu
2410 m=int(4*rnd(24))
2420 print "ekonomika trhu ";m;"zaziva konjunkturu."
2430 print "ceny vsech akcii na trhu prudce rostou."
2440 b=10*rnd(80)
2450 for i=0 to 3: trh(m,i)=int(100*(trh(m,i)+b))/100:next i
2460 return
3000 print "spolecnost";i;"zkrachovala. ";
3010 print "na jeji misto ihned nastoupil konkurencni podnik."
3020 b=int(50*rnd(48))
3030 for n=0 to 3:trh(n,i)=int(100*(b+(2-4*rnd(96))))/100:next n
3040 akc(i)=0
3050 return
9100 rem sub pro nacteni akcie
9110 print "kterou akcii [0-3]?"
9120 input a
9130 if a>3 or a<0 goto 9110
9140 return
9150 rem subr pro nacteni trhu
9160 print "na jakem trhu [0-3]?"
9170 input t
9180 if t>3 or t<0 goto 9160
9190 return
9200 rem subr pro nacteni kusu
9210 print "kolik kusu?"
9220 input q
9230 if q<0 goto 9220
9240 return
9900 print:print "konec hry":end
9999 print "---------------------------------------":return

Jak to funguje?
Doufám, že dobře. Děkuji za optání. Hra vychází z prostého principu, kterým lze filosoficky pojmout veškeré jsoucno: Čemu nerozumím, to mohu považovat za náhodné nebo alespoň pseudonáhodné. A jelikož dění ve finančním světě nerozumí ani sami finančníci (kdyby ano, nebyly by krize), pak je zřejmé, že stěžejním bodem celé hry je funkce RND. Jelikož je mi pravidelně vštěpováno, že C64 má kvalitní generátor náhodných čísel, založený na čipu SID a bílém šumu, mohla by to být i celkem zábava.

Akcionar na C64

Hráč na počátku dostává 10000 USD a může obchodovat na čtyřech trzích s akciemi čtyř společností. Cena jednoho druhu akcie je na každém trhu jiná a i když jsou z počátku nastaveny velmi podobně, mohou se postupem času rozeběhnout každá jinam, v podstatě to bude záležet jen na rozložení čísel vašeho náhodného generátoru. V každém kole se totiž k ceně přičítá číslo z intervalu (-0.5,0.5) a to ke každé z šestnácti cen jiné (4 akcie x 4 trhy).
Kromě tohoto chaotického dění je tu ještě zhruba 50% pravděpodobnost, že dojde k některé ze čtyř událostí:

  1. Pád jedné společnosti - v důsledku odhalení finančních podvodů cena akcií společnosti klesá na všech trzích o číslo z intervalu 0 až 10 USD, podle libovůle vašeho RND.
  2. Vzestup jedné společnosti - nově uvedený produkt způsobí akciové nákupní šílenství, cena akcií dané společnosti roste na všech trzích. Interval je stejný jako v předchozím bodu, jen znaménko je opačné.
  3. Recese na trhu - v důsledku recese už obchody na daném trhu nejdou tak dobře jako dřív. Cena u všech produktů na jednom trhu klesá. Platí stejný interval jako v prvním bodu.
  4. Konjunktura na trhu - náhlé zlepšení stavu ekonomiky se projevilo zvýšným zájmem o burzovní obchody. Ceny všech akcií onoho šťastného trhu rostou o hodnotu vybranou ze stejného intervalu, jako v předchozích bodech.

Je mi jasné, že tyto čtyři situace jsou hrubým zjednodušením. Také je nabíledni, že by se nemělo jednat o jednorázové cenové skoky, nýbrž o nastavení postupně mizejícího trendu pro více kol, ale to by znamenalo minimálně jedno další dvourozměrné pole a několik dalších algoritmů. Pokud případný puntičkářský čtenář touží, může si takové úpravy dodělat sám, já jsem už ani sobě ani Commodoru nechtěl takové trápení nadělovat.

Hra dále stojí i na několika dalších principech, o kterých je třeba se zmínit:

  • V každém kole můžete jednou nakoupit nebo jednou prodat nebo nedělat nic a vyčkat, kam se trhy v příštím kole pohnou.
  • Přístup na trhy není bezplatný, a tak i když neobchodujete, zaplatíte každých 10 kol na každém z trhů tisícidolarový poplatek, celkem tedy musíte za deset kol vydělat alespoň 4000USD, jinak se neodvratně nasměrujete k bankrotu.
  • I když jsou ceny akcií jedné společnosti na různých trzích na sobě nezávislé, je to stále jedna společnost, takže pokud hodnota klesne někde na nulu, pak společnost zbankrotuje globálně, vy přijdete o všechny peníze do jejích akcií investované a na její místo nastoupí společnost nová, s novými cenami a novou zářivou budoucností.

Pokud mě paměť neklame, jsou toto všechna pravidla, se kterýma se hráč musí potýkat. Vše ostatní už je (tak jako ve skutečnosti) o šikovnosti, štěstí a náhodě. Program sám není nijak komplikovaný, složitější početní operace než násobení a dělení v něm nenajdete, nejkomplikovanější programátorskou konstrukcí jsou dva v sobě vnořené FOR cykly určené pro plnění nebo čtení dvourozměrného pole.

Schválně, kolik kol vydržíte?