Nekonečná klec

Místo konce hry při naražení do okraje okýnka můžeš nechat hada „projít“ a objevit se na druhé straně.

Z pohledu logiky hry to není tak složité, jak to může znít. Stačí v move místo ukončení hry 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!

Řešení

Jestli ale vykresluješ hada (místo housenky), narazíš teď na problém s vybíráním správných dílků – okraj herní plochy hada vizuálně rozdělí na dva menší. Řešení tohoto problému nechávám na čtenáři – s tím, že je to hodně těžký problém.

Zbytkové řešení

Jde logiku vylázání z okýnka vyřešit jednodušeji? Jde! Matematikové vymysleli operaci, která se jmenuje zbytek po dělení. Ta dělá přesně to, co tu potřebuješ – 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.

Python moužívá pro zbytek po dělení operátor %. Zkus si to:

>>> 6 % 10      # Zbytek po dělení šesti desíti
6
>>> 10 % 10
0
>>> -1 % 10
9

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

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

Podobné matematické „zkratky“ umí programátorům často usnadnit život. Jen 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.

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.

Pro matematiky

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.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-podzim-snake:extensions:1",
      "title": "Rozšíření Hada – Nekonečná klec",
      "html": "\n          \n    \n\n    <h1>Nekone&#x10D;n&#xE1; klec</h1>\n<p>M&#xED;sto konce hry p&#x159;i nara&#x17E;en&#xED; do okraje ok&#xFD;nka m&#x16F;&#x17E;e&#x161; nechat hada &#x201E;proj&#xED;t&#x201C;\na objevit se na druh&#xE9; stran&#x11B;.</p>\n<p>Z&#xA0;pohledu logiky hry to nen&#xED; tak slo&#x17E;it&#xE9;, jak to m&#x16F;&#x17E;e zn&#xED;t.\nSta&#x10D;&#xED; v&#xA0;<code>move</code> m&#xED;sto ukon&#x10D;en&#xED; hry spr&#xE1;vn&#x11B; nastavit 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=\"solution\" id=\"solution-0\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-podzim-snake/snake/toroid/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=\"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>Jestli ale vykresluje&#x161; hada (m&#xED;sto housenky), naraz&#xED;&#x161; te&#x10F; 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;.\n&#x158;e&#x161;en&#xED; tohoto probl&#xE9;mu nech&#xE1;v&#xE1;m na &#x10D;ten&#xE1;&#x159;i &#x2013; s&#xA0;t&#xED;m, &#x17E;e je to hodn&#x11B; t&#x11B;&#x17E;k&#xFD;\nprobl&#xE9;m.</p>\n<h2>Zbytkov&#xE9; &#x159;e&#x161;en&#xED;</h2>\n<p>Jde logiku vyl&#xE1;z&#xE1;n&#xED; z ok&#xFD;nka vy&#x159;e&#x161;it 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 tu pot&#x159;ebuje&#x161; &#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>Python mou&#x17E;&#xED;v&#xE1; pro zbytek po d&#x11B;len&#xED; oper&#xE1;tor <code>%</code>. Zkus si to:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"mi\">6</span> <span class=\"o\">%</span> <span class=\"mi\">10</span>      <span class=\"c1\"># Zbytek po d&#x11B;len&#xED; &#x161;esti des&#xED;ti</span>\n<span class=\"go\">6</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"mi\">10</span> <span class=\"o\">%</span> <span class=\"mi\">10</span>\n<span class=\"go\">0</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"o\">-</span><span class=\"mi\">1</span> <span class=\"o\">%</span> <span class=\"mi\">10</span>\n<span class=\"go\">9</span>\n</pre></div><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 dv&#x11B;ma &#x159;&#xE1;dky:</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.\nJen p&#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>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</div><div class=\"admonition note\"><p class=\"admonition-title\">Pro matematiky</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 vhodn&#x11B;</a>\npro 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>\n\n\n        "
    }
  }
}