Linux E X P R E S

Facebook

Naprogramujte logickou hru v Pythonu a GTK

python_hra.png

Tento praktický tutoriál na konkrétním příkladu nastíní proces vývoje malých desktopových aplikací. Pomocí technologií jako Python, GTK a Glade vytvoříme malou logickou hru. Nebudou chybět ani domácí úkoly.


O co v dnešním článku půjde?

  • Seznámíme se s jedním mechanickým hlavolamem.

  • Logiku úlohy nakódujeme v jazyce Python.

  • Stručně uvedeme čtenáře do problematiky technologií Python, Glade, GTK, PyGTK a Cairo.

  • V grafickém návrháři Glade naklikáme uživatelské rozhraní programu.

  • Grafické uživatelské rozhraní naroubujeme na připravený kód v Pythonu.

  • Doprogramujeme vykreslování vektorové grafiky zobrazující aktuální stav hlavolamu. Celý program dokončíme.

  • Pro zájemce uvedeme úkoly k dalšímu studiu.

Seznámení s hlavolamem

Vlevo počáteční pozice, vpravo cílová pozice Vlevo počáteční pozice, vpravo cílová pozice

Cílem hlavolamu je získat z počáteční pozice, kterou ukazuje levé okno v obrázku, koncovou pozici, kterou ukazuje pravé okno v obrázku. Větší kolečka blíže středu mohou pouze zezelenat a zčervenat. Malá černá kolečka dále od středu tvoří „masku“. Stiskem tlačítka Otočení barev se velká kolečka pod maskou přebarví. Názorně tento úkon osvětluje screenshot níže.

Změna barev na vymaskovaných pozicích Změna barev na vymaskovaných pozicích

Tlačítkem Otočení masky (+) (resp. Otočení masky (-)) lze rotovat maskou o jedno políčko v kladném (resp. záporném) směru. Opět následuje názorná ilustrace.

Otočení masky o jednu pozici Otočení masky o jednu pozici

Popis mechanického vyhotovení hračky: Dvoubarevné díly jsou ozubená kola uložená symetricky v centrálním disku. Disk obepíná otáčitelný věnec, který má na vnitřním plášti po obvodu vysoustružené drážky rovnoběžné s osami barevných kol. Do drážek jsou zaklesnuta svými zuby barevná ozubená kola a tím se fixuje jejich poloha. (Při rotaci věnce ozubená kola kloužou v drážkách.) Věnec je sesazen ze stacionárních segmentů a ze vzájemně napevno spojených pohyblivých segmentů, které tvoří masku. Translace pohyblivých segmentů probíhá ve směru osy symetrie výrobku. Drážky pohyblivých segmentů pak fungují jako ozubený hřeben, který roztáčí přiléhající barevná ozubená kola. Přechod mezi oběma úvratěmi otočí ozubená kola o jednu půlotáčku, a tak se odkryje odlišně nabarvená strana kol. Popsaný komplet je zapouzdřen. Vhodný tvar krytu zajišťuje integritu výrobku (např. nevypadávají segmenty věnce) a vodicí kulisy na krytu brání pohybům porušujícím definici úlohy. Nedefinovaným pohybem je například otáčení věnce, aniž by pohyblivé segmenty nedosáhly jedné z úvratí.

Jádro programu

Zdrojový kód jádra programu Zdrojový kód jádra programu

Komentáře k jednotlivým řádkům:

  • řádek 1: Řádek označuje interpreta skriptu. Nyní již stačí jen přidat právo ke spuštění (chmod +x hra.py).

  • řádek 2: Řádek označuje kódování zdrojového kódu skriptu. Uživatelské rozhraní s českými znaky (např. č) budeme izolovat od zdrojového kódu, a proto je deklarace kódování víceméně zbytečná.

  • řádek 4,5: Údaje o barvách se ukládají do pole dvanácti prvků pomocí boolovských hodnot (ano/ne). Maska se reprezentuje jako pole s čísly pozic.

  • řádek 7 až 12: Funkce provede otočení masky o dx pozic. V řádku 8 jsou zpřístupněny některé proměnné z hlavního jmenného prostoru. Výraz len(barvy) označuje délku pole barvy.

  • řádek 14 až 17: Funkce invertuje barvy v maskovaných pozicích.

  • zbytek kódu: Zbytek kódu slouží k jednoduchému otestování v terminálu. Řádek 25 načítá řetězec ze standardního vstupu (obvykle klávesnice). Nekonečný cyklus lze ukončit například přerušením z klávesnice (obvykle klávesová zkratka [Ctrl+c]) nebo uzavřením standardního vstupu (obvykle klávesová zkratka [Ctrl+d]).

