Close

Jak se staví mazel aneb LEGO potkává micro:bit [ ČÁST 2 ]

Mazel micro:bit tamagoči [ ČÁST 2 ]

V první části tohoto seriálu jsme se pustili do stavby tamagočiho v podobě ovečky ze stavebnice LEGO. Nakreslili jsme si základní schéma chování a sestavili rozhodovací kostru našeho programu.
Dnes se podíváme, jak se tvoří funkce, které nám pomohou kód vylepšit jak po stránce efektivity, tak přehlednosti.

Optimalizace kódu aneb ještě trošku nalejvárny

Nejspíš vidíte, že kód nám začíná bobtnat a stává se nepřehledným. A navíc tu máme opakující se části kódu, které jsme vložili pokaždé znovu – nešlo by alespoň s těmi opakujícími se částmi kódu udělat něco, abychom je nemuseli neustále vypisovat znovu? Ale samozřejmě, že s tím něco jde udělat – a dokonce bych vám velmi doporučoval, abyste to udělali.

podprogramy a kde je najít

Nastal čas na trochu té teorie – poprosím vás však o trpělivost, tahle část je důležitá:
Podprogram je označení pro znovupoužitelnou část programu, kterou můžeme volat z jiných částí kódu. Je možné ji doplnit i o různé parametry.
(Pamatujete ještě, jak jsme minule nastavovali hodnotu proměnné S jako výpočet S = a . b? Mohli bychom se na tuto proměnnou koukat jako na podprogram výpočtu obsahu obdélníku a a a b by byly parametry.)

Nejběžnější způsob tvorby podprogramů je pomocí funkcí. Vytvořme proto pro opakující se část kódu samostatnou funkci, jíž zavoláme vždy, když bude třeba.
Obrovskou výhodou je, že pokud bychom v budoucnu chtěli změnit průběh této funkce, pak ji máme definovanou na jednom místě a nemůže se nám stát, že některý její výskyt zapomeneme upravit! Stejně můžeme využívat proměnných (jak jsme si ukázali na příkladu výpočtu obsahu obdélníku) – tam ale voláme jen hodnotu, kdežto funkce volají spuštění určitého kódu.

záložka Functions

Abych vás ale neunudil, chápu, že se už chcete zase vrhnout do dalšího programování, pojďme se tedy podívat kde funkce najdeme a jak je vytvoříme:

Záložku Functions najdete po rozbalení záložky Advanced v MakeCode
Záložku Functions najdete po rozbalení záložky Advanced

Podobně jako u proměnných, i funkce je nejprve třeba vytvořit, než se nám nabídnou další bloky v záložce Functions. Když spustíme Make a Function…, spustí se okno editace funkce – do pole doSomething vepíšeme název funkce. Nahoře pak máme nabídku Add a parameter, kde si můžeme vybrat, jaký typ parametru vyžadujeme. Funkce nemusí mít žádný parametr, ale může jich mít libovolné množství. Obecně je ale velmi vzácná situace, kdy bychom potřebovali více jak dva parametry, navíc větší množství parametrů velmi znesnadňuje porozumění kódu.

makecode editor funkce

Jakmile vytvoříme nějakou funkci, nalezneme v záložce Functions další bloky konkrétně bloky <call _jméno_funkce> a blok <return [value]>. První jmenovaný slouží k zavolání funkce v kódu a jeho využití je dost zřejmé. Blok <return> je zajímavější – pokud chceme, aby funkce sloužila k navrácení hodnoty, je třeba ukončit všechny větve jejího programu právě tímto blokem.[ 4 ]

[ CVIČENÍ 2 ] Zkusme nyní vzít podmínku z předchozího cvičení a přetvořit ji ve funkci XOR, která bude mít dva parametry typu Boolean a bude vracet hodnotu TRUE nebo FALSE.

Pojďme se podívat, jestli bychom nedokázali náš kód trochu zpřehlednit pomocí funkcí. Rozhodně bychom měli vytvořit funkci pro onen opakující se kus kódu. Jde vlastně o vyhodnocení spokojenosti, takže bychom ji mohli pojmenovat evaluation. A když už jsme v tom, možná by nám rozhodovací proces zpřehlednilo i to, že každé náladě vytvoříme vlastní funkci. Tak pojďme na to – až vše vytvoříme, měla vaše nabídka záložky Functions vypadat takto:

makecode funkce

Můžeme si zvolat hurá, protože v tuto chvíli má náš program už funkční kostru! A snad mi uvěříte, že takto rozčleněný kód je o něco přehlednější, než předchozí podoba:

makecode vícestavová podmínka volající funkce pro ovečku tamagoči

Obalujeme tamagočimu kostru programu masem

Výborně – to nejhorší máme snad už za sebou a nyní je potřeba postupně vyřešit jednotlivé stavy nespokojenosti ovečky tamagoči. V mnoha ohledech jsou si podobné – vždy půjde o zjišťování, jestli byla daná potřeba naplněna, či nikoli. A samozřejmě nemáme neomezený čas na to, abychom potřebu naplnili.

Dobře – možná jsem se mýlil a tohle bude ta nejnáročnější část na abstrakci. Musíme totiž sestavit takovou podmínku, která bude kontrolovat dvě věci zároveň – jednak jestli byla naplněna potřeba a ta druhá, jestli už neuběhlo příliš mnoho času. Tady bychom měli trošku vystoupit ze své ulity a podívat se na to, jak měřit čas – micro:bit sice umí měřit čas, ale zároveň nemá žádný přímočarý časovač, který by šlo jednoduše zkontrolovat. Tak si pojďme jeden takový vytvořit! Ale jak to udělat? Co se třeba ptát pořád dokola, jestli je potřeba naplněna a měřit při tom, kolikrát jsme se už zeptali? To by jako určité počítadlo času mohlo fungovat, ne?

