Logika hry

Už umíš vykreslit „fotku“ hada. Hadí videohra ale nebude jen statický obrázek. Had se bude hýbat!

Rozhýbejme hada

Tak, ale teď už k samotné hře!

Tvůj program teď, doufám, vypadá nějak takhle:

from pathlib import Path

import pyglet

TILE_SIZE = 64
TILES_DIRECTORY = Path('snake-tiles')

snake = [(1, 2), (2, 2), (3, 2), (3, 3), (3, 4), (3, 5), (4, 5)]
food = [(2, 0), (5, 1), (1, 4)]

red_image = pyglet.image.load('apple.png')
snake_tiles = {}
for path in TILES_DIRECTORY.glob('*.png'):
    snake_tiles[path.stem] = pyglet.image.load(path)

window = pyglet.window.Window()

@window.event
def on_draw():
    window.clear()
    pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
    pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)
    for x, y in snake:
        source = 'tail'     # (Tady případně je nějaké
        dest = 'head'       #  složitější vybírání políčka)
        snake_tiles[source + '-' + dest].blit(
            x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE)
    for x, y in food:
        red_image.blit(
            x * TILE_SIZE, y * TILE_SIZE, width=TILE_SIZE, height=TILE_SIZE)

pyglet.app.run()

Zkus těsně nad řádek pyglet.app.run doplnit funkci, která se bude volat každou šestinu vteřiny, a přidá hadovi políčko navíc:

def move(dt):
    x, y = snake[-1]
    new_head = x+1, y
    snake.append(new_head)

pyglet.clock.schedule_interval(move, 1/6)

Funguje? Tak do téhle funkce ještě přidej del snake[0], aby had nerostl donekonečna. Víš co tenhle příkaz dělá? Jestli ne, koukni znovu na poznámky k seznamům!

A had se hýbe… Jen ho ještě nejde ovládat.

Ven se stavem

Než uděláme interaktivního hada, zkusíme trošku uklidit. Program se nám rozrůstá, a za chvíli bude složité se v něm vyznat. Můžeme tomu trochu pomoct tím, že ho rozdělíme do dvou souborů: jeden pro logiku hry a druhý na vykreslování (a později ovládání) přes Pyglet.

Udělej si nový soubor pojmenovaný had.py. V něm budeme mít třídu, která spravuje (a obsahuje) celý stav hry.

Všechno, co je potřeba o hře vědět – v našem případně zatím souřadnice hada a jídla – bude tato třída obsahovat jako atributy.

Třída bude obsahovat dvě metody – funkce, které se dají zavolat na objekty této třídy. Speciální metoda __init__ (která se automaticky volá při vytvoření objektu této třídy) bude tyto atributy nastavovat. Metoda move, kterou budeme volat při každém „tahu“ hry, je pak bude měnit.

Pro funkčnost, kterou zatím náš had umí, bude had.py vypadat takto:

class State:
    def __init__(self):
        self.food = [(2, 0), (5, 1), (1, 4)]
        self.snake = [(0, 0), (1, 0)]  # (kratší než v kódu na vykreslování)

    def move(self):
        old_x, old_y = self.snake[-1]
        new_x = old_x + 1
        new_y = old_y
        new_head = new_x, new_y
        self.snake.append(new_head)
        del self.snake[0]

Pužij prosím pro třídu jméno State a i atributy pojmenuj podle materiálů – snake, food, a později i další, které budeme přidávat. Bude se ti to hodit.

Všimni si, že metody berou argument self. To označuje konkrétní objekt, stav hry se kterým metoda pracuje nebo který mění. Ke všem atributúm přistupují pomocí tečky – self.jméno_atributu.

Tak, máme třídu se stavem. No jo, ale jak ji teď použít? Je v jiném souboru než naše hra (ui.py).

Pythonní soubory (ty s příponou .py) jsou zároveň moduly, které se dají importovat. Na začátku ui.py tak můžeš napsat:

from had import State

… a třída se stavem bude k dispozici!

Pak potřebuješ ještě několik změn:

  • Nastavování seznamů snake a food zruš; místo nich nastav jedinou proměnnou state na nový stav:

    state = State()
    
  • Místo snake a food ve funkci on_draw použij state.snake a state.food – atributy našeho stavu.

    Všimni si že tady nepoužíváme self – tohle jméno je pro metody v rámci třídy. Jinde musíme pojmenovat konkrétní objekt, se kterým pracujeme.

  • Funkci move přepiš tak, aby jen volala metodu state.move:

    def move(dt):
        state.move()
    

    Všimni si že ani tady nepoužíváme self. Ten se doplní automaticky – jde o objekt, jehož metodu voláme.

Povedlo se? Funguje to jako předtím? Pro kontrolu můžeš svůj program porovnat s mým (ale nejde o jediné správné řešení):

Řešení

Ovládání

Nyní k onomu slíbenému ovládání. Respektive nejdřív k změnám směru.

Had ze hry se plazí stále stejným směrem, dokud hráč nezmáckne klávesu. Had z naší ukázky se plazí doprava; dokážeš zařídit, aby se místo toho plazil nahoru?

Řešení

A co dolů?

Řešení

Aby si had „pamatoval“ kam se zrovna plazí, je potřeba mít směr součástí stavu hry. Uložme ho tedy do atrubutu jménem snake_direction.

Co tam ale přesně uložit? Jak reprezentovat směr v Pythonu – pomocít čísel, n-tic a tak?

Asi nejpříhodnější řešení je uložit si o kolik políček se had posune, a to zvlášť v x-ovém a zvlášť v y-ovém směru. Čili jako dvojici:

  • (1, 0) = doprava (o jedno políčko v kladném x-ovém směru)
  • (-1, 0) = doleva (o jedno políčko v záporném x-ovém směru)
  • (0, 1) = nahoru (+y)
  • (0, -1) = dolů (-y)

Nový atribut přidej do metody __init__ ve stavu:

        self.snake_direction = 0, 1

A v metodě move změň nastavování new_x a new_y podle nového atributu:

        dir_x, dir_y = self.snake_direction
        new_x = old_x + dir_x
        new_y = old_y + dir_y

Směr hada teď můžeš měnit změnou snake_direction__init__. Funguje to? (Jestli ne, oprav to – a jestli to nejde, zavolej někoho na pomoc!)

Nyní zbývá jen atribut snake_direction měnit, když uživatel něco stiskne na klávesnici. To už je doména Pygletu. Opusť na chvíli abstraktní stav v had.py a koukni na hru v ui.py. Sem je potřeba přidat funkci, která reaguje na stisk klávesy.

Aby Pyglet tuhle funkci našel a uměl zavolat, musí se jmenovat on_key_press, musí mít dekorátor @window.event, a musí brát dva argumenty: číslo klávesy, která byla zmáčknutá, a informace o modifikátorech (Shift, Ctrl, a tak podobně):

@window.event
def on_key_press(symbol, mod):
    ...

Druhý argument nepoužijeme. Podle prvního ale nastav aktuální směr hada. Čísla kláves jsou definována v modulu pyglet.window.key jako konstanty se jmény LEFT, ENTER, Q či AMPERSAND . My použijeme šipky:

@window.event
def on_key_press(symbol, mod):
    if symbol == pyglet.window.key.LEFT:
        state.snake_direction = -1, 0
    if symbol == pyglet.window.key.RIGHT:
        state.snake_direction = 1, 0
    if symbol == pyglet.window.key.DOWN:
        state.snake_direction = 0, -1
    if symbol == pyglet.window.key.UP:
        state.snake_direction = 0, 1

Tuhle funkci je potřeba dát někam za nastavení window (aby byl k dispozici window.event) a před pyglet.app.run() (protože nastavovat ovládání až potom, co hra proběhne, je zbytečné). Nejlepší je ji dát vedle jiné funkce s dekorátorem @window.event, aby byly pěkně pohromadě.

Funguje to? Můžeš ovládat směr hada? To je skvělé! Určitě ale při zkoušení narazíš na pár věcí, které je potřeba dodělat:

  • Had by neměl mít možnost vylézt ven z okýnka.
  • Had by měl jíst jídlo a růst.
  • Hra by měla skončit, když had narazí sám do sebe.

Pojďme je vyřešit, jednu po druhé.

Zatím dobrý, teď ale narazíme

„Hadí“ hry jako ta naše mají dvě varianty: buď je kolem hřiště „zeď“ a hráč při nárazu do okraje prohraje, nebo je hřiště „nekonečné“ – had okrajem proleze a objeví se na druhé straně.

My nakonec naprogramujeme druhou variantu, která je zajímavější. Začneme ale s tou první, která je jednodušší.

Vrať se k souboru se stavem – had.py. Budeme pracovat na chování, na logice hry; ne na vykreslování a ovládání.

Abys zjistil/a, jestli had „vylezl“ z levého okraje okna ven, je potřeba zkontrolovat, jestli x-ová souřadnice hlavy je menší než 0. To je dobré udělat hned poté, co nové souřadnice hlavy získáš – konkrétně hned před řádkem new_head = new_x, new_y v metodě move.

A co při takovém nárazu udělat? Nejjednodušší bude hru ukončit. Na to má Python funkci exit(), která funguje podobně jako když v programu nastane chyba. Jen místo chybového výpisu ukáže daný text.

Ukončení programu není příliš příjemný způsob, jak říct hráčovi že prohrál. Za chvíli ale tuhle část předěláme, tak prozatím tenhle jednoduchý způsob postačí.

    def move(self):
        old_x, old_y = self.snake[-1]
        dir_x, dir_y = self.snake_direction
        new_x = old_x + dir_x
        new_y = old_y + dir_y

        # Nový kód – kontrola vylezení z hrací plochy
        if new_x < 0:
            exit('GAME OVER')

        new_head = new_x, new_y
        self.snake.append(new_head)
        del self.snake[0]

Věřím, že zvládneš udělat stejnou kontrolu pro vylezení ze spodního okraje.

Jak ale ošetřit ty zbylé okraje – pravý a horní? Na to je potřeba znát velikost okýnka. A tu zná Pyglet; třída se stavem k okýnku nemá přístup!

Na velikosti herní plochy závisí chování hry. Tahle informace tedy bude tedy muset být součást stavu. Pro začátek nějakou velikost – třeba 10×10 – nastav v __init__:

        self.width = 10
        self.height = 10

A pak zařiď, aby po nárazu na neviditelnou stěnu kolem hřiště velkého 10×10 políček hra skončila. Vyzkoušej všechny varianty – severní, jižní, východní i západní zeď. (Had je virtuální, nemusíš se bát že mu z toho vyroste boule.)

Řešení

A pak nastav opravdovou velikost herní plochy. Jak? V souboru se hrou (ui.py), hned po tom co vytvoříš stav (state) a okýnko (window) velikost nastav. Použij celočíselné dělení (se zbytkem), aby velikost byla v celých číslech:

state.width = window.width // TILE_SIZE
state.height = window.height // TILE_SIZE

Nekonečná magická klec

Teď místo konce hry při naražení necháme hada „projít“ a objevit se na druhé straně.

Nemělo by to být tak složité udělat – stačí místo exit() vždy správně nastavit příslušnou hodnotu. Je ale potřeba si dát pozor kde použít new_x a kde new_y, kde width a kde height, a kde přičíst nebo odečíst jedničku, aby při číslování od nuly všechno sedělo. Zkus to!

Jestli už vykresluješ hada místo housenky, možná teď narazíš na problém s vybíráním správných dílků – okraj herní plochy hada vizuálně rozdělí na dva menší. Zatím to ignoruj, ale ve volné chvilce se pokus problém opravit. Doporučuji se vrátit k „abstraktní“ funkci, která jen vypisuje souřadnice a směry:

