Pojďte s námi programovat !

1. 6. 2008

Sdílet

Červnová lekce našeho programátorského kurzu jazyka C# 3.0 se bude věnovat vývoji ryze praktických aplikací. Aby ne...


Červnová lekce našeho programátorského kurzu jazyka C# 3.0 se bude věnovat vývoji ryze praktických aplikací. Aby nebyla křivka učení příliš strmá, začneme pozvolna a poté budeme pomalinku přidávat otáčky.


1. program: Ekonomická aplikace pro stanovení kritického bodu rentability

Náš první praktický experiment se soustřeďuje na ekonomickou problematiku. Abychom mohli vytvořit program, nejprve se musíme seznámit s analýzou problému, který hodláme pomocí sestaveného programu vyřešit. Jelikož určení kritického bodu rentability je běžný úkol pro studenty ekonomie, začneme lehkým úvodem do tématu. Představme si, že máme podnik (strategickou podnikatelskou jednotku), který vyrábí a prodává jisté portfolio produktů. V závislosti od diverzifikace výrobního programu může podnik vyrábět a prodávat mnoho různých výrobků a jejich variant. Nechť tedy existuje konečná neprázdná množina vyráběných výrobků V, která je tvořena jednotlivými výrobky, což můžeme formalizovat takto: V = {v1, v2, …, vn}. My si z uvedené množiny vybereme jeden výrobek, na němž provedeme naši ekonomickou analýzu. Ekonomové zpravidla chtějí vědět, kdy se celkové náklady na výrobu daného výrobku budou shodovat s celkovými tržbami dosaženými prodejem jistého množství tohoto výrobku. Právě tuto situaci, tedy když se náklady na výrobu výrobku rovnají tržbám z jeho prodeje, charakterizuje tzv. kritický bod rentability. Tento bod označuje množství vyrobených a současně prodaných jednotek výrobku, přičemž musí platit následující matematická rovnice:

T = N

kde:

T jsou celkové tržby generované prodejem jistého množství výrobku.
N jsou celkové náklady vynaložené na výrobu jistého množství výrobku.

Když se celkové tržby shodují s celkovými náklady, podniku prozatím nepřináší výroba a následný prodej výrobku žádný zisk. Jelikož je zřejmé, že zisk generovaný prodejem výrobku je v okamžiku dosažení kritického bodu rentability nulový (Z = 0), kritický bod rentability se někdy jednoduše nazývá též nulovým bodem. Jelikož jsou veličiny T a N agregované, musíme je pro potřebu bližší analýzy dále specifikovat. Opět připomínáme, že budeme zvažovat nejjednodušší možné vyjádření a rovněž tak abstrahujeme od jakýchkoliv nepřesností, jichž se můžeme ve vztahu ke skutečnosti dopustit. Uveďme si nejprve matematický aparát, který poté opatříme doprovodným komentářem:

T = N
p × q = FN + b × q
p × q ? b × q = FN
q(p ?b) = FN
FN
q = ____
p ? b

Celkové tržby (T) obdržíme, když prodáme jistý objem výrobků (q), přičemž každý výrobek má svou prodejní cenu (p). Celkové náklady se skládají z nákladů fixních (FN) a variabilních (VN). Zatímco úroveň fixních nákladů není závislá na objemu vyrobené produkce, u variabilních nákladů tato závislost existuje. Čím více jednotek zkoumaného výrobku podnik vyprodukuje, tím větší variabilní náklady bude nutno alokovat. Abychom znázornili závislost variabilních nákladů na objemu produkce, zavádíme vztah VN = b × q. V dalších krocích se již matematický algoritmus koncentruje na osamostatnění proměnné q, protože její hodnota (za takto stanovených podmínek) představuje množství vyrobených a prodaných jednotek produktu, čili námi hledaný kritický bod rentability. Samozřejmě studenti běžně operují již s finálním vzorcem, který můžeme zapsat takto:

FN
qkb = ____
p ? b
kde:
qkb je množství vyprodukovaných a prodaných výrobků, při kterém je dosažen kritický bod rentability.
FN jsou fixní náklady na výrobu příslušného množství výrobků.
p je prodejní cena jednoho výrobku.
b jsou variabilní náklady na výrobu jednoho výrobku (tzv. jednotkové náklady).

Nuže, a k čemu je vůbec analýza nulového bodu dobrá? Inu, pokud není pro jistý výrobek dosaženo množství produkce a prodeje, jaké stanovuje proměnná qkb, pak takovýto výrobek způsobuje podniku ztrátu. Naopak, při překročení kritického bodu se již výrobek dostává do „ziskové oblasti“, neboť celkové tržby začínají převyšovat celkové náklady.

Pokud budeme chtít naprogramovat aplikaci, která pomůže ekonomickým manažerům s výpočtem nulového bodu, budeme potřebovat tyto vstupní údaje: fixní náklady, prodejní cenu výrobku a variabilní náklady na výrobek. Toto tedy budou vstupy, s nimiž bude naše aplikace pracovat. Jakmile provedeme načtení vstupů, použijeme je k určení kritického bodu rentability, který ve finální fázi zobrazíme uživatelům. Výborně, můžeme přistoupit ke stavbě programu!
V integrovaném vývojovém prostředí produktu Microsoft Visual C# 2008 Express založíme novou konzolovou aplikaci (projektová šablona Console Application), kterou můžeme vhodně pojmenovat. Poté zapíšeme tento zdrojový kód:

Komentář k programu: Ve chvíli, kdy vytvoříme proměnné pro úschovu vstupních dat, žádáme uživatele, aby zadal konkrétní data, jimiž budou dotyčné proměnné inicializovány. Všimněte si obzvláště přiřazovací příkazy, v nichž dochází k inicializaci proměnných fixníNáklady, cenaVýrobku a variabilníNáklady. Ačkoliv máme celkem tři přiřazení, všechna pracují podle jednoho a téhož modelu, který si nyní vysvětlíme. Předpokládejme, že uživatel zadá data do programu. Tato data budou přečtena metodou ReadLine třídy Console. Zmíněná metoda je spojena se vstupním datovým proudem, ze kterého postupně odebírá textové znaky, až dokud nenarazí na symbol konce řádku (ten vloží uživatel stiskem klávesy Enter). Na tomto místě je nezbytné podotknout, že data, jež získá metoda ReadLine třídy Console, jsou textové povahy. Ve skutečnosti jsou data uložena do textového řetězce, jenž je následně zapouzdřen do speciálního objektu (konkrétně do objektu třídy System.String). Přestože uvedené technické detaily nejsou pro nás nyní důležité, naší snahou je poukázat na jednu věc: Vše, co přichází ze vstupního datového proudu, má charakter textových dat. My ale potřebujeme celá čísla, ne posloupnosti textových znaků.

Proto je bezpodmínečně nutné převést textové řetězce na odpovídající celočíselné ekvivalenty. To se v programování děje prostřednictvím explicitní typové konverze. Explicitní typová konverze představuje mechanizmus, díky kterému smíme pozměnit datový typ jisté hodnoty. Ačkoliv na typové konverze ještě přijde řeč, první kontakt s nimi získáme i při tak jednoduché aplikaci jako je ta, kterou právě vyvíjíme. Dobrou zprávou je, že explicitní typovou konverzi pro nás obstará metoda ToUInt32 třídy Convert. Tato metoda přijme textový řetězec a zpátky nám vrátí celočíselnou hodnotu, kterou řetězec reprezentuje. Pomozme si příkladem: uživatel po výzvě na zadání fixních nákladů zapíše hodnotu 30000 a stiskne Enter. Když se tak stane, metoda ReadLine třídy Console načte zadanou hodnotu, přičemž s ní bude zacházet jako s textovým řetězcem. To ovšem není to, co chceme. Proto hodnotu fixních nákladů v podobě textového řetězce předáme metodě ToUInt32 třídy Convert, která textový řetězec transformuje do celočíselné formy datového typu uint. (Dodejme, že typu uint na systémové úrovni náleží typ System.UInt32.) Po provedení explicitní typové konverze je hodnota fixních nákladů už ve správném formátu, a proto nám nic nebrání v tom, abychom ji uložili do požadované proměnné. Přesně stejný postup se opakuje i u všech ostatních přiřazovacích příkazů, jimiž uskutečňujeme inicializaci zbývajících proměnných.
Dalším zajímavým místem je vypočtení množství q, které představuje kritický bod rentability. Povšimněte si zejména výrazu stojícího na pravé straně přiřazovacího příkazu. Ano, při přepisu výpočtu do zdrojového kódu jazyka C# 3.0 postupujeme krok za krokem přesně podle matematického vzorce. Jelikož ve jmenovateli počítáme rozdíl mezi prodejní cenou výrobku a jeho jednotkovými náklady, tuto aritmetickou operaci umísťujeme do závorek, čímž zvyšujeme její prioritu. Poté, co určíme kritický bod rentability, zobrazujeme ho na výstupu v okně příkazového řádku. Výstup programu je uveden na obrázku.

