Programovací prostředí/jazyk Karel možná vypadá na první pohled jako hračka pro malé děti, ale pro výuku dekompozice problémů na jednodušší podúlohy, základy programování a obzvláště rekurzi byste moc vhodnějších nástrojů nenašli. To vše navíc v přirozeném jazyce a s vizuální názorností. My budeme používat mírně upravenou implementaci Oldřicha Jedličky – jako webová aplikace běží bez instalace prakticky kdekoliv a rozumně se ovládá.
PS: „Robota Karla“ vymyslel před více jak třiceti lety Richard E. Pattis ze Stanfordovy university. Své jméno získal na počest spisovatele Karla Čapka, díky jehož hře R.U.R. – Rossum's Universal Robots se slovo robot (které na základě slovanské „roboty“ vymyslel Karlův bratr Josef) dostalo snad do všech světových jazyků.
Robot Karel je jediným obyvatelem města o rozměrech 10x10 políček. Na začátku je město zcela prázdné a Karel vykukuje ze svého domu v jeho levém spodním rohu směrem na východ. Ve městě je však možné stavět zdi a Karel sám umí navíc na políčka pokládat (a naopak z nich zase sbírat) značky, maximálně osm na jedno pole.
Jako správný robot poslouchá Karel Vaše příkazy – na začátku umí přesně čtyři:
KROK
– (pokus o) krok o jedno pole směrem, kterým je Karel natočen
VLEVO VBOK
– otočení Karla o 90° doleva
POLOŽ
– (pokus o) položení jedné značky na pole, na kterém Karel právě stojí
ZVEDNI
– (pokus o) zvednutí jedné značky z pole, na kterém Karel právě stojí
Poznámky „pokus o“ jsou uvedeny zcela úmyslně – pokud po Karlovi chcete něco, co nemůže provést, zahlásí Vám chybu. A pokus o krok mimo město nebo do zdi, položení značky na zcela zaplněné pole a zvednutí značky z prázdného pole jsou přesně tři takovéto „zakázané“ operace. Karel rozeznává i podmínky, které ho před těmito „zádrhely“ dokáží ochránit, ale na ty se podíváme, až se na dalších stránkách naučíme vytvářet nové příkazy a trochu chodit s Karlem po městě.
Karla naučíme novou činnost seskupením volání již známých činností pod jméno nového příkazu:
Naprosto typickou první úlohou je naučit Karla udělat ČELEM VZAD
. Jak na to, když jediný otáčecí příkaz, který znáte, je VLEVO VBOK
? Snadno:
Tímto ke čtyřem vestavěným příkazům KROK
, VLEVO VBOK
, POLOŽ
a ZVEDNI
přibyl příkaz ČELEM VZAD
, který jste Karla právě naučili vykonávat. Od této chvíle tak při vytváření dalších příkazů můžete použít již pět příkazů, kterým Karel rozumí a ví, jak na ně má reagovat.
Pokusme se nyní Karla naučit otočit doprava. Jako první Vás asi napadne následující:
To dá přece rozum – po třech otočeních doleva o 90° bude Karel koukat stejným směrem, jako kdyby se rovnou otočil doprava. Jenže daného cíle můžeme dosáhnout ještě dvěma dalšími způsoby, protože jsme Karla před chvílí naučili udělat ČELEM VZAD
:
Výhodou první varianty je, že k otočení doprava nemusíme Karla naučit žádný další příkaz. Výhodou druhých dvou (i když u něčeho tak krátkého to ještě není moc poznat) je naopak to, že vedou k řešení kratším – a často snad i čitelnějším a jasnějším – kusem kódu.
Jako ponaučení si z této lekce odneste to, že jeden konkrétní problém se dá často vyřešit více než jedním způsobem. Později si ještě ukážeme, že rozhodnout, který ze způsobů je v danou chvíli nejlepší, nemusí být zrovna jednoduchá záležitost.
ČELEM VZAD
i první varianta VPRAVO VBOK
se vyznačují tím, že stejnou část kódu (v tomto případě tedy pouze jeden příkaz VLEVO VBOK
) voláme více než jednou. Většina programovacích jazyků obsahuje pro opakované volání části kódu speciální konstrukci (nebo konstrukce) a Karel není výjimkou – jedná se o příkaz..
..kde místo x dosadíme číslo vyjařující požadovaný počet opakování. Například VPRAVO VBOK
bychom tak mohli zapsat následujícím způsobem:
Pravda, na počtu řádek kódu jsme vůbec neušetřili (a řešit takto ČELEM VZAD
by bylo ještě podivnější – zkuste si to) a smyčkou jsme navíc zatáhli do programu novou konstrukci, se kterou si musí Karel poradit, ale zato jsme explicitně uvedli, že jeden konrétní příkaz VLEVO VBOK
voláme třikrát za sebou. Pokud by se měla opakovat větší část kódu, byli bychom moc rádi, že máme smyčky k dispozici.
Obecně používáme cykly na místech programu, která je třeba opakovat přesně určeným počtem krát. Zrovna v Karlovi – možná k překvapení některých – je zas až tak moc neupotřebíme (pokud si tedy nebudeme chtít např. pomocí pokládání značek nakreslit do města nějaký obrazec), ale do budoucna se nám budou hodit.
Na konec ještě poznamenejme, že u OPAKUJ
je možno úplně vynechat počet opakování, čímž vyrobíme nekonečnou smyčku:
Takovouto smyčku buď musíme ukončit ručně z GUI nebo v sobě musí nějakým způsobem obsahovat ukončení (ať už přímo vyvoláním příkazu STOP
při splnění ukončovací podmínky nebo nepřímo zavoláním dalšího příkazu, který zařídí totéž).
Vidět, že se Karel doprava otočí tak, že vykoná tři otočení doleva, protože VLEVO VBOK
je vestavěný příkaz, který Karel zná, je sice poučné, ale ve chvíli, kdy jsme si to již dostatečně uvědomili, je to také docela otravné a nadále asi zbytečné. Pro případ takovýchto operací, jejichž výsledkem je jedna konkrétní a jasně definovaná akce, má Karel k dispozici příkaz RYCHLE
..
..který způsobí „přeskočení“ vizualizace mezikroků a zobrazí Karla rovnou ve výsledném postavení.
KONEC
je v tomto konkrétním případě možno nahradit i výmluvným POMALU
.
Znovu ale důsledně upozorňuji, že jediné rozumné použití tohoto příkazu je u akcí s jedním konkrétním výsledkem a žádnými meziakcemi! Vidět Karla otočeného rovnou čelem vzad nebo vpravo vbok dává smysl, ale najít ho najednou v protějším rohu, přičemž mezitím z celého města zmizely všechny v něm dříve roztroušené značky, je úplně o ničem...
Předpokládejme na chvíli, že jsme Karla naučili udělat DVOJKROK
a TROJKROK
(přičemž zatím ještě pořád neřešíme otázku případného nabourání do zdi nebo hranic města). ČTYŘKROK
jako posunutí o čtyři políčka daným směrem pak můžeme naprogramovat mnoha vpodstatě ekvivalentními způsoby, např.:
Kromě těchto správných řešení se však můžeme dopracovat ke zdánlivě stejnému výsledku i mnoha jinými způsoby, které však s sebou prakticky vždy nesou nějaký zádrhel. Vřele doporučuji si následující příklady důkladně promyslet, byť jsou velmi jednoduché – ve složitějších (a nepřehlednějších) programech se podobné „chyby“ vyrábějí až příliš snadno a je třeba se jich vyvarovat.
V následujícím řešení se sice dostaneme o požadovaná čtyři pole dále, ale za prvé při tom ujdeme zbytečně moc kroků a za druhé ještě na konci stojíme úplně opačně:
Největší problém tohoto „řešení“ se však skrývá v tom, že ve skutečnosti s Karlem zajdeme během cesty o pět políček dále a pokud náš algoritmus počítal s tím, že nejdále půjdeme o čtyři pole (což by tedy člověk od čtyřkroku čekal, že) a na pátém poli stojí zeď, tak Karel nabourá a vykonávání příkazu zhavaruje!
Následující „oprava“ předchozího „řešení“ Karla sice otočí do správného změru, ale řešení největšího problému (zbytečná návštěva pátého pole) se ani nedotkne:
Následující řešení je už podstatně lepší – Karel se sice během posunu o čtyři pole na prvním poli zcela nesmyslně zatočí jednou kolem dokola, ale kromě zdržování běhu programu to aspoň nezpůsobí havárii:
Jako poslední příklad „řešení“ úlohy o čtyřkroku si ukažme ještě následující program:
Karel sice dojde na požadované místo a dokonce i cestou pěkně rovně po žádaných čtyřech polích, zanechá po sobě ovšem pěkný nepořádek – kdo po nás chtěl, abychom při obyčejném čtyřkroku značkovali každé liché políčko značkou?
Než se rozloučíme se základy programování Karla a podíváme se na podmínky a rekurzi, řekněme si ještě pár slov k psaní programů obecně. Za příklad si vezmeme zase náš oblíbený ČTYŘKROK
, který někdo napsal sice dost rozumně tak, aby Karel nenaboural na pátém políčku do zdi, ovšem zanechal Karla na konci otočeného do nesprávného směru, např. takto:
Dostaneme-li takovýto „čtyřkrok“ k dispozici a nemůžeme jeho definici změnit, relativně dobrým řešením bude rozšířit Karlův slovník známých příkazů o „upravený“ čtyřkrok, např. takto..
..který pak budeme v našem programu používat místo původního.
Na druhou stranu sice možná máme možnost vlézt „dovnitř“ a původní definici opravit, aby žádné přebytečné otáčení, které musíme napravit, na konci nebylo, jenže někdo jiný používá stejnou sadu příkazů a kdo ví proč počítá s tím, že Karel se po provedení čtyřkroku otočí o 180°. V takovém případě bychom si opravou originálu moc nepomohli, protože by se musely přepsat jiné části kódu.
V takovéto chvíli je asi nejčistější provést následující:
Místo původního „čtyřkroku“ budeme radši všude volat příkaz ČTYŘKROK S OTOČENÍM
, aby každému bylo jasné, co doopravdy dělá, a všude jinde, kde budeme potřebovat „správný“ čtyřkrok, budeme používat volání ČTYŘKROK BEZ OTOČENÍ
.
V následujících úlohách si vystačte pouze se základními příkazy (plus těmi, které Karla postupně naučíte) a smyčkami. Nepoužívejte tedy zatím žádné podmínky a rekurzi.
TROJKROK
co nejvíce různými způsoby.