1 2 tail right
2 2 left right
3 2 left top
3 3 bottom top
3 4 bottom top
3 5 bottom right
4 5 left head

Jdeš-li podle návodu, tuhle funkci máš uloženou v souboru smery.py Oprav nejdřív tu, a řešení „transplantuj“ do hry.

Řešení

Jde to jednodušeji? Jde! Matematikové vymysleli operaci, která se jmenuje zbytek po dělení. Ta dělá přesně to, co potřebujeme – zbytek po dělení nové souřadnice velikostí hřiště dá souřadnici, která leží v hřišti. Když byla předchozí souřadnice o jedna větší než maximum, zbytek po dělení bude nula; když byla -1, dostaneme maximum.

Celý kód pro kontrolu a ošetření vylézání z hrací plochy tak jde nahradit tímhle:

        new_x = new_x % self.width
        new_y = new_y % self.height

Podobné matematické „zkratky“ umí programátorům často usnadnit život – ale přijít na ně nebývá jednoduché. Ale nevěš hlavu: neláká-li tě studovat informatiku na škole, věz, že to jde i bez „zkratek“. Jen občas trochu krkoloměji.

Ale jestli tě matematika baví, je tu poznámka pro tebe!

To, že existuje přesně operace kterou potřebujeme, není až tak úplně náhoda. Ona matematická jednoduchost je spíš důvod, proč se hrací plocha u spousty starých her chová právě takhle. Odborně se tomu „takhle“ říká toroidální topologie.

Zkušení matematici si teď možná stěžují na nutnost definovat zbytek po dělení záporných čísel. Proto dodám, že ho Python schválně definuje vhodně pro tento účel; a % b má vždy stejné znaménko jako b.

Krmení

Tak. Had je v pasti, už nemůže vylézt. Co dál?

Teď se musíme o hada postarat: pravidelně ho krmit. Ale ještě předtím je potřeba ho naučit, jak se vůbec jí – na naši potravu ještě není zvyklý. Když to zvládneme, poroste jako z vody!

Konkrétně musíme hlavně zajistit, aby když se had připlazí na políčko s jídlem, tak jídlo zmizelo. K tomu se dá použít operátor in, který zjišťuje jestli něco (třeba souřadnice) je v nějakém seznamu (třeba seznamu souřadnic jídla), a metoda remove, která ze seznamu odstraní daný prvek (podle hodnoty prvku, na rozdíl od del, který maže podle pozice).

Nebudu napínat, kód je následující. Rozumíš mu? Víš, kam je ho potřeba dát?

        if new_head in self.food:
            self.food.remove(new_head)

Řešení

Vyzkoušej, jestli to funguje. Had by měl jíst jídlo.

Ještě ale zbývá zařídit, aby po každém soustu trochu povyrostl. Ale jak? Kterým směrem má růst?

Tady je dobré se podívat na existující kód a uvědomit si, co dělá.

Náš had se plazí tak, že napřed vepředu povyroste (pomocí append) a potom se vzadu zmenší (pomocí del self.snake[0]).

Aby tedy po snězení jídla vyrostl, stačí přeskočit ono zmenšování! Ono přeskočit znamená podmínit, pomocí if. Logika jezení a zmenšování hada tedy bude:

  • Když had sní jídlo, jídlo zmizí. Had se nezmenší.
  • Jinak (tedy když had nesní jídlo) se had zmenší (a tudíž neroste).

Neboli přeloženo do Pythonu:

        if new_head in self.food:
            self.food.remove(new_head)
        else:
            del self.snake[0]

Pro ty, co se začínají ztrácet, dám k dispozici celou metodu move. Běda ale těm, kdo opisují kód bez toho aby mu rozuměli!

Řešení

Nové jídlo

Když už had umí jíst, je potřeba mu zajistit pravidelný přísun jídla. Nejlépe tak, že se každé snězené jídlo nahradí novým.

Přidej do třídy State následující novou metodu, která umí přidat jídlo:

    def add_food(self):
        x = 0
        y = 0
        position = x, y
        self.food.append(position)

Pak tuhle metodu zavolej – najdi v programu kód, který se provádí když je potřeba přidat nové jídlo, a přidej tam následující řádek:

            self.add_food()

