IB111 Návrh aplikace Založeno na 9. kapitole knihy J. M. Zelle: Python Programming: An Introduction to Computer Science Simulace hry volejbal •Chceme vytvořit simulátor hry volejbal –Ne grafický :-) •Jde nám o počty vítězství 2 teamů, známe-li pravděpodobnosti výhry jejich podání. •Například: –První team vyhrává svá podání s 60% úspěšností –Druhý team vyhrává svá podání s 50% úspěšností •Úkolem je vytvoření programu, který bude simulovat několik her volejbalu –Používáme stará pravidla a existenci setů ignorujeme Volejbal •Začíná jeden team –Pokud získá své podání, dostane bod a opět podává –Pokud ztratí své podání, podává druhý team a bod nezískává nikdo •Hra končí pokud nějaký team získá 15 bodů –Pokud je však rozdíl ve skóre pouze jednobodový, je třeba hrát dál dokud rozdíl není alespoň 2 body Detailnější specifikace problému •Vstup: Program se zeptá na potřebné údaje –Pravděpodobnost výhry podání teamu A –Pravděpodobnost výhry podání teamu B –Počet her, které budeme simulovat •Výstup: Program vypíše výsledné statistiky –Počet simulovaných her –Počet her, které vyhrál team A –Počet her, které vyhrál team B Náhoda •Pro deterministický počítač není jednoduché vytvářet zcela náhodná čísla •Pro simulace typicky používáme generátor pseudonáhodných čísel –Založené na „semínku“ (seed) –Vytváří posloupnost čísel s dobrými statistickými vlastnostmi •Vhodné pro simulace •Python –Modul random –Pseudonáhodný generátor „Mersenne Twister “ inicializovaný aktuálním časem •Zcela nevhodné pro kryptografické účely Generování náhodných čísel •Python –random.randint(a, b) •Return a random integer N such that a <= N <= b. –random.random() •Return the next random floating point number in the range [0.0, 1.0). •Výhra podání • if random() < prob: • score = score + 1 • kde prob je pravděpodobnost výhry hráče – Návrh shora dolů (top-down) •Návrh začínáme na abstraktní (vysoké) úrovní •Specifikujeme co principielně bude program dělat •Uvedeme, jak se bude postupovat, aniž bychom museli rovnou zmínit všechny detaily jak to udělat –To upřesníme později •V dalších krocích pak postupně upřesňujeme detaily, které jsme v předchozích krocích přeskočili •Nakonec tak získáme kompletní program Náš příklad se simulací volejbalu •Základní algoritmus: • Vypiš úvodní informace • Získej vstupní údaje: probA, probB, n • Simuluj n her teamů A a B za pomoci probA, probB • Vypiš kolik her se hrálo, kolikrát vyhrál team A, B • •Pro každý krok dále musíme upřesnit vstupy a výstupy –parametry a návratové hodnoty funkcí –Interface / rozhraní První návrh programu •Program v pythonu: • • def main(): • printInstructions() • probA, probB, n = getInputs() • winsA, winsB = simNGames(n, probA, probB) • printSummary(winsA, winsB) Grafický návrh •Náš návrh lze zobrazit i graficky • Druhá úroveň návrhu •Po navržení první (kořenové) úrovně návrhu pokračujeme druhou úrovní •Specifikujeme chování funkcí použitých v návrhu první úrovně. •Tj. specifikujeme funkce –printIntro –getInputs –simNGames –printSummary Výpis úvodních informací •Funkce v pythonu: • • def printIntro(): • print "Tento program simuluje hru volejbal mezi 2" • print ’teamy "A" a "B". Schopnosti teamu jsou dany’ • print "pravdepodobnostmi (cislo mezi 0 a 1) s jakymi" • print "team vyhraje sve podani. Zacina vždy team A." • Získání vstupních dat •Funkce v pythonu • • def getInputs(): • a = input("S jakou pravdepodobnosti vyhraje team A sve podani") • b = input("S jakou pravdepodobnosti vyhraje team B sve podani") • n = input("Kolik her bude simulovano?") • return a, b, n Simulace n her •Intuitivně bude simulace vypadat nějak takto: • • iniciálně počet výher winsA a winsB bude nula • opakuj n-krát • simuluj jednu hru • jestliže vyhrál team A • team A získává bod • jinak • team B získává bod Simulace n her •Přepíšeme do pythonu: • def simNGames(n, probA, probB): • winsA = winsB = 0 • for i in range(n): • scoreA, scoreB = simOneGame(probA, probB) • if scoreA > scoreB: • winsA = winsA + 1 • else: • winsB = winsB + 1 • return winsA, winsB Výpis výsedku •Zapíšeme v pythonu • •def printSummary(winsA, winsB): • n = winsA + winsB • print "\nPocet simulovanych her:", n • print "Pocet vyher A: %d (%0.1f%%)" % (winsA, float(winsA)/n*100) • print "Pocet vyher B: %d (%0.1f%%)" % (winsB, float(winsB)/n*100) Grafické znázornění •Opět může aktuální specifikaci zobrazit graficky: Třetí úroveň návrhu •Zbývá dospecifikovat funkci pro jednu hru •Intuitivně bude funkce fungovat takto: • • Inicializuje skóre obou teamů na nulu • Team A má podávat • Opakuj dokud není konec hry: • simuluj jedno podání teamu, který podává • aktualizuj skóre • Vrať skóre obou teamů Implementace v pythonu •def simOneGame(probA, probB): • scoreA = 0 • scoreB = 0 • serving = "A" • while gameNotOver(scoreA, scoreB): • if serving == "A": • if random() < probA: • scoreA = scoreA + 1 • else: • serving = "B" • else: • if random() < probB: • scoreB = scoreB + 1 • else: • serving = "A" • return scoreA, scoreB Grafické zobrazení Zbývá funkce pro zjištění konce hry •Hra končí, pokud některý z teamů získá 15 bodů –A rozdíl skóre obou teamů je nejméně 2 • •def gameOver(a,b): • return (a>=15 or b>=15) and (a>=b+2 or b>=a+2) Jak jsme postupovali 1.Vyjádřili jsme algoritmus jako sérii menších problémů (bloků/funkcí) 2.Pro každý menší problém (blok/funkci) jsme vyvinuli rozhraní 3.Algoritmus jsem pak upřesnili tím, že jsme specifikovali, jak využijeme rozhraní s menšími problémy (bloky/funkcemi). 4.A obdobně jsme postupovali při návrhu jednotlivých menších problémů (bloků/funkcí) na nižších úrovních. Testování •Program implementujeme v pythonu •Když ho poprvé spustíme je možné, že díky chybám nebude fungovat, tak jak si představujeme –Chybujeme všichni –Chyby jsou běžné –Bug •Program budeme testovat po částech –Použijeme přístup „zdola nahoru“ (botton-up) –Nejprve ověříme funkčnost komponent na nižší úrovni a později komponent na vyšší úrovni Testování funkce gameOver •Vyzkoušíme na několika voláních s různými parametry: • • • • • •Pokud se zdá, že funkce funguje dobře, pokračujeme o úroveň výše. •Pozn: Skutečná verifikace toho, že funkce dělá přesně to co má, je netriviální. Jiné přístup k návrhu a vývoji SW •Prototypování a spirálový vývoj –Prototyp – iniciální verze programu s omezenou funkčností •Vhodné pro ověření, zda principy, na kterých chceme SW založit fungují –Prototyp dále vylepšujeme, až získáme kompletní program s plnou funkčností •Inkrementální vývoj Prototypování: úvodní verze •def simOneGame(): • scoreA = 0 • scoreB = 0 • serving = "A" • for i in range(30): • if serving == "A": • if random() < .5: • scoreA = scoreA + 1 • else: • serving = "B" • else: • if random() < .5: • scoreB = scoreB + 1 • else: • serving = "A" • print scoreA, scoreB Prototypování: inkrementální vývoj •Fáze: 1.Iniciální prototyp: 30 podání s pravděpodobností vyhrání podání 50 % a 50 %. Pomocný výpis po každém podání. 2.Přidáme parametry pro pravděpodobnosti výher podání. 3.Přidáme funkci sledující konec hry při získání 15 bodů jedním hráčem. Tím máme funkční simulaci jedné hry. 4.Rozšíříme na opakování několika her. Výstupem bude počet výher jednotlivých teamů. 5.Vývoj plně funkčního programu. Dořešení získání vstupu od uživatele a vhodného formátování výstupu. Vývoj softwaru •Vývoj softwaru je umění •Již dlouhou dobu se jí zabývá věda nazývaná „Softwarové inženýrství“ („Software engineering“) •S dalšími aspekty vývoje SW se setkáte v dalších předmětech na FI –například PB007 Softwarové inženýrství I – 633px-Three_software_development_patterns_mashed_together_cz_svg Ladění programů v pythonu •Modul pdb •Spustíme ladění vykonávání určitého kódu •Nebo program zastavíme na určitém místě (breakpoint) pomocí pdb.set_trace() •Potom můžeme –Pokračovat (c) –Krokovat (s) –Prohlížet proměnné (p) –… Ladění programů v Pythonu v IDLE Ladění programů v C: Visual Studio C++ Dokumentování programů •Poznámky/komentáře –Usnadňují pochopení jednotlivých konstrukcí –Píšeme pro sebe i ostatní •Užitečné pro pozdější modifikace programu –Prováděné námi i jinými •Dokumentace rozhraní –API –Ty funkce/moduly/knihovny, které budou používány ostatními •Názvy modulů, funkcí, proměnných… Dokumentace rozhraní •Funkce –Jméno funkce –Vstupní parametry •Povinné •Nepovinné •Defaultní hodnoty –Návratová hodnota –Funkčnost Příklad z dokumentace Pythonu Příklad z dokumentace Windows API Dokumentujeme v Pythonu •Dokumentační řetězce (docstring) •První řetězec třídy, modulu, funkce (metody) •Všechny „veřejné“ části by měly být dokumentovány Jak správně dokumentovat? Příklad využití Styl •Styl psaní programů –Styl programování, coding style •Stejný program lze zapsat různým způsobem –Pěkně vs. škaredě (nevhodně) Doporučení pro Python •Odsazení: 4 mezery •Délka řádku: pod 80 znaků •Prázdné řádky mezi funkcemi a třídami •Komentáře na separátních řádcích •Mezery mezi operátory –Ale žádné mezery u závorek při volání funkcí •Rozumné a konzistentní názvy funkcí –dlouhy_nazev_funkce –DlouhyNazevFunkce Příklady Další příklady