Stručné představení technologií

  • Python patří mezi nejpopulárnější programovací jazyky.

  • GTK je prostředí pro tvorbu programů a jejich grafických uživatelských rozhraní. Desktopové prostředí GNOME je vybudováno právě nad GTK. Toolkit GTK zahrnuje množství nejrůznějších technologií.

  • Glade Interface Designer (dále jen Glade) je grafický návrhář uživatelských rozhraních v GTK.

  • PyGTK zpřístupňuje GTK z programovacího jazyku Python.

  • Cairo je knihovna produkující vektorovou grafiku.

Všechny zmíněné technologie spadají do základního vybavení běžných linuxových distribucí. Proto pravděpodobně výsledný program půjde pustit okamžitě, protože tyto softwarové závislosti budou již instalované, v opačném případě je třeba doinstalovat chybějící balíčky.

Glade

Nejprve zkontrolujte, že máte nainstalováno Glade třetí řady (balíček glade-3). Při zakládání nového projektu v Glade se objeví následující okno.

Dialog pro nový projekt Dialog pro nový projekt

Pracovní prostor okna Glade se dělí na tři části. V levém panelu figurují nabídky různých GTK komponent. (Dostupnost některých méně důležitých komponent se různí podle zvolené verze GTK.) V prostřední části naleznete schéma uživatelského rozhraní. Návrh se vytvoří triviálně metodou „táhni a pusť“ (drag-and-drop). Designér si jednoduše myší přetáhne prvky z levého panelu.

Glade Glade

Pravý panel ve své horní části reprezentuje návrh rozhraní stromovým diagramem. V našem návrhu v kořenu stromu se nachází hlavní okno aplikace (window1), okno vyplňuje jediný potomek vertikální tabulka (vbox1), tabulku vyplňují dvě buňky, první buňku zabírá plátno (vdrawingarea1), druhou buňku zabírá horizontální tabulka (hbox1) se třemi buňkami, jež nabízejí tři různá tlačítka. V diagramu názvu komponenty předchází příslušný symbol, který koresponduje s ikonami v levém panelu.

Stejné symboly v obou panelech Stejné symboly v obou panelech

Dolní část pravého panelu nastavuje různé vlastnosti a chování komponent. Na následujícím screenshotu si všimněme kolonky Měnitelná velikost.

Kolonka Měnitelnost velikosti v dolní části pravého panelu Kolonka Měnitelnost velikosti v dolní části pravého panelu

Přepnutí této jedné kolonky vyvolá komplexní změny v celém fungování okna aplikace. Například zmizel symbol pro maximalizaci okna a zmizela ouška pro roztahování okna.

Vlevo bez měnitelné velikosti, vpravo s měnitelnou velikostí Vlevo bez měnitelné velikosti, vpravo s měnitelnou velikostí

Dále pomocí příslušného přepínače u plátna (vdrawingarea1) zafixujte velikost a nastavte rozměry na 500 × 500 pixelů. Restrikce zpřehlední překreslovací rutinu, poněvadž programátor není nucen dynamicky zjišťovat šířku plátna, výšku plátna a reagovat na změnu poměru šířky a výšky.

Prostředí GTK avizuje činnost uživatele programu ve formě posloupnosti signálů. Ústředním signálem z několika desítek signálů u tlačítka samozřejmě bude oznámení o kliknutí (signál clicked). Obsluhu kliknutí na tlačítko button1 můžeme pojmenovat jako vpravo, jak dokládá obrázek.

V dolní části konfigurace zpracování signálů V dolní části konfigurace zpracování signálů

V aplikaci věnujeme pozornost následujícímu:

  • Program by měl zareagovat na zavření okna aplikace (signál destroy). Jinak by zbytečně čekal na odezvu z již „mrtvého“ okna. Obsluhu nazvěme zavreni.

  • Dále by měl program zareagovat na stisknutí tlačítka. Obsluhy nazvěme vpravo, vlevo a otoceni.

  • Manipulace s okny může zahodit grafiku vykreslenou na plátně. Proto obnovení okna z lišty a získání zaměření (fokusu) obslužme ve funkci prekresleni, které překreslí obsah plátna.

Podrobnosti viz přiložené zdrojové kódy s návrhem uživatelského rozhraní (na konci článku).

Projekt uložte pod jménem navrh.xml. Soubor s navrženým rozhraním se uloží ve formátu XML podle schématu GtkBuilderu. Soubor navrh.xml lze charakterizovat jako čitelný zdrojový kód, což dokládá následující screenshot z prohlížeče Gedit.

Definice uživatelského rozhraní ve formátu GtkBuilderu Definice uživatelského rozhraní ve formátu GtkBuilderu

Grafické uživatelské rozhraní

Z předchozího zdrojového kódu jsem odstranil testovací část a dopsal celý program.

Zdrojový kód otevřený v Geany Zdrojový kód otevřený v Geany

Úvodní část nově dopsaného kódu ukazuje okno GVimu.

Komentovaný výsek zdrojového kódu Komentovaný výsek zdrojového kódu