2. program: Simulace detekce kolizí mezi objekty

Programátoři počítačových her stráví mnoho času navrhováním algoritmů pro detekci kolizí mezi objekty. V dalším programu sestrojíme jednoduchý algoritmus, který bude zjišťovat, zda se dva objekty dostaly do kolize či nikoliv. Přitom budeme vycházet z premisy, že pracujeme na dvojrozměrné (2D) závodní hře, v níž řídíme svůj vůz. Během závodu se může stát, že se trajektorie našeho automobilu setká s trajektorií jiného vozidla (přitom je zcela nepodstatné, zda půjde o vůz jednoho z našich soupeřů nebo o stroj jiného účastníka silničního provozu). Pokud dojde ke srážce s jiným vozem, náš program tuto kolizi zaregistruje a ohlásí.

Přestože vývojáři počítačových her používají spoustu nezřídka i velice sofistikovaných postupů pro detekci kolizí, my svého cíle dosáhneme se snad až magickou elegancí. Budeme totiž předpokládat, že všechny automobily v naší hře jsou opatřeny jakýmisi ochrannými obaly, které budou mít tvar kružnice (viz obrázek).
Je zřejmé, že ochranné obaly ve tvaru kružnice jsou ve vztahu k modelům automobilů poznamenány značnou mírou aproximace. Ano, této disproporce jsme si vědomi, ale záměrně jsme celou situaci zjednodušili do té míry, abychom ji dokázali s existující znalostní úrovní algoritmizace vyřešit (kromě toho se nám budou kolize snáze modelovat i z matematického hlediska). Nuže, v našem chápání se auta dostanou do kolize tehdy, když vznikne průnik mezi jejich ochrannými obaly. Tuto situaci názorně ilustruje další obrázek.

Odmyslíme-li si modely aut, pak se z detekce kolizí stává hezké matematické cvičení, ve kterém budeme zkoumat vzájemnou pozici dvou kružnic. Každá kružnice je jednoznačně definována svým středem a poloměrem. V euklidovském dvojrozměrném prostoru lze každou kružnici popsat její středovou rovnicí, která má následující podobu:

(x ? m)2 + (y ? n)2 = r2

kde:
m, n jsou souřadnice středu kružnice,
r je poloměr kružnice,
x, y jsou souřadnice jakéhokoliv bodu, který leží na kružnici.

Jestliže je střed kružnice situován v počátku souřadnicové soustavy, pak má středová rovnice kružnice tvar:

x2 + y2 = r2

Tento vzorec vychází ze známé Pythagorovy věty a dá se velice pěkně graficky znázornit.
Pozice kružnice je určena jejím středem, zatímco velikost kružnice určuje poloměr. Uvažujme o dvou kružnicích: k1(S1; r1) a k2(S2; r2). Tyto kružnice jsou v kolizi tehdy, pokud je vzdálenost mezi jejich středy menší nebo rovna součtu jejich poloměrů. Matematicky zapsáno:

|S1S2| ? r1 + r2 ?$ kolize

