Tato lekce navazuje na dřívější úkoly - 1D piškvorky. Pokud je nemáš udělané, můžeš použít ukázkové následující soubory.
Soubor util.py
musí obsahovat funkci tah(pole, index, symbol)
, která se
pokusí umístit hráčův symbol do zadaného hracího pole a vrací nový stav hracího
pole (neúspěch je indikován vyvoláním výjimky ValueError
). Může vypadat
například takto:
Podobně s ai.py
. Ten musí obsahovat funkci tah_pocitace(pole, symbol)
, který
se pokusí umístit zadaný symbol do hracího pole, vrací nový stav hracího pole.
použít velmi naivní strategii:
Pro webový server dneska použijeme knihovnu flask
. Již tradičně, nejprve si ji
nainstalujeme:
(venv) $ python -m pip install flask
Začneme s jednoduchou kostrou:
# webpiskvorky.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hra():
jmeno_zvirete = 'Andulka na bidýlku'
return f'Ahoj, jmenuju se {jmeno_zvirete}.'
Aplikace ve Flasku se spouští trochu jinak, než programy, které jsme si doposud napsali. Nejprve je nutné nastavit několik proměnných prostředí a to se dělá na různých počítačích jiným způsobem.
V linuxu/Mac:
$ export FLASK_APP=webpiskvorky.py
$ export FLASK_DEBUG=1
Pokud pracuješ na Windows:
> set FLASK_APP=webpiskvorky.py
> set FLASK_DEBUG=1
Tak, tím máme nachystané prostředí a konečně můžeme server spustit:
(venv) $ flask run
* Serving Flask app "webpiskvorky.py" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 279-218-554
Otevři si v prohlížeči stránku http://127.0.0.1:5000 a mělo by se ti zobrazi prázdná stránka pouze s textem
Ahoj, jmenuju se Andulka na bidýlku.
Psaní obsahu stránky přímo v pythonu je docela nepohodlné. Proto využijeme tzv. šablon. To je soubor, do kterého ve kterém se dají nahradit proměnné za jejich hodnoty.
Ve stejné složce, jako se nachází soubor webpiskvorky.py
vytvoříme novou
složku templates
a v ní následující piskvorky.html
:
Soubor templates/piskvorky.html
:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
</head>
<body>
Ahoj, jmenuju se {{ jmeno }}
</body>
</html>
Nyní upravíme naši funkci tak, abychom šabloně předali proměnné a výsledný obsah vrátili jako odpověd serveru.
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hra():
jmeno_zvirete = 'Andulka na bidýlku'
return render_template('piskvorky.html', jmeno=jmeno_zvirete)
Pojmenovaný argument funkce render_template
uvnitř šablony vezme jako název
proměnné uvnitř šablony. Hodnotu proměnné v šabloně vypíšeme pomocí dvojitých
složených závorek.
{ "data": { "sessionMaterial": { "id": "session-material:2019/brno-jaro-2019-pondeli:tmp4:1", "title": "Webový server - rozhraní k piškvorkám", "html": "\n \n \n\n <h1>Webový server - rozhraní k piškvorkám</h1>\n<p>Tato lekce navazuje na dřívější úkoly - 1D piškvorky. Pokud je nemáš udělané,\nmůžeš použít ukázkové následující soubory.</p>\n<p>Soubor <code>util.py</code> musí obsahovat funkci <code>tah(pole, index, symbol)</code>, která se\npokusí umístit hráčův symbol do zadaného hracího pole a vrací nový stav hracího\npole (neúspěch je indikován vyvoláním výjimky <code>ValueError</code>). Může vypadat\nnapříklad takto:</p>\n<div class=\"solution\" id=\"solution-0\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-2019-pondeli/projects/webpiskvorky/index/solutions/0/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"c1\"># util.py</span>\n<span class=\"k\">def</span> <span class=\"nf\">tah</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">,</span> <span class=\"n\">symbol</span><span class=\"p\">):</span>\n <span class=\"k\">if</span> <span class=\"n\">index</span> <span class=\"o\">>=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">)</span> <span class=\"ow\">or</span> <span class=\"n\">index</span> <span class=\"o\"><</span> <span class=\"mi\">0</span><span class=\"p\">:</span>\n <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span>\n <span class=\"k\">if</span> <span class=\"n\">pole</span><span class=\"p\">[</span><span class=\"n\">index</span><span class=\"p\">]</span> <span class=\"o\">!=</span> <span class=\"s1\">'-'</span><span class=\"p\">:</span>\n <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span>\n <span class=\"k\">if</span> <span class=\"n\">symbol</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"p\">(</span><span class=\"s1\">'x'</span><span class=\"p\">,</span> <span class=\"s1\">'o'</span><span class=\"p\">):</span>\n <span class=\"k\">raise</span> <span class=\"ne\">ValueError</span>\n\n <span class=\"k\">return</span> <span class=\"n\">pole</span><span class=\"p\">[:</span><span class=\"n\">index</span><span class=\"p\">]</span> <span class=\"o\">+</span> <span class=\"n\">symbol</span> <span class=\"o\">+</span> <span class=\"n\">pole</span><span class=\"p\">[</span><span class=\"n\">index</span> <span class=\"o\">+</span> <span class=\"mi\">1</span><span class=\"p\">:]</span>\n\n\n<span class=\"k\">def</span> <span class=\"nf\">vyhodnot</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">):</span>\n <span class=\"k\">if</span> <span class=\"s1\">'xxx'</span> <span class=\"ow\">in</span> <span class=\"n\">pole</span><span class=\"p\">:</span>\n <span class=\"k\">return</span> <span class=\"s1\">'x'</span>\n <span class=\"k\">if</span> <span class=\"s1\">'ooo'</span> <span class=\"ow\">in</span> <span class=\"n\">pole</span><span class=\"p\">:</span>\n <span class=\"k\">return</span> <span class=\"s1\">'o'</span>\n <span class=\"k\">if</span> <span class=\"s1\">'-'</span> <span class=\"ow\">not</span> <span class=\"ow\">in</span> <span class=\"n\">pole</span><span class=\"p\">:</span>\n <span class=\"k\">return</span> <span class=\"s1\">'!'</span>\n <span class=\"k\">return</span> <span class=\"s1\">'-'</span>\n</pre></div>\n </div>\n</div><p>Podobně s <code>ai.py</code>. Ten musí obsahovat funkci <code>tah_pocitace(pole, symbol)</code>, který\nse pokusí umístit zadaný symbol do hracího pole, vrací nový stav hracího pole.\npoužít velmi naivní strategii:</p>\n<div class=\"solution\" id=\"solution-1\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-2019-pondeli/projects/webpiskvorky/index/solutions/1/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"c1\"># ai.py</span>\n<span class=\"kn\">from</span> <span class=\"nn\">random</span> <span class=\"kn\">import</span> <span class=\"n\">randrange</span>\n<span class=\"kn\">from</span> <span class=\"nn\">util</span> <span class=\"kn\">import</span> <span class=\"n\">tah</span>\n\n<span class=\"k\">def</span> <span class=\"nf\">tah_pocitace</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">,</span> <span class=\"n\">symbol</span><span class=\"p\">):</span>\n <span class=\"n\">delka</span> <span class=\"o\">=</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">)</span>\n\n <span class=\"k\">while</span> <span class=\"bp\">True</span><span class=\"p\">:</span>\n <span class=\"k\">try</span><span class=\"p\">:</span>\n <span class=\"n\">index</span> <span class=\"o\">=</span> <span class=\"n\">randrange</span><span class=\"p\">(</span><span class=\"mi\">0</span><span class=\"p\">,</span> <span class=\"n\">delka</span><span class=\"p\">)</span>\n <span class=\"k\">return</span> <span class=\"n\">tah</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">,</span> <span class=\"n\">index</span><span class=\"p\">,</span> <span class=\"n\">symbol</span><span class=\"p\">)</span>\n <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n <span class=\"k\">pass</span>\n</pre></div>\n </div>\n</div><h1>První seznámení se serverem</h1>\n<p>Pro webový server dneska použijeme knihovnu <code>flask</code>. Již tradičně, nejprve si ji\nnainstalujeme:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"o\">(</span>venv<span class=\"o\">)</span> $ python -m pip install flask\n</pre></div><p>Začneme s jednoduchou kostrou:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\"># webpiskvorky.py</span>\n<span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">Flask</span>\n\n<span class=\"n\">app</span> <span class=\"o\">=</span> <span class=\"n\">Flask</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hra</span><span class=\"p\">():</span>\n <span class=\"n\">jmeno_zvirete</span> <span class=\"o\">=</span> <span class=\"s1\">'Andulka na bidýlku'</span>\n\n <span class=\"k\">return</span> <span class=\"n\">f</span><span class=\"s1\">'Ahoj, jmenuju se {jmeno_zvirete}.'</span>\n</pre></div><h2>Spuštění serveru</h2>\n<p>Aplikace ve Flasku se spouští trochu jinak, než programy, které jsme si doposud\nnapsali. Nejprve je nutné nastavit několik proměnných prostředí a to se dělá na\nrůzných počítačích jiným způsobem.</p>\n<p>V linuxu/Mac:</p>\n<div class=\"highlight\"><pre><span></span>$ <span class=\"nb\">export</span> <span class=\"nv\">FLASK_APP</span><span class=\"o\">=</span>webpiskvorky.py\n$ <span class=\"nb\">export</span> <span class=\"nv\">FLASK_DEBUG</span><span class=\"o\">=</span><span class=\"m\">1</span>\n</pre></div><p>Pokud pracuješ na Windows:</p>\n<div class=\"highlight\"><pre><span></span>> <span class=\"nb\">set</span> <span class=\"nv\">FLASK_APP</span><span class=\"o\">=</span>webpiskvorky.py\n> <span class=\"nb\">set</span> <span class=\"nv\">FLASK_DEBUG</span><span class=\"o\">=</span><span class=\"m\">1</span>\n</pre></div><p>Tak, tím máme nachystané prostředí a konečně můžeme server spustit:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"o\">(</span>venv<span class=\"o\">)</span> $ flask run\n * Serving Flask app <span class=\"s2\">"webpiskvorky.py"</span> <span class=\"o\">(</span>lazy loading<span class=\"o\">)</span>\n * Environment: production\n WARNING: Do not use the development server in a production environment.\n Use a production WSGI server instead.\n * Debug mode: on\n * Running on http://127.0.0.1:5000/ <span class=\"o\">(</span>Press CTRL+C to quit<span class=\"o\">)</span>\n * Restarting with stat\n * Debugger is active!\n * Debugger PIN: <span class=\"m\">279</span>-218-554\n</pre></div><p>Otevři si v prohlížeči stránku <a href=\"http://127.0.0.1:5000\">http://127.0.0.1:5000</a> a mělo by se ti zobrazi\nprázdná stránka pouze s textem</p>\n<div class=\"highlight\"><pre><code>Ahoj, jmenuju se Andulka na bidýlku.</code></pre></div><h2>Šablona</h2>\n<p>Psaní obsahu stránky přímo v pythonu je docela nepohodlné. Proto využijeme tzv.\nšablon. To je soubor, do kterého ve kterém se dají nahradit proměnné za jejich\nhodnoty.</p>\n<p>Ve stejné složce, jako se nachází soubor <code>webpiskvorky.py</code> vytvoříme novou\nsložku <code>templates</code> a v ní následující <code>piskvorky.html</code>:</p>\n<p>Soubor <code>templates/piskvorky.html</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\"><!DOCTYPE html></span>\n<span class=\"p\"><</span><span class=\"nt\">html</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">title</span><span class=\"p\">></</span><span class=\"nt\">title</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">meta</span> <span class=\"na\">charset</span><span class=\"o\">=</span><span class=\"s\">"utf-8"</span><span class=\"p\">></span>\n <span class=\"p\"></</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">body</span><span class=\"p\">></span>\n Ahoj, jmenuju se {{ jmeno }}\n <span class=\"p\"></</span><span class=\"nt\">body</span><span class=\"p\">></span>\n<span class=\"p\"></</span><span class=\"nt\">html</span><span class=\"p\">></span>\n</pre></div><p>Nyní upravíme naši funkci tak, abychom šabloně předali proměnné a výsledný obsah\nvrátili jako odpověd serveru.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">Flask</span><span class=\"p\">,</span> <span class=\"n\">render_template</span>\n\n<span class=\"n\">app</span> <span class=\"o\">=</span> <span class=\"n\">Flask</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hra</span><span class=\"p\">():</span>\n <span class=\"n\">jmeno_zvirete</span> <span class=\"o\">=</span> <span class=\"s1\">'Andulka na bidýlku'</span>\n\n <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s1\">'piskvorky.html'</span><span class=\"p\">,</span> <span class=\"n\">jmeno</span><span class=\"o\">=</span><span class=\"n\">jmeno_zvirete</span><span class=\"p\">)</span>\n</pre></div><p>Pojmenovaný argument funkce <code>render_template</code> uvnitř šablony vezme jako název\nproměnné uvnitř šablony. Hodnotu proměnné v šabloně vypíšeme pomocí dvojitých\nsložených závorek.</p>\n<h2>Výsledná aplikace</h2>\n<div class=\"solution\" id=\"solution-2\">\n <h3>Řešení</h3>\n <div class=\"solution-cover\">\n <a href=\"/2019/brno-jaro-2019-pondeli/projects/webpiskvorky/index/solutions/2/\"><span class=\"link-text\">Ukázat řešení</span></a>\n </div>\n <div class=\"solution-body\" aria-hidden=\"true\">\n <div class=\"highlight\"><pre><span></span><span class=\"c1\"># webpiskvorky.py</span>\n\n<span class=\"c1\"># Spouštění (v příkazové řádce):</span>\n<span class=\"c1\"># export FLASK_APP=webpiskvorky.py</span>\n<span class=\"c1\"># export FLASK_DEBUG=1</span>\n<span class=\"c1\"># flask run</span>\n\n<span class=\"c1\"># (na Windows "set" místo "export")</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">Flask</span><span class=\"p\">,</span> <span class=\"n\">render_template</span><span class=\"p\">,</span> <span class=\"n\">request</span>\n\n<span class=\"kn\">from</span> <span class=\"nn\">util</span> <span class=\"kn\">import</span> <span class=\"n\">tah</span>\n<span class=\"kn\">from</span> <span class=\"nn\">ai</span> <span class=\"kn\">import</span> <span class=\"n\">tah_pocitace</span>\n\n<span class=\"n\">app</span> <span class=\"o\">=</span> <span class=\"n\">Flask</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/'</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hra</span><span class=\"p\">():</span>\n <span class=\"k\">if</span> <span class=\"s1\">'pole'</span> <span class=\"ow\">in</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">:</span>\n <span class=\"n\">pole</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">[</span><span class=\"s1\">'pole'</span><span class=\"p\">]</span>\n <span class=\"k\">else</span><span class=\"p\">:</span>\n <span class=\"n\">pole</span> <span class=\"o\">=</span> <span class=\"s1\">'-'</span> <span class=\"o\">*</span> <span class=\"mi\">20</span>\n <span class=\"k\">if</span> <span class=\"s1\">'cislo'</span> <span class=\"ow\">in</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">:</span>\n <span class=\"n\">cislo_policka</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">args</span><span class=\"p\">[</span><span class=\"s1\">'cislo'</span><span class=\"p\">])</span>\n <span class=\"n\">pole</span> <span class=\"o\">=</span> <span class=\"n\">tah</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">,</span> <span class=\"n\">cislo_policka</span><span class=\"p\">,</span> <span class=\"s1\">'x'</span><span class=\"p\">)</span>\n <span class=\"n\">pole</span> <span class=\"o\">=</span> <span class=\"n\">tah_pocitace</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">,</span> <span class=\"s1\">'o'</span><span class=\"p\">)</span>\n\n <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span>\n <span class=\"s1\">'hra.html'</span><span class=\"p\">,</span>\n <span class=\"n\">ocislovane_pole</span><span class=\"o\">=</span><span class=\"nb\">enumerate</span><span class=\"p\">(</span><span class=\"n\">pole</span><span class=\"p\">),</span>\n <span class=\"n\">pole</span><span class=\"o\">=</span><span class=\"n\">pole</span><span class=\"p\">,</span>\n <span class=\"p\">)</span>\n</pre></div><div class=\"highlight\"><pre><span></span><span class=\"cp\"><!DOCTYPE html></span>\n<span class=\"p\"><</span><span class=\"nt\">html</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">title</span><span class=\"p\">></span>Piškvorky<span class=\"p\"></</span><span class=\"nt\">title</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">meta</span> <span class=\"na\">charset</span><span class=\"o\">=</span><span class=\"s\">"utf-8"</span><span class=\"p\">></span>\n <span class=\"p\"></</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">body</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">h1</span><span class=\"p\">></span>Piškvorky<span class=\"p\"></</span><span class=\"nt\">h1</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">form</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">"hidden"</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">"pole"</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">"{{ pole }}"</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">div</span><span class=\"p\">></span>\n {% for cislo, znak in ocislovane_pole %}\n {% if znak == '-' %}\n <span class=\"p\"><</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">"radio"</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">"cislo"</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">"{{ cislo }}"</span><span class=\"p\">></span>\n {% else %}\n {{ znak }}\n {% endif %}\n {% endfor %}\n <span class=\"p\"></</span><span class=\"nt\">div</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">"submit"</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">"Odeslat!"</span><span class=\"p\">></span>\n <span class=\"p\"></</span><span class=\"nt\">form</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">"{{ url_for('hra') }}"</span><span class=\"p\">></span>Reset<span class=\"p\"></</span><span class=\"nt\">a</span><span class=\"p\">></span>\n <span class=\"p\"></</span><span class=\"nt\">body</span><span class=\"p\">></span>\n<span class=\"p\"></</span><span class=\"nt\">html</span><span class=\"p\">></span>\n</pre></div>\n </div>\n</div>\n\n\n " } } }