Komentáře k jednotlivým řádkům:

  • řádky 23 až 26: Nutné prostředky se musí importovat. Matematiku na řádku 25 importuji kvůli zisku goniometrických funkcí, které využiji při počítání souřadnic při kreslení na plátno. Pro jednoduchost na žádném místě v programu neodchytávám a neošetřuji případné chyby. Zde bych správně měl ošetřit případy, kdy se import nezdaří.

  • řádek 28: Celé uživatelské rozhraní budu abstrahovat jednou třídou GUI.

  • řádek 30: Inicializační funkce __init__ je něco jako konstruktor. Klíčové slovo self odkazuje na svou třídu a odpovídá klíčovému slovu this např. z jazyka Java.

  • řádek 31, 32: Vytvořený builder za nás podle souboru navrh.xml zkonstruuje uživatelské rozhraní. Soubor navrh.xml a skript umístěte do téhož adresáře.

  • řádek 33: Funkce, kterými ošetřuji signály emitované uživatelským rozhraním, se nacházejí v inicializované instanci třídy GUI.

  • řádky 34, 35, 36: Připravím si plochu pro kreslení...

  • řádek 37: ... a vykreslím hlavolam.

  • řádky 37 až 49: Obsluhuji otočení masky oběma směry a inverzi barev. Na konci obsluh nezapomínám na překreslení.

  • řádky 51, 52: Tato funkce ukončí program, což bude vysvětleno v komentáři k řádku 69.

Cairo a dokončení programu

Pokračování komentovaného zdrojového kódu Pokračování komentovaného zdrojového kódu

Komentáře k jednotlivým řádkům:

  • řádek 54: Tato funkce vykresluje hlavolam na plochu.

  • řádek 55: Prochází se všechny pozice...

  • řádek 56: ...bude se kreslit červeně...

  • řádky 57, 58: ...je-li však barva zelená (hodnota True), nastaví se zelená barva...

  • řádek 59: ...nyní následuje logika vykreslení kruhu. Vypočtou se argumenty. Následují popořadě obě souřadnice, poloměr kruhu, síla čáry a velikost plného úhlu.

  • řádek 60: ...nyní se připravený kruh vykreslí.

  • řádek 61 a zbytek funkce: Analogicky se vykreslí i maska.

  • řádek 68: Vzniká instance třídy GUI.

  • řádek 69: Na konec se nastartuje GTK. Spustí se hlavní obslužná smyčka GTK, jež zachytává a obsluhuje události. Z nekonečné smyčky se vystoupí až voláním speciální funkce na řádku 52. Tím se dokončí volání funkce na řádku 69, interpret Pythonu pokračuje ve zpracování kódu, čímž narazí na konec souboru a program skončí.

Domácí úkoly

V oblasti designu

  • Zkoumejte možnost frameworku GTK a návrháře Glade. Vylepšete grafické uživatelské rozhraní aplikace.

  • Jaké výhody přináší vývoj v Glade/GtkBuilderu?

  • Pracujte na odlišném uživatelském rozhraní pro aplikaci. Svoje nápady posléze konfrontujte s doporučeními v GNOME HIG.

  • Prohlédněte si obsahy některých adresářů v /usr/share. Všimněte si zdrojů souvisejících s uživatelskými rozhraními.

V oblasti programování

  • Napište program provádějící náhodné tahy. Statisticky zjišťujte, po kolika tazích program průměrně hlavolam vyřeší. Proveďte dostatek simulací, aby odchylka vašeho výsledku od skutečné hodnoty byla nejvýše 100 tahů na alespoň 99% hladině spolehlivosti.

  • Algoritmus nápovědy hrubou silou prohledává celý stavový prostor. Naprogramujte nápovědu, která uživateli radí nejlepší tahy. (Nejlepší tahy řeší libovolnou situaci s nejmenším možným počtem inverzí barev.)

  • Lze v předchozím úkolu vtipně využít předností Pythonu?

  • Vyhledejte dokumentaci ke Cairo. S pomocí dalších primitiv (např. čáry) a efektů (např. průhlednost) zdokonalte vykreslování hlavolamu.

V oblasti matematiky

  • Kolik pozic je dosažitelných legálními tahy z počáteční pozice?

  • Vzdáleností pozic A a B definujme jako minimální počet inverzí barev, který umožňuje přejít z pozice A do pozice B. Je maximální vzdálenost pozic (tzv. průměr grafu) přesně dvanáct? Jaká je průměrná vzdálenost pozic?

  • Své odpovědi na předcházející otázky zobecněte.

  • Existuje výpočetně efektivní algoritmus pro hledání nejlepších tahů v podobných hrách?

Řešení naleznete v článku Řešení domácích úloh k programovacímu tutoriálu.

Dokument typu py

hra.py

Dokument typu py | Velikost 1,6 kB

Dokument typu xml

navrh.xml

Dokument typu xml | Velikost 2,88 kB

Diskuze (2) Nahoru