Tahle metoda přidává jídlo na pozici (0, 0), tedy stále do stejného rohu. Bylo by ale fajn, kdyby se nové jídlo objevilo vždycky jinde, na náhodném místě. Na to můžeme použít funkci random.randrange, která vrací náhodná celá čísla. Vyzkoušej si ji (z jiného souboru, třeba `experiment.py):

import random

print('Na kostce padlo:', random.randrange(6))

Čím se liší random.randrange od klasické hrací kostky? Uměl/a bys program upravit tak, aby padalo 1 až 6?

Je tahle změna užitečná pro naši hru? Jaký rozsah čísel potřebujeme pro hadí jídlo?

Až na to přijdeš, zkus přidat náhodu do programu: jídlo by se mělo objevit na úplně náhjodném políčku na herní ploše. Nezapomeň na import random – to patří na úplný začátek souboru. Další změny už dělej v metodě add_food.

Řešení

Až to budeš testovat, asi zjistíš, že úplně náhodné políčko není ideální. Občas se totiž jídlo objeví na políčku s hadem, nebo dokonce na jiném jídle. Je proto dobré tuhle situaci zkontrolovat, a když volba padne na plné políčko, jídlo nepřidávat:

        if (position not in self.snake) and (position not in self.food):
            self.food.append(position)

Když ale zkusíš tohle, zjistíš, že občas se nové jídlo vůbec nepřidá. To taky není vhodná varianta – had by tak měl hlad. Co s tím?

Překvapivě dobré (i když ne úplně ideální) řešení je zkusit políčko vybrat několikrát. Když padne prázdné políčko, šup tam s jídlem; když padne plné, tak to prostě zkusit znovu.

Je ale potřeba počet pokusů omezit, aby v situaci, kdy je pole úplně plné, počítač nevybíral donekonečna. Řekněme že když se na 100 pokusů nepodaří prázdné políčko vybrat, vzdáme to.

Metoda add_food po všech úpravách bude vypadat takhle:

    def add_food(self):
        for try_number in range(100):
            x = random.randrange(self.width)
            y = random.randrange(self.height)
            position = x, y
            if (position not in self.snake) and (position not in self.food):
                self.food.append(position)
                # Ukončení funkce ("vyskočí" i z cyklu for)
                return

Jestli ti to funguje, ještě zařiď, aby na začátku hry bylo jídlo na náhodných pozicích.

Řešení

Konec

Had teď může narůst do obrovských rozměrů – a hru stále nelze prohrát. Zařídíme tedy, aby hra skončila, když had narazí sám do sebe.

Na rozdíl od 0/1, které jsme použili výše, buďme trochu opatrnější. Není dobré ukončit celý program; to by se hráčům moc nelíbilo. Ostatně, zkus si, jak to působí – následující kód dej na správné místo a zkus, jak se hra hraje, když skončí hned po nárazu:

        # Kontrola, jestli had narazil
        if new_head in self.snake:
            exit('GAME OVER')

Řešení

Lepší je hru „zapauzovat“ – ukázat hráči situaci, do které nešťastného hada dostal, aby se z ní mohl pro příště poučit.

Aby to bylo možné, dáme do stavu hry další atribut: snake_alive. Ten bude nastavený na True, dokud bude had žít. Když had narazí, nastaví se na False, a od té doby se už nebude pohybovat. Je dobré i graficky ukázat, že hadovi není dobře – hráč pak spíš bude zpytovat svědomí.

Zkus zapřemýšlet, kam v kódu (a i do kterých souborů) patří následující kousky kódu, které prohru implementují:

        # Prvotní nastavení atributu
        self.snake_alive = True
        # Kontrola, jestli had narazil
        if new_head in self.snake:
            self.snake_alive = False
        # Zabránění pohybu
        if not self.snake_alive:
            return
        # Grafická indikace
        if dest == 'head' and not state.snake_alive:
            dest = 'dead'

Řešení

Vylepšení ovládání

Poslední úprava kódu!

Možná si všimneš – zvlášť jestli jsi už nějakou verzi hada hrál/a, že ovládání tvé nové hry je trošku frustrující. A možná není úplně jednoduché přijít na to, proč.

Můžou za to (hlavně) dva důvody.

První problém: když zmáčkneš dvě šipky rychle za sebou, v dalším „tahu“ hada se projeví jen ta druhá. Z pohledu programu je to chování (snad) jasné – po stisknutí šipky se uloží její směr, a při „tahu“ hada se použije poslední uložený směr. S tímhle chováním je ale složité hada rychle otáčet: hráč se musí „trefovat“ do tahů hada. Lepší by bylo, kdyby se ukládaly všechny stisknuté klávesy, a had by v každém tahu reagoval maximálně jednu – další by si „schoval“ na další tahy.

Takovou „frontu“ stisků kláves lze uchovávat v seznamu. Přidej si na to do stavu hry seznam (v metodě __init__):

        self.queued_directions = []

Tuhle frontu plň v ui.py po každém stisku klávesy, metodou append. Je potřeba změnit většinu funkce on_key_press:

@window.event
def on_key_press(symbol, mod):
    if symbol == pyglet.window.key.LEFT:
        new_direction = -1, 0
    if symbol == pyglet.window.key.RIGHT:
        new_direction = 1, 0
    if symbol == pyglet.window.key.DOWN:
        new_direction = 0, -1
    if symbol == pyglet.window.key.UP:
        new_direction = 0, 1
    state.queued_directions.append(new_direction)

A zpátky k logice, v had.py v metodě move místo dir_x, dir_y = self.snake_direction z fronty vyber první nepoužitý prvek (a nezapomeň ho z fronty smazat, ať se dostane i na další!):

        if self.queued_directions:
            new_direction = self.queued_directions[0]
            del self.queued_directions[0]
            self.snake_direction = new_direction

Zkontroluj, že to funguje.

Druhý problém: když se had plazí doleva a hráč zmáčkne šipku doprava, had se otočí a hlavou si narazí do krku. Z pohledu programu to dává smysl: políčko napravo od hlavy je plné, hra tedy končí. Z pohledu hry (a biologie už vůbec!) ale narážení do krku moc smyslu nedává. Lepší by bylo obrácení směru úplně ignorovat.

A jak poznat opačný směr? Když se had plazí doprava – (1, 0) – tak je opačný směr doleva – (-1, 0). Když se plazí dolů – (0, -1) – tak naopak je nahoru – (0, 1). Obecně, k (x, y) je opačný směr (-x, -y).

Zatím ale pracujeme s celými n-ticemi, je potřeba obě na x a y „rozbalit“. Kód tedy bude vypadat takto:

            old_x, old_y = self.snake_direction
            new_x, new_y = new_direction
            if (old_x, old_y) != (-new_x, -new_y):
                self.snake_direction = new_direction

A to je vše?

Gratuluji, máš funkční a hratelnou hru! Doufám že jsi na sebe hrdý/á!

Dej si něco sladkého, zasloužíš si to.


Tady je moje řešení. To se touhle dobou od toho tvého může dost lišit – to je úplně normální. (A nedívej se sem dokud hada nenaprogramuješ sám/sama, Chybami (a neustálým zkoušením) se člověk učí – a programátor zvlášť. Čtením už vyřešeného se učí hůř.)

Řešení

Najdeš ještě nějaké další vylepšení, které by se dalo udělat?

Zkus třeba následující rozšíření:

  • Každých 30 vteřin hry přibude samo od sebe nové jídlo, takže jich pak bude na hrací ploše víc.

  • Hra se bude postupně zrychlovat.
    (Na to je nejlepší předělat funkci moveui.py, aby sama naplánovala, kdy se má příště zavolat. Volání schedule_interval tak už nebude potřeba.)

  • Hadi budou dva; druhý se ovládá klávesami W A S D.
    (Na to je nejlepší udělat novou třídu, Snake, a všechen stav hada přesunout ze State do ní. Ve State pak měj seznam hadů. Téhle změně je potřeba přizpůsobit celý zytek programu.)

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2018/snake-hradec:workshop:7",
      "title": "Had – Logika hry",
      "html": "\n          \n    \n\n    <h1>Logika hry</h1>\n<p>U&#x17E; um&#xED;&#x161; vykreslit &#x201E;fotku&#x201C; hada.\nHad&#xED; videohra ale nebude jen statick&#xFD; obr&#xE1;zek.\nHad se bude h&#xFD;bat!</p>\n<!--\n# Ukládání revizí\n\nXXX - Nestíhám dopsat, omlouvám se\n-->\n\n<h1>Rozh&#xFD;bejme hada</h1>\n<p>Tak, ale te&#x10F; u&#x17E; k&#xA0;samotn&#xE9; h&#x159;e!</p>\n<p>Tv&#x16F;j program te&#x10F;, douf&#xE1;m, vypad&#xE1; n&#x11B;jak takhle:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pyglet</span>\n\n<span class=\"n\">TILE_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n<span class=\"n\">TILES_DIRECTORY</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;snake-tiles&apos;</span><span class=\"p\">)</span>\n\n<span class=\"n\">snake</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">2</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">3</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">3</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">4</span><span class=\"p\">,</span> <span class=\"mi\">5</span><span class=\"p\">)]</span>\n<span class=\"n\">food</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">)]</span>\n\n<span class=\"n\">red_image</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"s1\">&apos;apple.png&apos;</span><span class=\"p\">)</span>\n<span class=\"n\">snake_tiles</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n<span class=\"k\">for</span> <span class=\"n\">path</span> <span class=\"ow\">in</span> <span class=\"n\">TILES_DIRECTORY</span><span class=\"o\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s1\">&apos;*.png&apos;</span><span class=\"p\">):</span>\n    <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">stem</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span>\n\n<span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">Window</span><span class=\"p\">()</span>\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_draw</span><span class=\"p\">():</span>\n    <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glEnable</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_BLEND</span><span class=\"p\">)</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glBlendFunc</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_SRC_ALPHA</span><span class=\"p\">,</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_ONE_MINUS_SRC_ALPHA</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">snake</span><span class=\"p\">:</span>\n        <span class=\"n\">source</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;tail&apos;</span>     <span class=\"c1\"># (Tady p&#x159;&#xED;padn&#x11B; je n&#x11B;jak&#xE9;</span>\n        <span class=\"n\">dest</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;head&apos;</span>       <span class=\"c1\">#  slo&#x17E;it&#x11B;j&#x161;&#xED; vyb&#xED;r&#xE1;n&#xED; pol&#xED;&#x10D;ka)</span>\n        <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">source</span> <span class=\"o\">+</span> <span class=\"s1\">&apos;-&apos;</span> <span class=\"o\">+</span> <span class=\"n\">dest</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">food</span><span class=\"p\">:</span>\n        <span class=\"n\">red_image</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</pre></div><p>Zkus t&#x11B;sn&#x11B; nad &#x159;&#xE1;dek <code>pyglet.app.run</code> doplnit funkci,\nkter&#xE1; se bude volat ka&#x17E;dou &#x161;estinu vte&#x159;iny,\na p&#x159;id&#xE1; hadovi pol&#xED;&#x10D;ko nav&#xED;c:</p>\n<div class=\"highlight\"><pre><code>def move(dt):\n    x, y = snake[-1]\n    new_head = x+1, y\n    snake.append(new_head)\n\npyglet.clock.schedule_interval(move, 1/6)</code></pre></div><p>Funguje?\nTak do t&#xE9;hle funkce je&#x161;t&#x11B; p&#x159;idej <code>del snake[0]</code>, aby had nerostl donekone&#x10D;na.\nV&#xED;&#x161; co tenhle p&#x159;&#xED;kaz d&#x11B;l&#xE1;? Jestli ne, koukni znovu na pozn&#xE1;mky k&#xA0;seznam&#x16F;m!</p>\n<p>A had se h&#xFD;be&#x2026; Jen ho je&#x161;t&#x11B; nejde ovl&#xE1;dat.</p>\n<h2>Ven se stavem</h2>\n<p>Ne&#x17E; ud&#x11B;l&#xE1;me interaktivn&#xED;ho hada, zkus&#xED;me tro&#x161;ku uklidit.\nProgram se n&#xE1;m rozr&#x16F;st&#xE1;, a za chv&#xED;li bude slo&#x17E;it&#xE9; se v&#xA0;n&#x11B;m vyznat.\nM&#x16F;&#x17E;eme tomu trochu pomoct t&#xED;m, &#x17E;e ho rozd&#x11B;l&#xED;me do dvou soubor&#x16F;:\njeden pro <em>logiku hry</em> a druh&#xFD; na <em>vykreslov&#xE1;n&#xED;</em> (a pozd&#x11B;ji ovl&#xE1;d&#xE1;n&#xED;)\np&#x159;es Pyglet.</p>\n<p>Ud&#x11B;lej si nov&#xFD; soubor pojmenovan&#xFD; <code>had.py</code>.\nV&#xA0;n&#x11B;m budeme m&#xED;t <em>t&#x159;&#xED;du</em>, kter&#xE1; spravuje (a obsahuje) cel&#xFD; stav hry.</p>\n<p>V&#x161;echno, co je pot&#x159;eba o h&#x159;e v&#x11B;d&#x11B;t &#x2013; v&#xA0;na&#x161;em p&#x159;&#xED;padn&#x11B; zat&#xED;m sou&#x159;adnice hada\na j&#xED;dla &#x2013; bude tato t&#x159;&#xED;da obsahovat jako <em>atributy</em>.</p>\n<p>T&#x159;&#xED;da bude obsahovat dv&#x11B; <em>metody</em> &#x2013; funkce, kter&#xE9; se daj&#xED; zavolat na objekty\nt&#xE9;to t&#x159;&#xED;dy.\nSpeci&#xE1;ln&#xED; metoda <code>__init__</code> (kter&#xE1; se automaticky vol&#xE1; p&#x159;i vytvo&#x159;en&#xED; objektu\nt&#xE9;to t&#x159;&#xED;dy) bude tyto atributy nastavovat.\nMetoda <code>move</code>, kterou budeme volat p&#x159;i ka&#x17E;d&#xE9;m &#x201E;tahu&#x201C; hry, je pak bude\nm&#x11B;nit.</p>\n<p>Pro funk&#x10D;nost, kterou zat&#xED;m n&#xE1;&#x161; had um&#xED;, bude <code>had.py</code> vypadat takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">class</span> <span class=\"nc\">State</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">2</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">5</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">4</span><span class=\"p\">)]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)]</span>  <span class=\"c1\"># (krat&#x161;&#xED; ne&#x17E; v&#xA0;k&#xF3;du na vykreslov&#xE1;n&#xED;)</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span>\n        <span class=\"n\">new_head</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</pre></div><div class=\"admonition note\"><p>Pu&#x17E;ij pros&#xED;m pro t&#x159;&#xED;du jm&#xE9;no <code>State</code> a i atributy pojmenuj podle\nmateri&#xE1;l&#x16F; &#x2013; <code>snake</code>, <code>food</code>, a pozd&#x11B;ji i dal&#x161;&#xED;, kter&#xE9; budeme p&#x159;id&#xE1;vat.\nBude se ti to hodit.</p>\n</div><p>V&#x161;imni si, &#x17E;e metody berou argument <code>self</code>.\nTo ozna&#x10D;uje konkr&#xE9;tn&#xED; objekt, stav hry se kter&#xFD;m metoda pracuje nebo\nkter&#xFD; m&#x11B;n&#xED;.\nKe v&#x161;em atribut&#xFA;m p&#x159;istupuj&#xED; pomoc&#xED; te&#x10D;ky &#x2013;\n<code>self.<var>jm&#xE9;no_atributu</var></code>.</p>\n<p>Tak, m&#xE1;me t&#x159;&#xED;du se stavem.\nNo jo, ale jak ji te&#x10F; pou&#x17E;&#xED;t?\nJe v&#xA0;jin&#xE9;m souboru ne&#x17E; na&#x161;e hra (<code>ui.py</code>).</p>\n<p>Pythonn&#xED; soubory (ty s&#xA0;p&#x159;&#xED;ponou <code>.py</code>) jsou z&#xE1;rove&#x148; <em>moduly</em>, kter&#xE9; se daj&#xED;\nimportovat.\nNa za&#x10D;&#xE1;tku <code>ui.py</code> tak m&#x16F;&#x17E;e&#x161; napsat:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">had</span> <span class=\"kn\">import</span> <span class=\"n\">State</span>\n</pre></div><p>&#x2026; a t&#x159;&#xED;da se stavem bude k dispozici!</p>\n<p>Pak pot&#x159;ebuje&#x161; je&#x161;t&#x11B; n&#x11B;kolik zm&#x11B;n:</p>\n<ul>\n<li><p>Nastavov&#xE1;n&#xED; seznam&#x16F; <code>snake</code> a <code>food</code> zru&#x161;; m&#xED;sto nich nastav jedinou\nprom&#x11B;nnou <code>state</code> na nov&#xFD; stav:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"n\">State</span><span class=\"p\">()</span>\n</pre></div></li>\n<li><p>M&#xED;sto <code>snake</code> a <code>food</code> ve funkci <code>on_draw</code> pou&#x17E;ij <code>state.snake</code>\na <code>state.food</code> &#x2013; atributy na&#x161;eho stavu.</p>\n<p>V&#x161;imni si &#x17E;e tady nepou&#x17E;&#xED;v&#xE1;me <code>self</code> &#x2013; tohle jm&#xE9;no je pro <em>metody</em> v&#xA0;r&#xE1;mci\nt&#x159;&#xED;dy. Jinde mus&#xED;me pojmenovat konkr&#xE9;tn&#xED; objekt, se kter&#xFD;m pracujeme.</p>\n</li>\n<li><p>Funkci <code>move</code> p&#x159;epi&#x161; tak, aby jen volala metodu <code>state.move</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"n\">dt</span><span class=\"p\">):</span>\n    <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">move</span><span class=\"p\">()</span>\n</pre></div><p>V&#x161;imni si &#x17E;e ani tady nepou&#x17E;&#xED;v&#xE1;me <code>self</code>.\nTen se dopln&#xED; automaticky &#x2013; jde o objekt, jeho&#x17E; metodu vol&#xE1;me.</p>\n</li>\n</ul>\n<p>Povedlo se? Funguje to jako p&#x159;edt&#xED;m?\nPro kontrolu m&#x16F;&#x17E;e&#x161; sv&#x16F;j program porovnat s&#xA0;m&#xFD;m (ale nejde o jedin&#xE9; spr&#xE1;vn&#xE9;\n&#x159;e&#x161;en&#xED;):</p>\n<div class=\"solution\" id=\"solution-0\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/0/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pyglet</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">had</span> <span class=\"kn\">import</span> <span class=\"n\">State</span>\n\n<span class=\"n\">TILE_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n<span class=\"n\">TILES_DIRECTORY</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;snake-tiles&apos;</span><span class=\"p\">)</span>\n\n<span class=\"n\">red_image</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"s1\">&apos;apple.png&apos;</span><span class=\"p\">)</span>\n<span class=\"n\">snake_tiles</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n<span class=\"k\">for</span> <span class=\"n\">path</span> <span class=\"ow\">in</span> <span class=\"n\">TILES_DIRECTORY</span><span class=\"o\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s1\">&apos;*.png&apos;</span><span class=\"p\">):</span>\n    <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">stem</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span>\n\n<span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">Window</span><span class=\"p\">()</span>\n\n<span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"n\">State</span><span class=\"p\">()</span>\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_draw</span><span class=\"p\">():</span>\n    <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glEnable</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_BLEND</span><span class=\"p\">)</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glBlendFunc</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_SRC_ALPHA</span><span class=\"p\">,</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_ONE_MINUS_SRC_ALPHA</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">:</span>\n        <span class=\"n\">source</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;tail&apos;</span>     <span class=\"c1\"># (Tady p&#x159;&#xED;padn&#x11B; je n&#x11B;jak&#xE9;</span>\n        <span class=\"n\">dest</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;head&apos;</span>       <span class=\"c1\">#  slo&#x17E;it&#x11B;j&#x161;&#xED; vyb&#xED;r&#xE1;n&#xED; pol&#xED;&#x10D;ka)</span>\n        <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">source</span> <span class=\"o\">+</span> <span class=\"s1\">&apos;-&apos;</span> <span class=\"o\">+</span> <span class=\"n\">dest</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n        <span class=\"n\">red_image</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"n\">dt</span><span class=\"p\">):</span>\n    <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">move</span><span class=\"p\">()</span>\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">clock</span><span class=\"o\">.</span><span class=\"n\">schedule_interval</span><span class=\"p\">(</span><span class=\"n\">move</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"mi\">6</span><span class=\"p\">)</span>\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</pre></div>\n    </div>\n</div><h2>Ovl&#xE1;d&#xE1;n&#xED;</h2>\n<p>Nyn&#xED; k&#xA0;onomu sl&#xED;ben&#xE9;mu ovl&#xE1;d&#xE1;n&#xED;. Respektive nejd&#x159;&#xED;v k&#xA0;zm&#x11B;n&#xE1;m sm&#x11B;ru.</p>\n<p>Had ze hry se plaz&#xED; st&#xE1;le stejn&#xFD;m sm&#x11B;rem, dokud hr&#xE1;&#x10D; nezm&#xE1;ckne kl&#xE1;vesu.\nHad z na&#x161;&#xED; uk&#xE1;zky se plaz&#xED; doprava; dok&#xE1;&#x17E;e&#x161; za&#x159;&#xED;dit, aby se m&#xED;sto toho\nplazil nahoru?</p>\n<div class=\"solution\" id=\"solution-1\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/1/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p>Ve funkci <code>move</code> je pot&#x159;eba jinak nastavit prom&#x11B;nn&#xE9; <code>new_x</code> a <code>new_y</code>:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"mi\">1</span>\n</pre></div>\n    </div>\n</div><p>A co dol&#x16F;?</p>\n<div class=\"solution\" id=\"solution-2\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/2/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n</pre></div>\n    </div>\n</div><p>Aby si had &#x201E;pamatoval&#x201C; kam se zrovna plaz&#xED;, je pot&#x159;eba m&#xED;t sm&#x11B;r sou&#x10D;&#xE1;st&#xED; stavu\nhry.\nUlo&#x17E;me ho tedy do atrubutu jm&#xE9;nem <code>snake_direction</code>.</p>\n<p>Co tam ale p&#x159;esn&#x11B; ulo&#x17E;it?\nJak reprezentovat sm&#x11B;r v&#xA0;Pythonu &#x2013; pomoc&#xED;t &#x10D;&#xED;sel, <var>n</var>-tic a tak?</p>\n<p>Asi nejp&#x159;&#xED;hodn&#x11B;j&#x161;&#xED; &#x159;e&#x161;en&#xED; je ulo&#x17E;it si o kolik pol&#xED;&#x10D;ek se had posune,\na to zvl&#xE1;&#x161;&#x165; v <var>x</var>-ov&#xE9;m a zvl&#xE1;&#x161;&#x165; v <var>y</var>-ov&#xE9;m sm&#x11B;ru.\n&#x10C;ili jako dvojici:</p>\n<ul>\n<li><code>(1, 0)</code> = doprava (o jedno pol&#xED;&#x10D;ko v&#xA0;kladn&#xE9;m <var>x</var>-ov&#xE9;m sm&#x11B;ru)</li>\n<li><code>(-1, 0)</code> = doleva (o jedno pol&#xED;&#x10D;ko v&#xA0;z&#xE1;porn&#xE9;m <var>x</var>-ov&#xE9;m sm&#x11B;ru)</li>\n<li><code>(0, 1)</code> = nahoru (+<var>y</var>)</li>\n<li><code>(0, -1)</code> = dol&#x16F; (-<var>y</var>)</li>\n</ul>\n<p>Nov&#xFD; atribut p&#x159;idej do metody <code>__init__</code> ve stavu:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>\n</pre></div><p>A v metod&#x11B; <code>move</code> zm&#x11B;&#x148; nastavov&#xE1;n&#xED; <code>new_x</code> a <code>new_y</code> podle nov&#xE9;ho atributu:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"n\">dir_x</span><span class=\"p\">,</span> <span class=\"n\">dir_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"n\">dir_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"n\">dir_y</span>\n</pre></div><p>Sm&#x11B;r hada te&#x10F; m&#x16F;&#x17E;e&#x161; m&#x11B;nit zm&#x11B;nou <code>snake_direction</code> v&#xA0;<code>__init__</code>.\nFunguje to? (Jestli ne, oprav to &#x2013; a jestli to nejde, zavolej n&#x11B;koho na pomoc!)</p>\n<p>Nyn&#xED; zb&#xFD;v&#xE1; jen atribut <code>snake_direction</code> m&#x11B;nit, kdy&#x17E; u&#x17E;ivatel n&#x11B;co stiskne na\nkl&#xE1;vesnici.\nTo u&#x17E; je dom&#xE9;na Pygletu.\nOpus&#x165; na chv&#xED;li abstraktn&#xED; stav v&#xA0;<code>had.py</code> a koukni na hru v&#xA0;<code>ui.py</code>.\nSem je pot&#x159;eba p&#x159;idat funkci, kter&#xE1; reaguje na stisk kl&#xE1;vesy.</p>\n<p>Aby Pyglet tuhle funkci na&#x161;el a um&#x11B;l zavolat, mus&#xED; se jmenovat <code>on_key_press</code>,\nmus&#xED; m&#xED;t dekor&#xE1;tor <code>@window.event</code>, a mus&#xED; br&#xE1;t dva argumenty:\n&#x10D;&#xED;slo kl&#xE1;vesy, kter&#xE1; byla zm&#xE1;&#x10D;knut&#xE1;, a informace o modifik&#xE1;torech\n(Shift, Ctrl, a tak podobn&#x11B;):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">symbol</span><span class=\"p\">,</span> <span class=\"n\">mod</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n</pre></div><p>Druh&#xFD; argument nepou&#x17E;ijeme.\nPodle prvn&#xED;ho ale nastav aktu&#xE1;ln&#xED; sm&#x11B;r hada.\n&#x10C;&#xED;sla kl&#xE1;ves jsou definov&#xE1;na v&#xA0;modulu <code>pyglet.window.key</code> jako konstanty se\njm&#xE9;ny <code>LEFT</code>, <code>ENTER</code>, <code>Q</code> &#x10D;i <code>AMPERSAND</code> .\nMy pou&#x17E;ijeme &#x161;ipky:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">symbol</span><span class=\"p\">,</span> <span class=\"n\">mod</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">LEFT</span><span class=\"p\">:</span>\n        <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">RIGHT</span><span class=\"p\">:</span>\n        <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">DOWN</span><span class=\"p\">:</span>\n        <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">UP</span><span class=\"p\">:</span>\n        <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>\n</pre></div><p>Tuhle funkci je pot&#x159;eba d&#xE1;t n&#x11B;kam za nastaven&#xED; <code>window</code> (aby byl k&#xA0;dispozici\n<code>window.event</code>) a p&#x159;ed <code>pyglet.app.run()</code> (proto&#x17E;e nastavovat ovl&#xE1;d&#xE1;n&#xED; a&#x17E;\npotom, co hra prob&#x11B;hne, je zbyte&#x10D;n&#xE9;).\nNejlep&#x161;&#xED; je ji d&#xE1;t vedle jin&#xE9; funkce s&#xA0;dekor&#xE1;torem <code>@window.event</code>,\naby byly p&#x11B;kn&#x11B; pohromad&#x11B;.</p>\n<p>Funguje to?\nM&#x16F;&#x17E;e&#x161; ovl&#xE1;dat sm&#x11B;r hada?\nTo je skv&#x11B;l&#xE9;!\nUr&#x10D;it&#x11B; ale p&#x159;i zkou&#x161;en&#xED; naraz&#xED;&#x161; na p&#xE1;r v&#x11B;c&#xED;, kter&#xE9; je pot&#x159;eba dod&#x11B;lat:</p>\n<ul>\n<li>Had by nem&#x11B;l m&#xED;t mo&#x17E;nost vyl&#xE9;zt ven z&#xA0;ok&#xFD;nka.</li>\n<li>Had by m&#x11B;l j&#xED;st j&#xED;dlo a r&#x16F;st.</li>\n<li>Hra by m&#x11B;la skon&#x10D;it, kdy&#x17E; had naraz&#xED; s&#xE1;m do sebe.</li>\n</ul>\n<p>Poj&#x10F;me je vy&#x159;e&#x161;it, jednu po druh&#xE9;.</p>\n<h2>Zat&#xED;m dobr&#xFD;, te&#x10F; ale naraz&#xED;me</h2>\n<p>&#x201E;Had&#xED;&#x201C; hry jako ta na&#x161;e maj&#xED; dv&#x11B; varianty: bu&#x10F; je kolem h&#x159;i&#x161;t&#x11B; &#x201E;ze&#x10F;&#x201C;\na hr&#xE1;&#x10D; p&#x159;i n&#xE1;razu do okraje prohraje, nebo je h&#x159;i&#x161;t&#x11B; &#x201E;nekone&#x10D;n&#xE9;&#x201C; &#x2013; had okrajem\nproleze a objev&#xED; se na druh&#xE9; stran&#x11B;.</p>\n<p>My nakonec naprogramujeme druhou variantu, kter&#xE1; je zaj&#xED;mav&#x11B;j&#x161;&#xED;.\nZa&#x10D;neme ale s&#xA0;tou prvn&#xED;, kter&#xE1; je jednodu&#x161;&#x161;&#xED;.</p>\n<p>Vra&#x165; se k&#xA0;souboru se stavem &#x2013; <code>had.py</code>.\nBudeme pracovat na chov&#xE1;n&#xED;, na logice hry; ne na vykreslov&#xE1;n&#xED; a ovl&#xE1;d&#xE1;n&#xED;.</p>\n<p>Abys zjistil/a, jestli had &#x201E;vylezl&#x201C; z&#xA0;lev&#xE9;ho okraje okna ven,\nje pot&#x159;eba zkontrolovat, jestli <var>x</var>-ov&#xE1; sou&#x159;adnice hlavy\nje men&#x161;&#xED; ne&#x17E; 0.\nTo je dobr&#xE9; ud&#x11B;lat hned pot&#xE9;, co nov&#xE9; sou&#x159;adnice hlavy z&#xED;sk&#xE1;&#x161; &#x2013; konkr&#xE9;tn&#x11B;\nhned p&#x159;ed &#x159;&#xE1;dkem <code>new_head = new_x, new_y</code> v&#xA0;metod&#x11B; <code>move</code>.</p>\n<p>A co p&#x159;i takov&#xE9;m n&#xE1;razu ud&#x11B;lat?\nNejjednodu&#x161;&#x161;&#xED; bude hru ukon&#x10D;it.\nNa to m&#xE1; Python funkci <code>exit()</code>, kter&#xE1; funguje podobn&#x11B; jako kdy&#x17E; v&#xA0;programu\nnastane chyba.\nJen m&#xED;sto chybov&#xE9;ho v&#xFD;pisu uk&#xE1;&#x17E;e dan&#xFD; text.</p>\n<p>Ukon&#x10D;en&#xED; programu nen&#xED; p&#x159;&#xED;li&#x161; p&#x159;&#xED;jemn&#xFD; zp&#x16F;sob, jak &#x159;&#xED;ct hr&#xE1;&#x10D;ovi &#x17E;e prohr&#xE1;l.\nZa chv&#xED;li ale tuhle &#x10D;&#xE1;st p&#x159;ed&#x11B;l&#xE1;me, tak prozat&#xED;m tenhle jednoduch&#xFD; zp&#x16F;sob posta&#x10D;&#xED;.</p>\n<div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">dir_x</span><span class=\"p\">,</span> <span class=\"n\">dir_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"n\">dir_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"n\">dir_y</span>\n\n        <span class=\"c1\"># Nov&#xFD; k&#xF3;d &#x2013; kontrola vylezen&#xED; z hrac&#xED; plochy</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n\n        <span class=\"n\">new_head</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</pre></div><p>V&#x11B;&#x159;&#xED;m, &#x17E;e zvl&#xE1;dne&#x161; ud&#x11B;lat stejnou kontrolu pro vylezen&#xED; ze spodn&#xED;ho okraje.</p>\n<p>Jak ale o&#x161;et&#x159;it ty zbyl&#xE9; okraje &#x2013; prav&#xFD; a horn&#xED;?\nNa to je pot&#x159;eba zn&#xE1;t velikost ok&#xFD;nka.\nA tu zn&#xE1; Pyglet; t&#x159;&#xED;da se stavem k&#xA0;ok&#xFD;nku nem&#xE1; p&#x159;&#xED;stup!</p>\n<p>Na velikosti hern&#xED; plochy z&#xE1;vis&#xED; chov&#xE1;n&#xED; hry.\nTahle informace tedy bude tedy muset b&#xFD;t sou&#x10D;&#xE1;st stavu.\nPro za&#x10D;&#xE1;tek n&#x11B;jakou velikost &#x2013; t&#x159;eba 10&#xD7;10 &#x2013; nastav v&#xA0;<code>__init__</code>:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n</pre></div><p>A pak za&#x159;i&#x10F;, aby po n&#xE1;razu na neviditelnou st&#x11B;nu kolem h&#x159;i&#x161;t&#x11B; velk&#xE9;ho\n10&#xD7;10 pol&#xED;&#x10D;ek hra skon&#x10D;ila.\nVyzkou&#x161;ej v&#x161;echny varianty &#x2013; severn&#xED;, ji&#x17E;n&#xED;, v&#xFD;chodn&#xED; i z&#xE1;padn&#xED; ze&#x10F;.\n(Had je virtu&#xE1;ln&#xED;, nemus&#xED;&#x161; se b&#xE1;t &#x17E;e mu z toho vyroste boule.)</p>\n<div class=\"solution\" id=\"solution-3\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/3/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">dir_x</span><span class=\"p\">,</span> <span class=\"n\">dir_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"n\">dir_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"n\">dir_y</span>\n\n        <span class=\"c1\"># Kontrola vylezen&#xED; z hrac&#xED; plochy</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_y</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_y</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n\n        <span class=\"n\">new_head</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</pre></div>\n    </div>\n</div><p>A pak nastav <em>opravdovou</em> velikost hern&#xED; plochy. Jak?\nV&#xA0;souboru se hrou (<code>ui.py</code>), hned po tom co vytvo&#x159;&#xED;&#x161; stav (<code>state</code>)\na ok&#xFD;nko (<code>window</code>) velikost nastav.\nPou&#x17E;ij celo&#x10D;&#xED;seln&#xE9; d&#x11B;len&#xED; (se zbytkem), aby velikost byla v&#xA0;cel&#xFD;ch &#x10D;&#xED;slech:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">//</span> <span class=\"n\">TILE_SIZE</span>\n<span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">//</span> <span class=\"n\">TILE_SIZE</span>\n</pre></div><h2>Nekone&#x10D;n&#xE1; magick&#xE1; klec</h2>\n<p>Te&#x10F; m&#xED;sto konce hry p&#x159;i nara&#x17E;en&#xED; nech&#xE1;me hada &#x201E;proj&#xED;t&#x201C; a objevit se na druh&#xE9;\nstran&#x11B;.</p>\n<p>Nem&#x11B;lo by to b&#xFD;t tak slo&#x17E;it&#xE9; ud&#x11B;lat &#x2013; sta&#x10D;&#xED; m&#xED;sto <code>exit()</code> v&#x17E;dy spr&#xE1;vn&#x11B;\nnastavit p&#x159;&#xED;slu&#x161;nou hodnotu.\nJe ale pot&#x159;eba si d&#xE1;t pozor kde pou&#x17E;&#xED;t <code>new_x</code> a kde <code>new_y</code>, kde <code>width</code> a kde\n<code>height</code>, a kde p&#x159;i&#x10D;&#xED;st nebo ode&#x10D;&#xED;st jedni&#x10D;ku, aby p&#x159;i &#x10D;&#xED;slov&#xE1;n&#xED; od nuly\nv&#x161;echno sed&#x11B;lo.\nZkus to!</p>\n<div class=\"admonition note\"><p>Jestli u&#x17E; vykresluje&#x161; hada m&#xED;sto housenky, mo&#x17E;n&#xE1; te&#x10F; naraz&#xED;&#x161; na probl&#xE9;m\ns&#xA0;vyb&#xED;r&#xE1;n&#xED;m spr&#xE1;vn&#xFD;ch d&#xED;lk&#x16F; &#x2013; okraj hern&#xED; plochy hada vizu&#xE1;ln&#x11B; rozd&#x11B;l&#xED;\nna dva men&#x161;&#xED;.\nZat&#xED;m to ignoruj, ale ve voln&#xE9; chvilce se pokus probl&#xE9;m opravit.\nDoporu&#x10D;uji se vr&#xE1;tit k&#xA0;&#x201E;abstraktn&#xED;&#x201C; funkci, kter&#xE1; jen vypisuje sou&#x159;adnice\na sm&#x11B;ry:</p>\n<div class=\"highlight\"><pre><code>1 2 tail right\n2 2 left right\n3 2 left top\n3 3 bottom top\n3 4 bottom top\n3 5 bottom right\n4 5 left head</code></pre></div><p>Jde&#x161;-li podle n&#xE1;vodu, tuhle funkci m&#xE1;&#x161; ulo&#x17E;enou v&#xA0;souboru <code>smery.py</code>\nOprav nejd&#x159;&#xED;v tu, a &#x159;e&#x161;en&#xED; &#x201E;transplantuj&#x201C; do hry.</p>\n</div><div class=\"solution\" id=\"solution-4\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/4/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Kontrola vylezen&#xED; z hrac&#xED; plochy</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_y</span> <span class=\"o\">&lt;</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n            <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">-</span> <span class=\"mi\">1</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_x</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span><span class=\"p\">:</span>\n            <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_y</span> <span class=\"o\">&gt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span><span class=\"p\">:</span>\n            <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n</pre></div>\n    </div>\n</div><p>Jde to jednodu&#x161;eji? Jde!\nMatematikov&#xE9; vymysleli operaci, kter&#xE1; se jmenuje <em>zbytek po d&#x11B;len&#xED;</em>.\nTa d&#x11B;l&#xE1; p&#x159;esn&#x11B; to, co pot&#x159;ebujeme &#x2013; zbytek po d&#x11B;len&#xED; nov&#xE9; sou&#x159;adnice velikost&#xED;\nh&#x159;i&#x161;t&#x11B; d&#xE1; sou&#x159;adnici, kter&#xE1; le&#x17E;&#xED; v&#xA0;h&#x159;i&#x161;ti.\nKdy&#x17E; byla p&#x159;edchoz&#xED; sou&#x159;adnice o jedna v&#x11B;t&#x161;&#xED; ne&#x17E; maximum,\nzbytek po d&#x11B;len&#xED; bude nula; kdy&#x17E; byla -1, dostaneme maximum.</p>\n<p>Cel&#xFD; k&#xF3;d pro kontrolu a o&#x161;et&#x159;en&#xED; vyl&#xE9;z&#xE1;n&#xED; z&#xA0;hrac&#xED; plochy tak jde\nnahradit t&#xED;mhle:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">new_y</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span>\n</pre></div><p>Podobn&#xE9; matematick&#xE9; &#x201E;zkratky&#x201C; um&#xED; program&#xE1;tor&#x16F;m &#x10D;asto usnadnit &#x17E;ivot &#x2013; ale\np&#x159;ij&#xED;t na n&#x11B; neb&#xFD;v&#xE1; jednoduch&#xE9;.\nAle nev&#x11B;&#x161; hlavu: nel&#xE1;k&#xE1;-li t&#x11B; studovat informatiku na &#x161;kole, v&#x11B;z, &#x17E;e to jde\ni bez &#x201E;zkratek&#x201C;. Jen ob&#x10D;as trochu krkolom&#x11B;ji.</p>\n<div class=\"admonition note\"><p>Ale jestli t&#x11B; matematika bav&#xED;, je tu pozn&#xE1;mka pro tebe!</p>\n<p>To, &#x17E;e existuje p&#x159;esn&#x11B; operace kterou pot&#x159;ebujeme, nen&#xED; a&#x17E; tak &#xFA;pln&#x11B; n&#xE1;hoda.\nOna matematick&#xE1; jednoduchost je sp&#xED;&#x161;  <em>d&#x16F;vod</em>, pro&#x10D; se hrac&#xED; plocha\nu spousty star&#xFD;ch her chov&#xE1; pr&#xE1;v&#x11B; takhle.\nOdborn&#x11B; se tomu &#x201E;takhle&#x201C; &#x159;&#xED;k&#xE1;\n<a href=\"https://en.wikipedia.org/wiki/Torus#Topology\">toroid&#xE1;ln&#xED; topologie</a>.</p>\n<p>Zku&#x161;en&#xED; matematici si te&#x10F; mo&#x17E;n&#xE1; st&#x11B;&#x17E;uj&#xED; na nutnost definovat zbytek po\nd&#x11B;len&#xED; z&#xE1;porn&#xFD;ch &#x10D;&#xED;sel. Proto dod&#xE1;m, &#x17E;e ho Python schv&#xE1;ln&#x11B;\n<a href=\"https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations\">definuje</a>\n<em>vhodn&#x11B;</em> pro tento &#xFA;&#x10D;el; <code>a % b</code> m&#xE1; v&#x17E;dy stejn&#xE9; znam&#xE9;nko jako <code>b</code>.</p>\n</div><h2>Krmen&#xED;</h2>\n<p>Tak. Had je v&#xA0;pasti, u&#x17E; nem&#x16F;&#x17E;e vyl&#xE9;zt.\nCo d&#xE1;l?</p>\n<p>Te&#x10F; se mus&#xED;me o hada postarat: pravideln&#x11B; ho krmit.\nAle je&#x161;t&#x11B; p&#x159;edt&#xED;m je pot&#x159;eba ho nau&#x10D;it, jak se v&#x16F;bec j&#xED; &#x2013; na na&#x161;i potravu\nje&#x161;t&#x11B; nen&#xED; zvykl&#xFD;.\nKdy&#x17E; to zvl&#xE1;dneme, poroste jako z vody!</p>\n<p>Konkr&#xE9;tn&#x11B; mus&#xED;me hlavn&#x11B; zajistit, aby kdy&#x17E; se had p&#x159;iplaz&#xED; na pol&#xED;&#x10D;ko\ns&#xA0;j&#xED;dlem, tak j&#xED;dlo zmizelo.\nK tomu se d&#xE1; pou&#x17E;&#xED;t oper&#xE1;tor <code>in</code>, kter&#xFD; zji&#x161;&#x165;uje jestli n&#x11B;co (t&#x159;eba\nsou&#x159;adnice) je v&#xA0;n&#x11B;jak&#xE9;m seznamu (t&#x159;eba seznamu sou&#x159;adnic j&#xED;dla),\na metoda <code>remove</code>, kter&#xE1; ze seznamu odstran&#xED; dan&#xFD; prvek (podle hodnoty prvku,\nna rozd&#xED;l od <code>del</code>, kter&#xFD; ma&#x17E;e podle pozice).</p>\n<p>Nebudu nap&#xED;nat, k&#xF3;d je n&#xE1;sleduj&#xED;c&#xED;.\nRozum&#xED;&#x161; mu?\nV&#xED;&#x161;, kam je ho pot&#x159;eba d&#xE1;t?</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n</pre></div><div class=\"solution\" id=\"solution-5\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/5/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p>Do metody <code>move</code>, kamkoli za &#x159;&#xE1;dek kter&#xFD; nastavuje <code>new_head</code>.</p>\n    </div>\n</div><p>Vyzkou&#x161;ej, jestli to funguje. Had by m&#x11B;l j&#xED;st j&#xED;dlo.</p>\n<p>Je&#x161;t&#x11B; ale zb&#xFD;v&#xE1; za&#x159;&#xED;dit, aby po ka&#x17E;d&#xE9;m soustu trochu povyrostl.\nAle jak? Kter&#xFD;m sm&#x11B;rem m&#xE1; r&#x16F;st?</p>\n<p>Tady je dobr&#xE9; se pod&#xED;vat na existuj&#xED;c&#xED; k&#xF3;d a uv&#x11B;domit si, co d&#x11B;l&#xE1;.</p>\n<p>N&#xE1;&#x161; had se plaz&#xED; tak, &#x17E;e nap&#x159;ed vep&#x159;edu povyroste (pomoc&#xED; <code>append</code>)\na potom se vzadu zmen&#x161;&#xED; (pomoc&#xED; <code>del self.snake[0]</code>).</p>\n<p>Aby tedy po sn&#x11B;zen&#xED; j&#xED;dla vyrostl, sta&#x10D;&#xED; <em>p&#x159;esko&#x10D;it</em> ono zmen&#x161;ov&#xE1;n&#xED;!\nOno <em>p&#x159;esko&#x10D;it</em> znamen&#xE1; podm&#xED;nit, pomoc&#xED; <code>if</code>.\nLogika jezen&#xED; a zmen&#x161;ov&#xE1;n&#xED; hada tedy bude:</p>\n<ul>\n<li>Kdy&#x17E; had sn&#xED; j&#xED;dlo, j&#xED;dlo zmiz&#xED;. Had se nezmen&#x161;&#xED;.</li>\n<li>Jinak (tedy kdy&#x17E; had <em>nesn&#xED;</em> j&#xED;dlo) se had zmen&#x161;&#xED; (a tud&#xED;&#x17E; neroste).</li>\n</ul>\n<p>Neboli p&#x159;elo&#x17E;eno do Pythonu:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</pre></div><p>Pro ty, co se za&#x10D;&#xED;naj&#xED; ztr&#xE1;cet, d&#xE1;m k dispozici celou metodu <code>move</code>.\nB&#x11B;da ale t&#x11B;m, kdo opisuj&#xED; k&#xF3;d bez toho aby mu rozum&#x11B;li!</p>\n<div class=\"solution\" id=\"solution-6\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/6/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">dir_x</span><span class=\"p\">,</span> <span class=\"n\">dir_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"n\">dir_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"n\">dir_y</span>\n\n        <span class=\"c1\"># Kontrola vylezen&#xED; z hrac&#xED; plochy</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">new_y</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span>\n\n        <span class=\"n\">new_head</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n</pre></div>\n    </div>\n</div><h3>Nov&#xE9; j&#xED;dlo</h3>\n<p>Kdy&#x17E; u&#x17E; had um&#xED; j&#xED;st, je pot&#x159;eba mu zajistit pravideln&#xFD; p&#x159;&#xED;sun j&#xED;dla.\nNejl&#xE9;pe tak, &#x17E;e se ka&#x17E;d&#xE9; sn&#x11B;zen&#xE9; j&#xED;dlo nahrad&#xED; nov&#xFD;m.</p>\n<p>P&#x159;idej do t&#x159;&#xED;dy <code>State</code> n&#xE1;sleduj&#xED;c&#xED; novou metodu, kter&#xE1; um&#xED; p&#x159;idat j&#xED;dlo:</p>\n<div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">add_food</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n        <span class=\"n\">position</span> <span class=\"o\">=</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">position</span><span class=\"p\">)</span>\n</pre></div><p>Pak tuhle metodu zavolej &#x2013; najdi v&#xA0;programu k&#xF3;d, kter&#xFD; se prov&#xE1;d&#xED; kdy&#x17E;\nje pot&#x159;eba p&#x159;idat nov&#xE9; j&#xED;dlo, a p&#x159;idej tam n&#xE1;sleduj&#xED;c&#xED; &#x159;&#xE1;dek:</p>\n<div class=\"highlight\"><pre><span></span>            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n</pre></div><p>Tahle metoda p&#x159;id&#xE1;v&#xE1; j&#xED;dlo na pozici (0, 0), tedy st&#xE1;le do stejn&#xE9;ho rohu.\nBylo by ale fajn, kdyby se nov&#xE9; j&#xED;dlo objevilo v&#x17E;dycky jinde,\nna n&#xE1;hodn&#xE9;m m&#xED;st&#x11B;.\nNa to m&#x16F;&#x17E;eme pou&#x17E;&#xED;t funkci <code>random.randrange</code>, kter&#xE1; vrac&#xED; n&#xE1;hodn&#xE1; cel&#xE1; &#x10D;&#xED;sla.\nVyzkou&#x161;ej si ji (z&#xA0;jin&#xE9;ho souboru, t&#x159;eba <code>`experiment.py</code>):</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">random</span>\n\n<span class=\"k\">print</span><span class=\"p\">(</span><span class=\"s1\">&apos;Na kostce padlo:&apos;</span><span class=\"p\">,</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">6</span><span class=\"p\">))</span>\n</pre></div><p>&#x10C;&#xED;m se li&#x161;&#xED; <code>random.randrange</code> od klasick&#xE9; hrac&#xED; kostky?\nUm&#x11B;l/a bys program upravit tak, aby padalo 1 a&#x17E; 6?</p>\n<p>Je tahle zm&#x11B;na u&#x17E;ite&#x10D;n&#xE1; pro na&#x161;i hru? Jak&#xFD; rozsah &#x10D;&#xED;sel pot&#x159;ebujeme pro had&#xED; j&#xED;dlo?</p>\n<p>A&#x17E; na to p&#x159;ijde&#x161;, zkus p&#x159;idat n&#xE1;hodu do programu: j&#xED;dlo by se m&#x11B;lo objevit\nna <em>&#xFA;pln&#x11B; n&#xE1;hjodn&#xE9;m</em> pol&#xED;&#x10D;ku na hern&#xED; plo&#x161;e.\nNezapome&#x148; na <code>import random</code> &#x2013; to pat&#x159;&#xED; na &#xFA;pln&#xFD; za&#x10D;&#xE1;tek souboru.\nDal&#x161;&#xED; zm&#x11B;ny u&#x17E; d&#x11B;lej v metod&#x11B; <code>add_food</code>.</p>\n<div class=\"solution\" id=\"solution-7\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/7/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">add_food</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span><span class=\"p\">)</span>\n        <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span><span class=\"p\">)</span>\n        <span class=\"n\">position</span> <span class=\"o\">=</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">position</span><span class=\"p\">)</span>\n</pre></div>\n    </div>\n</div><p>A&#x17E; to bude&#x161; testovat, asi zjist&#xED;&#x161;, &#x17E;e <em>&#xFA;pln&#x11B; n&#xE1;hodn&#xE9;</em> pol&#xED;&#x10D;ko nen&#xED; ide&#xE1;ln&#xED;.\nOb&#x10D;as se  toti&#x17E; j&#xED;dlo objev&#xED; na pol&#xED;&#x10D;ku s&#xA0;hadem, nebo dokonce na jin&#xE9;m j&#xED;dle.\nJe proto dobr&#xE9; tuhle situaci zkontrolovat, a kdy&#x17E; volba padne na pln&#xE9; pol&#xED;&#x10D;ko,\nj&#xED;dlo nep&#x159;id&#xE1;vat:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">):</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">position</span><span class=\"p\">)</span>\n</pre></div><p>Kdy&#x17E; ale zkus&#xED;&#x161; <em>tohle</em>, zjist&#xED;&#x161;, &#x17E;e ob&#x10D;as se nov&#xE9; j&#xED;dlo v&#x16F;bec nep&#x159;id&#xE1;.\nTo taky nen&#xED; vhodn&#xE1; varianta &#x2013; had by tak m&#x11B;l hlad.\nCo s&#xA0;t&#xED;m?</p>\n<p>P&#x159;ekvapiv&#x11B; dobr&#xE9; (i kdy&#x17E; ne <em>&#xFA;pln&#x11B;</em> ide&#xE1;ln&#xED;) &#x159;e&#x161;en&#xED; je zkusit pol&#xED;&#x10D;ko vybrat\nn&#x11B;kolikr&#xE1;t.\nKdy&#x17E; padne pr&#xE1;zdn&#xE9; pol&#xED;&#x10D;ko, &#x161;up tam s j&#xED;dlem; kdy&#x17E; padne pln&#xE9;, tak to\nprost&#x11B; zkusit znovu.</p>\n<p>Je ale pot&#x159;eba po&#x10D;et pokus&#x16F; omezit, aby v&#xA0;situaci, kdy je pole <em>&#xFA;pln&#x11B;</em> pln&#xE9;,\npo&#x10D;&#xED;ta&#x10D; nevyb&#xED;ral donekone&#x10D;na.\n&#x158;ekn&#x11B;me &#x17E;e kdy&#x17E; se na 100 pokus&#x16F; nepoda&#x159;&#xED; pr&#xE1;zdn&#xE9; pol&#xED;&#x10D;ko vybrat,\nvzd&#xE1;me to.</p>\n<p>Metoda <code>add_food</code> po v&#x161;ech &#xFA;prav&#xE1;ch bude vypadat takhle:</p>\n<div class=\"highlight\"><pre><span></span>    <span class=\"k\">def</span> <span class=\"nf\">add_food</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">try_number</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span><span class=\"p\">)</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span><span class=\"p\">)</span>\n            <span class=\"n\">position</span> <span class=\"o\">=</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">position</span><span class=\"p\">)</span>\n                <span class=\"c1\"># Ukon&#x10D;en&#xED; funkce (&quot;vysko&#x10D;&#xED;&quot; i z cyklu for)</span>\n                <span class=\"k\">return</span>\n</pre></div><p>Jestli ti to funguje, je&#x161;t&#x11B; za&#x159;i&#x10F;, aby na za&#x10D;&#xE1;tku hry bylo j&#xED;dlo na n&#xE1;hodn&#xFD;ch\npozic&#xED;ch.</p>\n<div class=\"solution\" id=\"solution-8\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/8/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p>V&#xA0;metod&#x11B; <code>__init__</code> se d&#xE1; m&#xED;sto nastaven&#xED; <code>self.food</code> na seznam s&#xA0;pozicemi\nj&#xED;dla napsat:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n</pre></div><p>Pak budou na za&#x10D;&#xE1;tku hry na hada &#x10D;ekat dv&#x11B; n&#xE1;hodn&#xE9; j&#xED;dla.</p>\n    </div>\n</div><h2>Konec</h2>\n<p>Had te&#x10F; m&#x16F;&#x17E;e nar&#x16F;st do obrovsk&#xFD;ch rozm&#x11B;r&#x16F; &#x2013; a hru st&#xE1;le nelze prohr&#xE1;t.\nZa&#x159;&#xED;d&#xED;me tedy, aby hra skon&#x10D;ila, kdy&#x17E; had naraz&#xED; s&#xE1;m do sebe.</p>\n<p>Na rozd&#xED;l od <code>0/1</code>, kter&#xE9; jsme pou&#x17E;ili v&#xFD;&#x161;e, bu&#x10F;me trochu opatrn&#x11B;j&#x161;&#xED;.\nNen&#xED; dobr&#xE9; ukon&#x10D;it cel&#xFD; program; to by se hr&#xE1;&#x10D;&#x16F;m moc nel&#xED;bilo.\nOstatn&#x11B;, zkus si, jak to p&#x16F;sob&#xED; &#x2013; n&#xE1;sleduj&#xED;c&#xED; k&#xF3;d dej na spr&#xE1;vn&#xE9; m&#xED;sto\na zkus, jak se hra hraje, kdy&#x17E; skon&#x10D;&#xED; hned po n&#xE1;razu:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Kontrola, jestli had narazil</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">:</span>\n            <span class=\"nb\">exit</span><span class=\"p\">(</span><span class=\"s1\">&apos;GAME OVER&apos;</span><span class=\"p\">)</span>\n</pre></div><div class=\"solution\" id=\"solution-9\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/9/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p>K&#xF3;d pat&#x159;&#xED; do metody <code>move</code>, hned za nastaven&#xED; prom&#x11B;nn&#xE9; <code>new_head</code>.</p>\n    </div>\n</div><p>Lep&#x161;&#xED; je hru &#x201E;zapauzovat&#x201C; &#x2013; uk&#xE1;zat hr&#xE1;&#x10D;i situaci, do kter&#xE9; ne&#x161;&#x165;astn&#xE9;ho hada\ndostal, aby se z n&#xED; mohl pro p&#x159;&#xED;&#x161;t&#x11B; pou&#x10D;it.</p>\n<p>Aby to bylo mo&#x17E;n&#xE9;, d&#xE1;me do stavu hry dal&#x161;&#xED; atribut: <code>snake_alive</code>.\nTen bude nastaven&#xFD; na <code>True</code>, dokud bude had &#x17E;&#xED;t.\nKdy&#x17E; had naraz&#xED;, nastav&#xED; se na <code>False</code>, a od t&#xE9; doby se u&#x17E; nebude pohybovat.\nJe dobr&#xE9; i graficky uk&#xE1;zat, &#x17E;e hadovi nen&#xED; dob&#x159;e &#x2013; hr&#xE1;&#x10D; pak sp&#xED;&#x161; bude\nzpytovat sv&#x11B;dom&#xED;.</p>\n<p>Zkus zap&#x159;em&#xFD;&#x161;let, kam v&#xA0;k&#xF3;du (a i do kter&#xFD;ch soubor&#x16F;) pat&#x159;&#xED; n&#xE1;sleduj&#xED;c&#xED;\nkousky k&#xF3;du, kter&#xE9; prohru implementuj&#xED;:</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Prvotn&#xED; nastaven&#xED; atributu</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n</pre></div><div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Kontrola, jestli had narazil</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n</pre></div><div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Zabr&#xE1;n&#x11B;n&#xED; pohybu</span>\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n</pre></div><div class=\"highlight\"><pre><span></span>        <span class=\"c1\"># Grafick&#xE1; indikace</span>\n        <span class=\"k\">if</span> <span class=\"n\">dest</span> <span class=\"o\">==</span> <span class=\"s1\">&apos;head&apos;</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span><span class=\"p\">:</span>\n            <span class=\"n\">dest</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;dead&apos;</span>\n</pre></div><div class=\"solution\" id=\"solution-10\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/10/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <ul>\n<li>&#x201E;Prvotn&#xED; nastaven&#xED; atributu&#x201C; do metody <code>__init__</code>.</li>\n<li>&#x201E;Kontrola, jestli had narazil&#x201C; do <code>move</code> m&#xED;sto p&#x16F;vodn&#xED; kontroly,\nkdy se hra ukon&#x10D;ila pomoc&#xED; <code>exit()</code>.</li>\n<li>&#x201E;Zabr&#xE1;n&#x11B;n&#xED; pohybu&#x201C; na &#xFA;pln&#xFD; za&#x10D;&#xE1;tek metody <code>move</code> (p&#x159;&#xED;kaz <code>return</code>\nokam&#x17E;it&#x11B; ukon&#x10D;&#xED; prov&#xE1;d&#x11B;n&#xED; metody).</li>\n<li>&#x201E;Grafick&#xE1; indikace&#x201C; do <code>ui.py</code>, za sekci pro vyb&#xED;r&#xE1;n&#xED; obr&#xE1;zku pro kousek\nhada.</li>\n</ul>\n    </div>\n</div><h2>Vylep&#x161;en&#xED; ovl&#xE1;d&#xE1;n&#xED;</h2>\n<p>Posledn&#xED; &#xFA;prava k&#xF3;du!</p>\n<p>Mo&#x17E;n&#xE1; si v&#x161;imne&#x161; &#x2013; zvl&#xE1;&#x161;&#x165; jestli jsi u&#x17E; n&#x11B;jakou verzi hada hr&#xE1;l/a,\n&#x17E;e ovl&#xE1;d&#xE1;n&#xED; tv&#xE9; nov&#xE9; hry je tro&#x161;ku frustruj&#xED;c&#xED;.\nA mo&#x17E;n&#xE1; nen&#xED; &#xFA;pln&#x11B; jednoduch&#xE9; p&#x159;ij&#xED;t na to, pro&#x10D;.</p>\n<p>M&#x16F;&#x17E;ou za to (hlavn&#x11B;) dva d&#x16F;vody.</p>\n<p>Prvn&#xED; probl&#xE9;m: kdy&#x17E; zm&#xE1;&#x10D;kne&#x161; dv&#x11B; &#x161;ipky rychle za sebou, v&#xA0;dal&#x161;&#xED;m &#x201E;tahu&#x201C;\nhada se projev&#xED; jen ta druh&#xE1;.\nZ&#xA0;pohledu programu je to chov&#xE1;n&#xED; (snad) jasn&#xE9; &#x2013; po stisknut&#xED; &#x161;ipky se ulo&#x17E;&#xED;\njej&#xED; sm&#x11B;r, a p&#x159;i &#x201E;tahu&#x201C; hada se pou&#x17E;ije posledn&#xED; ulo&#x17E;en&#xFD; sm&#x11B;r.\nS t&#xED;mhle chov&#xE1;n&#xED;m je ale slo&#x17E;it&#xE9; hada rychle ot&#xE1;&#x10D;et: hr&#xE1;&#x10D; se mus&#xED; &#x201E;trefovat&#x201C;\ndo tah&#x16F; hada.\nLep&#x161;&#xED; by bylo, kdyby se ukl&#xE1;daly <em>v&#x161;echny</em> stisknut&#xE9; kl&#xE1;vesy, a had by\nv&#xA0;ka&#x17E;d&#xE9;m tahu reagoval maxim&#xE1;ln&#x11B; jednu &#x2013; dal&#x161;&#xED; by si &#x201E;schoval&#x201C; na dal&#x161;&#xED; tahy.</p>\n<p>Takovou &#x201E;frontu&#x201C; stisk&#x16F; kl&#xE1;ves lze uchov&#xE1;vat v&#xA0;seznamu.\nP&#x159;idej si na to do stavu hry seznam (v&#xA0;metod&#x11B; <code>__init__</code>):</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n</pre></div><p>Tuhle frontu pl&#x148; v&#xA0;<code>ui.py</code> po ka&#x17E;d&#xE9;m stisku kl&#xE1;vesy, metodou <code>append</code>.\nJe pot&#x159;eba zm&#x11B;nit v&#x11B;t&#x161;inu funkce <code>on_key_press</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">symbol</span><span class=\"p\">,</span> <span class=\"n\">mod</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">LEFT</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">RIGHT</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">DOWN</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">UP</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>\n    <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_direction</span><span class=\"p\">)</span>\n</pre></div><p>A zp&#xE1;tky k&#xA0;logice, v&#xA0;<code>had.py</code> v&#xA0;metod&#x11B; <code>move</code> m&#xED;sto\n<code>dir_x, dir_y = self.snake_direction</code> z&#xA0;fronty vyber prvn&#xED; nepou&#x17E;it&#xFD; prvek\n(a nezapome&#x148; ho z&#xA0;fronty smazat, a&#x165; se dostane i na dal&#x161;&#xED;!):</p>\n<div class=\"highlight\"><pre><span></span>        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">:</span>\n            <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"n\">new_direction</span>\n</pre></div><p>Zkontroluj, &#x17E;e to funguje.</p>\n<p>Druh&#xFD; probl&#xE9;m: kdy&#x17E; se had plaz&#xED; doleva a hr&#xE1;&#x10D; zm&#xE1;&#x10D;kne &#x161;ipku doprava,\nhad se oto&#x10D;&#xED; a hlavou si naraz&#xED; do krku.\nZ&#xA0;pohledu programu to d&#xE1;v&#xE1; smysl: pol&#xED;&#x10D;ko napravo od hlavy je pln&#xE9;,\nhra tedy kon&#x10D;&#xED;.\nZ pohledu hry (a biologie u&#x17E; v&#x16F;bec!) ale nar&#xE1;&#x17E;en&#xED; do krku moc smyslu ned&#xE1;v&#xE1;.\nLep&#x161;&#xED; by bylo obr&#xE1;cen&#xED; sm&#x11B;ru &#xFA;pln&#x11B; ignorovat.</p>\n<p>A jak poznat opa&#x10D;n&#xFD; sm&#x11B;r?\nKdy&#x17E; se had plaz&#xED; doprava &#x2013; (1, 0) &#x2013; tak je opa&#x10D;n&#xFD; sm&#x11B;r doleva &#x2013; (-1, 0).\nKdy&#x17E; se plaz&#xED; dol&#x16F; &#x2013; (0, -1) &#x2013; tak naopak je nahoru &#x2013; (0, 1).\nObecn&#x11B;, k&#xA0;(<var>x</var>, <var>y</var>) je opa&#x10D;n&#xFD; sm&#x11B;r\n(-<var>x</var>, -<var>y</var>).</p>\n<p>Zat&#xED;m ale pracujeme s&#xA0;cel&#xFD;mi <var>n</var>-ticemi, je pot&#x159;eba ob&#x11B;\nna <var>x</var> a <var>y</var> &#x201E;rozbalit&#x201C;.\nK&#xF3;d tedy bude vypadat takto:</p>\n<div class=\"highlight\"><pre><span></span>            <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n            <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">new_direction</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"n\">new_y</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"n\">new_direction</span>\n</pre></div><h2>A to je v&#x161;e?</h2>\n<p>Gratuluji, m&#xE1;&#x161; funk&#x10D;n&#xED; a hratelnou hru!\nDouf&#xE1;m &#x17E;e jsi na sebe hrd&#xFD;/&#xE1;!</p>\n<p>Dej si n&#x11B;co sladk&#xE9;ho, zaslou&#x17E;&#xED;&#x161; si to.</p>\n<hr>\n<p>Tady je moje &#x159;e&#x161;en&#xED;.\nTo se touhle dobou od toho tv&#xE9;ho m&#x16F;&#x17E;e dost li&#x161;it &#x2013; to je &#xFA;pln&#x11B; norm&#xE1;ln&#xED;.\n(A ned&#xED;vej se sem dokud hada nenaprogramuje&#x161; s&#xE1;m/sama,\nChybami (a neust&#xE1;l&#xFD;m zkou&#x161;en&#xED;m) se &#x10D;lov&#x11B;k u&#x10D;&#xED; &#x2013; a program&#xE1;tor zvl&#xE1;&#x161;&#x165;.\n&#x10C;ten&#xED;m u&#x17E; vy&#x159;e&#x161;en&#xE9;ho se u&#x10D;&#xED; h&#x16F;&#x159;.)</p>\n<div class=\"solution\" id=\"solution-11\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2018/snake-hradec/snake/logic/index/solutions/11/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <p><code>had.py</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">random</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">State</span><span class=\"p\">:</span>\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span> <span class=\"o\">=</span> <span class=\"p\">[(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">),</span> <span class=\"p\">(</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span><span class=\"p\">)]</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"mi\">10</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span> <span class=\"o\">=</span> <span class=\"bp\">True</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span> <span class=\"o\">=</span> <span class=\"p\">[]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">:</span>\n            <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n            <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n            <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">new_direction</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span><span class=\"p\">)</span> <span class=\"o\">!=</span> <span class=\"p\">(</span><span class=\"o\">-</span><span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"n\">new_y</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span> <span class=\"o\">=</span> <span class=\"n\">new_direction</span>\n\n        <span class=\"k\">if</span> <span class=\"ow\">not</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span><span class=\"p\">:</span>\n            <span class=\"k\">return</span>\n\n        <span class=\"n\">old_x</span><span class=\"p\">,</span> <span class=\"n\">old_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">]</span>\n        <span class=\"n\">dir_x</span><span class=\"p\">,</span> <span class=\"n\">dir_y</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_direction</span>\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">old_x</span> <span class=\"o\">+</span> <span class=\"n\">dir_x</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">old_y</span> <span class=\"o\">+</span> <span class=\"n\">dir_y</span>\n\n        <span class=\"n\">new_x</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span>\n        <span class=\"n\">new_y</span> <span class=\"o\">=</span> <span class=\"n\">new_y</span> <span class=\"o\">%</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span>\n\n        <span class=\"n\">new_head</span> <span class=\"o\">=</span> <span class=\"n\">new_x</span><span class=\"p\">,</span> <span class=\"n\">new_y</span>\n        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span> <span class=\"o\">=</span> <span class=\"bp\">False</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">new_head</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">new_head</span><span class=\"p\">)</span>\n            <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">add_food</span><span class=\"p\">()</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"k\">del</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">add_food</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"k\">for</span> <span class=\"n\">try_number</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mi\">100</span><span class=\"p\">):</span>\n            <span class=\"n\">x</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">width</span><span class=\"p\">)</span>\n            <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">height</span><span class=\"p\">)</span>\n            <span class=\"n\">position</span> <span class=\"o\">=</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span>\n            <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">)</span> <span class=\"ow\">and</span> <span class=\"p\">(</span><span class=\"n\">position</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">):</span>\n                <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">position</span><span class=\"p\">)</span>\n                <span class=\"k\">return</span>\n</pre></div><p><code>ui.py</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">pathlib</span> <span class=\"kn\">import</span> <span class=\"n\">Path</span>\n\n<span class=\"kn\">import</span> <span class=\"nn\">pyglet</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">had</span> <span class=\"kn\">import</span> <span class=\"n\">State</span>\n\n<span class=\"n\">TILE_SIZE</span> <span class=\"o\">=</span> <span class=\"mi\">64</span>\n<span class=\"n\">TILES_DIRECTORY</span> <span class=\"o\">=</span> <span class=\"n\">Path</span><span class=\"p\">(</span><span class=\"s1\">&apos;snake-tiles&apos;</span><span class=\"p\">)</span>\n\n<span class=\"n\">red_image</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"s1\">&apos;apple.png&apos;</span><span class=\"p\">)</span>\n<span class=\"n\">snake_tiles</span> <span class=\"o\">=</span> <span class=\"p\">{}</span>\n<span class=\"k\">for</span> <span class=\"n\">path</span> <span class=\"ow\">in</span> <span class=\"n\">TILES_DIRECTORY</span><span class=\"o\">.</span><span class=\"n\">glob</span><span class=\"p\">(</span><span class=\"s1\">&apos;*.png&apos;</span><span class=\"p\">):</span>\n    <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">path</span><span class=\"o\">.</span><span class=\"n\">stem</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">image</span><span class=\"o\">.</span><span class=\"n\">load</span><span class=\"p\">(</span><span class=\"n\">path</span><span class=\"p\">)</span>\n\n<span class=\"n\">window</span> <span class=\"o\">=</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">Window</span><span class=\"p\">()</span>\n\n<span class=\"n\">state</span> <span class=\"o\">=</span> <span class=\"n\">State</span><span class=\"p\">()</span>\n<span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">width</span> <span class=\"o\">//</span> <span class=\"n\">TILE_SIZE</span>\n<span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">=</span> <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">height</span> <span class=\"o\">//</span> <span class=\"n\">TILE_SIZE</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_draw</span><span class=\"p\">():</span>\n    <span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">clear</span><span class=\"p\">()</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glEnable</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_BLEND</span><span class=\"p\">)</span>\n    <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">glBlendFunc</span><span class=\"p\">(</span><span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_SRC_ALPHA</span><span class=\"p\">,</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">gl</span><span class=\"o\">.</span><span class=\"n\">GL_ONE_MINUS_SRC_ALPHA</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake</span><span class=\"p\">:</span>\n        <span class=\"n\">source</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;tail&apos;</span>     <span class=\"c1\"># (Tady p&#x159;&#xED;padn&#x11B; je n&#x11B;jak&#xE9;</span>\n        <span class=\"n\">dest</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;head&apos;</span>       <span class=\"c1\">#  slo&#x17E;it&#x11B;j&#x161;&#xED; vyb&#xED;r&#xE1;n&#xED; pol&#xED;&#x10D;ka)</span>\n        <span class=\"k\">if</span> <span class=\"n\">dest</span> <span class=\"o\">==</span> <span class=\"s1\">&apos;head&apos;</span> <span class=\"ow\">and</span> <span class=\"ow\">not</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">snake_alive</span><span class=\"p\">:</span>\n            <span class=\"n\">dest</span> <span class=\"o\">=</span> <span class=\"s1\">&apos;dead&apos;</span>\n        <span class=\"n\">snake_tiles</span><span class=\"p\">[</span><span class=\"n\">source</span> <span class=\"o\">+</span> <span class=\"s1\">&apos;-&apos;</span> <span class=\"o\">+</span> <span class=\"n\">dest</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n    <span class=\"k\">for</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"ow\">in</span> <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">food</span><span class=\"p\">:</span>\n        <span class=\"n\">red_image</span><span class=\"o\">.</span><span class=\"n\">blit</span><span class=\"p\">(</span>\n            <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">*</span> <span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">width</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">,</span> <span class=\"n\">height</span><span class=\"o\">=</span><span class=\"n\">TILE_SIZE</span><span class=\"p\">)</span>\n\n\n<span class=\"nd\">@window.event</span>\n<span class=\"k\">def</span> <span class=\"nf\">on_key_press</span><span class=\"p\">(</span><span class=\"n\">symbol</span><span class=\"p\">,</span> <span class=\"n\">mod</span><span class=\"p\">):</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">LEFT</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"o\">-</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">RIGHT</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"mi\">0</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">DOWN</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"o\">-</span><span class=\"mi\">1</span>\n    <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"o\">==</span> <span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">window</span><span class=\"o\">.</span><span class=\"n\">key</span><span class=\"o\">.</span><span class=\"n\">UP</span><span class=\"p\">:</span>\n        <span class=\"n\">new_direction</span> <span class=\"o\">=</span> <span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"mi\">1</span>\n    <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">queued_directions</span><span class=\"o\">.</span><span class=\"n\">append</span><span class=\"p\">(</span><span class=\"n\">new_direction</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">move</span><span class=\"p\">(</span><span class=\"n\">dt</span><span class=\"p\">):</span>\n    <span class=\"n\">state</span><span class=\"o\">.</span><span class=\"n\">move</span><span class=\"p\">()</span>\n\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">clock</span><span class=\"o\">.</span><span class=\"n\">schedule_interval</span><span class=\"p\">(</span><span class=\"n\">move</span><span class=\"p\">,</span> <span class=\"mi\">1</span><span class=\"o\">/</span><span class=\"mi\">6</span><span class=\"p\">)</span>\n\n<span class=\"n\">pyglet</span><span class=\"o\">.</span><span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">run</span><span class=\"p\">()</span>\n</pre></div>\n    </div>\n</div><p>Najde&#x161; je&#x161;t&#x11B; n&#x11B;jak&#xE9; dal&#x161;&#xED; vylep&#x161;en&#xED;, kter&#xE9; by se dalo ud&#x11B;lat?</p>\n<p>Zkus t&#x159;eba n&#xE1;sleduj&#xED;c&#xED; roz&#x161;&#xED;&#x159;en&#xED;:</p>\n<ul>\n<li><p>Ka&#x17E;d&#xFD;ch 30 vte&#x159;in hry p&#x159;ibude samo od sebe nov&#xE9; j&#xED;dlo,\ntak&#x17E;e jich pak bude na hrac&#xED; plo&#x161;e v&#xED;c.</p>\n</li>\n<li><p>Hra se bude postupn&#x11B; zrychlovat.<br>\n<em>(Na to je nejlep&#x161;&#xED; p&#x159;ed&#x11B;lat funkci <code>move</code> v&#xA0;<code>ui.py</code>, aby </em>sama<em>\nnapl&#xE1;novala, kdy se m&#xE1; p&#x159;&#xED;&#x161;t&#x11B; zavolat. Vol&#xE1;n&#xED; <code>schedule_interval</code> tak u&#x17E;\nnebude pot&#x159;eba.)</em></p>\n</li>\n<li><p>Hadi budou dva; druh&#xFD; se ovl&#xE1;d&#xE1; kl&#xE1;vesami\n<kbd>W</kbd> <kbd>A</kbd> <kbd>S</kbd> <kbd>D</kbd>.<br>\n<em>(Na to je nejlep&#x161;&#xED; ud&#x11B;lat novou t&#x159;&#xED;du, <code>Snake</code>, a v&#x161;echen stav hada\np&#x159;esunout ze <code>State</code> do n&#xED;. Ve <code>State</code> pak m&#x11B;j seznam had&#x16F;.\nT&#xE9;hle zm&#x11B;n&#x11B; je pot&#x159;eba p&#x159;izp&#x16F;sobit cel&#xFD; zytek programu.)</em></p>\n</li>\n</ul>\n\n\n        "
    }
  }
}