Formalizovat to můžeme například pomocí cyklů ze záložky Loops a vybereme <while [boolean] do>. Tento cyklus funguje tak, že jakmile dojde kód k tomuto bloku, provede kontrolu zadané podmínky – pokud je pravdivá, provede se kód uzavřený v tomto bloku a vrátí se zpět k vyhodnocení této podmínky. To se bude dít tak dlouho, dokud bude zadaná podmínka pravdivá.[ 5 ]

Počet průchodů můžeme počítat například tak, že si zavedeme proměnnou „counter“, které před začátkem cyklu nastavíme hodnotu 0 a v každém průchodu cyklem ji zvýšíme o jedna. Teď ještě potřebujeme počet průchodů porovnat s hodnotou, která nám říká, kolik času máme. Vzhledem k tomu, že velikost této hodnoty určuje náročnost splnění úkolu, pojmenujme si tuto hodnotu jako proměnnou difficulty. A nezapomeňme ji rovnou nastavit v události <on start> – ze svých zkušeností mohu doporučit hodnotu 25. Pokud chcete obtížnější hru, zvolte nižší hodnotu, pokud naopak potřebujete lehčí obtížnost, hodnotu zvyšte.

A aby ke kontrole nedocházelo zbytečně často, dejme v každém průchodu pauzu 100 ms. Teoreticky by se nic nestalo, ale každá kontrola nám spotřebovává nějakou energii a celkově příliš častou kontrolou zahlcujeme výkonnou jednotku, je tedy dobré se naučit dát stoji chvilku oddechu. Výsledek by měl vypadat asi takto:

zadání obtížnosti v makecode

Jenže to je pouze jedna část podmínky – my potřebujeme, aby cyklus ukončilo i naplnění potřeby. Budeme tedy muset podmínku upravit na složený výraz – a to pomocí logické spojky AND. Osobně považuji za přehlednější zároveň použít spojku NOT, kde nám potom vznikne výraz < <NOT [boolean]> AND <counter < difficulty> >. Do chybějícího výrazu u spojky NOT později budeme vkládat výraz vyjadřující naplnění konkrétní potřeby.

Po této úpravě bychom měli získat následující kód, který vložíme do každé z funkcí hungry, gloomy a scared před blok <call evaluation>:[ 6 ]

rozšíření podmínky vmakecode

funkce evaluation

Nyní nadešel čas zásadně přepsat funkci evaluation – doteď jsme pro naše potřeby určovali, zda došla ovečka spokojenosti, stisknutím tlačítka. Teď už jsme ale nechali proběhnout cyklus, který byl ukončen v jednom ze dvou případů – buď byla naplněna potřeba, nebo vypršel čas a hodnota proměnné counter dosáhla hodnoty proměnné difficulty. Už z tohoto slovního popisu je myslím celkem zřejmé, jak zjistíme, který případ nastal: Prostě porovnáme velikost zmíněných proměnných a pokud bude counter menší než difficulty musí být tamagoči spokojený! A co je skvělé, je skutečnost, že to platí pro všechny potřeby!

Nová evaluační funkce se tak bude skládat s poměrně jednoduché podmínky, která rozhodne, zda je ovečka tamagoči šťastná či mrtvá (jak velká odpovědnost je vložena do této pomocné funkce!):

funkce vyhodnocení v makecode

[ TIP ] Předpokládám, že po rozdělení na jednotlivé funkce je i pro vás kód nyní přehlednější. Nevím o žádné obecně uznávané teoretické poučce, jež by říkala, v kterém okamžiku je třeba kód rozdělit na menší podčásti, mohu se však podělit o přístup mého vyučujícího ze střední školy:
„Jedna část kódu (v našem případě funkce) by se měla vejít na obrazovku, abychom se v ní neztratili.“

Dnešní lekce na tomto místě končí – podařilo se nám kostru tamagočiho z minula obalit jednotlivými funkcemi, vytvořit jednotnou evaluaci a to, co našemu tamagočimu chybí k životu je schopnost vnímat okolí. Právě tu potřebujeme k tomu, abychom u funkcí jednotlivých nálad mohli vyplnit klíčovou podmínku a prošli evaluací pozitivně. Téma následující části našeho seriálu je tedy jasné: čtení dat ze senzorů.


[ 4 ] Protože se vždy hodí i další pohled na teorii, mohu doporučit portál microbiti.cz od členů Brněnské buňky projektu Jednoty školských informatiků Informatikáři–Informatikářům – konkrétně článek Pracovní listy – funkce a pole. Jedinou nevýhodou je, že ještě nejsou zapracovány novinky poslední verze prostředí MakeCode.

[ 5 ] Všimněte si, že pokud jako podmínku zadáte logickou konstantu TRUE, bude cyklus vykonávat, dokud bude mít micro:bit přísun energie, nebo ho neresetujete. Pokud naopak nastavíte jako podmínku konstantu FALSE, celý cyklus se přeskočí.

[ 6 ] Já vím, já vím – zase se nám tu opakuje kus kódu. Problém v tomto okamžiku je v tom, že potřebujeme, aby se při každém průchodu znovu naměřila hodnota z odpovídajícího senzoru – mohli bychom sice vytvořit funkci, které bychom předali tuto hodnotu jako parametr, ale problém je přesně v tom, že od okamžiku, kdy se parametr předá, už to bude hodnota, nikoli příkaz k jejímu naměření. Pokud by však někdo přišel na elegantnější řešení, které by umožnilo v prostředí MakeCode neopakovat kód této podmínky, budu rád, když se o něj podělíte v komentářích!

Emmet BrickHacker

Napsat komentář