Určení vzdálenosti mezi středy je jednoduché, opět nám bude nápomocna Pythagorova věta:

|S1S2| = ?(S2x ?S1x)2 + (S2y ?S1y)2

Při ostré nerovnosti budou mít obě kružnice společné dva body (průsečíky). Při rovnosti se kružnice budou dotýkat (bude se jednat o tzv. vnější dotyk). Geometrický pohled na kolizi aut zprostředkovává další obrázek.

Po zvládnutí matematické teorie se můžeme pustit do programování. Jak se již stalo naším dobrým zvykem, nejprve uvedeme program a pak k němu připojíme komentář.

Komentář k programu: Proměnné S1_x, S1_y, S2_x a S2_y slouží k úschově x-ových a y-ových souřadnic středů obou kružnic, které obklopují počítačové modely automobilů. Všechny zmíněné proměnné inicializujeme pevně zadanými celočíselnými hodnotami. Ovšem středy samotné nestačí, proto definujeme také proměnné r1 a r2, do nichž ukládáme poloměry zkoumaných kružnic. Pro vypočtení vzdálenosti mezi středy použijeme metodu Sqrt třídy Math. Tato metoda zjistí druhou odmocninu a vrátí ji v podobě reálného čísla typu double. Po výpočtu je v proměnné vzdálenostS1_S2 uložena délka měřená mezi středy S1 a S2. Vypočtením vzdálenosti mezi středy ale nekončíme, poněvadž od programu očekáváme, že určí, zda ke kolizi mezi auty došlo či nikoliv. Algoritmus, který pomůže programu v rozhodování, je zapsán pomocí rozhodovacího příkazu if-else. Ačkoliv to pravé dobrodružství s rozhodovacími příkazy nás ještě čeká, ve výše zapsaném programu vznikla přirozená potřeba jeden z nich použít.

Rozhodovací příkaz if-else se skládá z dvou větví: if a else. Zpracování příkazu začíná vyhodnocením výrazu, který je zapsán v závorkách za klíčovým slovem if. V našem případě se jedná o relační výraz vzdálenostS1_S2 <= r1 + r2. Tento výraz se označuje jako relační proto, že se v něm uplatňuje relační operátor <= (jenž je ztělesňován symbolem „menší než, anebo rovný“). Relačním výrazem testujeme, zda je vzdálenost mezi středy S1 a S2 menší nebo nanejvýš rovna součtu poloměrů obou kružnic. Když kompilátor narazí na zkoumaný výraz, nejprve vypočte součet poloměrů a poté jeho hodnotu porovná se vzdáleností středů. Hodnotou relačních výrazů může být buď logická pravda (true), nebo logická nepravda (false). Pokud je vzdálenost středů doopravdy menší nebo rovna než součet poloměrů, pak je celý výraz vyhodnocen jako pravdivý (jeho hodnotou je logická pravda). V opačném případě je hodnotou výrazu false, tedy logická nepravda. Relační výraz se v souvislosti s rozhodovacím příkazem if-else nazývá rovněž podmínkou, neboť testujeme, zda je tato podmínka splněna (výraz má hodnotu true) nebo ne (výraz má hodnotu false).

Kolize mezi automobily v naší počítačové hře nastane pouze tehdy, je-li relační výraz vyhodnocen jako pravdivý (podmínka je tudíž splněna). Za těchto okolností se provede příkaz, který následuje ihned za větví if. V našem programu se v tomto okamžiku zobrazí správa pojednávající o vzniku kolize. Je-li tomu tak, naše auto se právě nabouralo do jiného vozu nebo objektu, jenž je součástí silničního provozu. Lepší variantou pro náš závodní vůz je samozřejmě bezkolizní průběh v soutěži, kterému se vůz téší tehdy, je-li hodnotou relačního výrazu false. Podmínka není splněna vždy, když je vzdálenost mezi středy ochranných kružnic větší než je součet jejich poloměrů. Nedojde-li k bouračce, program nás seznámí s tím, že žádná kolize nevznikla. 8 0287/CZ o

Autor článku