Věší se jako druhá příloha ve formátu sha256sum, počítaná nad jménem, pod
kterým se soubor stahuje — aby se dala ověřit rovnou přes
sha256sum -c, bez přejmenovávání.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Matice Python 3.11 až 3.14 — u projektu, který deklaruje >=3.11, se hodí
vědět, že to na všech čtyřech opravdu jede. Pythony obstará uv, na
hostiteli nemusí být žádný.
K pytestu ještě skriptovaná partie v terminálové verzi. Pytest sahá na
core.py, prompty v dice.py nikdo netestoval; tohle projde dvě nuly, třetí
s vynulováním a výhru tak, jak to odehraje člověk.
Runner sdílí pracovní adresář mezi variantami matice, proto max-parallel 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PyInstaller hledá objdumpem, na kterých knihovnách binárka visí. Runner
v host módu ho nemá — je to jediné, co musí být na hostiteli, zbytek si
obstará uv.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Runner běží v host módu, bez dockeru, takže se v něm kontejner na AlmaLinux
spustit nedá. Ukázalo se ale, že kontejner potřeba není: stačí stavět proti
samostatnému CPythonu od uv. Ten je slinkovaný s glibc 2.17 a nic
z hostitele se do binárky nedostane — změřeno objdumpem přes všechno, co
se z ní rozbaluje. Výsledek je tedy přenositelnější než přes AlmaLinux 8
(2.28) a build.sh je o polovinu kratší.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Otagovaný commit postaví binárku na runneru, projede testy, zkusí ji
nastartovat a pověsí ji na release. Nad pull requesty běží totéž bez
posledního kroku, ať se rozbitá stavba pozná dřív než na tagu.
Staví se v kontejneru na AlmaLinux 8 ze stejného důvodu jako build.sh —
kvůli glibc. Záměrně bez hotových akcí z marketplace: na vlastním runneru
tím odpadá starost, jestli je v kontejneru node.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stáhni a spusť: jednosouborová binárka pro Linux, uvnitř Python, Flask,
šablony i styly. Staví se ./build.sh v kontejneru na AlmaLinux 8, protože
binárka slinkovaná proti glibc z Fedory 44 by nešla spustit nikde se
starším systémem.
Databáze tím dostává dvě různá místa. Ze zdrojáků zůstává dice.db
v pracovním adresáři, ať se dá mít víc sad vedle sebe. Z binárky jde do
~/.local/share/kostky/ — binárka se rozbaluje do dočasného adresáře
a pouští se odkudkoli, takže relativní cesta by databázi rozsypala po
disku. DICE_DB přebije obojí.
Server teď cestu k databázi vypisuje při startu, ať se na ni nemusí ptát.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Trojice venv/pip/python byla zbytečná ceremonie pro appku, která se pouští
jednou za herní večer.
- web.py i dice.py si nesou závislosti v hlavičce podle PEP 723, takže
je uv obstará sám a není co instalovat ani aktivovat
- pytest.ini staví kořen repa na pythonpath, takže testy jdou spustit
i mimo připravené prostředí
- README nabízí uv jako hlavní cestu, venv a systémové balíčky jako
záložní
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Detekce vracela jedinou adresu podle výchozí trasy. Když ta nevede tam,
kam je připojený telefon, QR kód míří do prázdna a nezbývá než sahat do
konfigurace. Při ladění se ukázalo i to, že záložní větev může vrátit
127.0.0.1, tedy QR kód na localhost.
- net.py hledá adresy všech rozhraní přes if_nameindex a ioctl, se zálohou
přes getaddrinfo; DICE_HOST má poslední slovo
- řadí se podle rozsahu adresy a obecného typu rozhraní, ne podle seznamu
konkrétních jmen: výchozí trasa, místní sítě, tailnet, virtuální sítě
- loopback a link-local vypadnou, nic dalšího se nezahazuje — o tom, co
funguje, rozhoduje člověk u stolu
- tailnet adresu vědomě necháváme: funguje i napříč sítěmi
- adresy se hledají při každém načtení; když se notebook přesune na jinou
síť, tabule to pozná podle data-address a načte se znovu
- když se nenajde nic, tabule řekne, co s tím, místo QR kódu naslepo
- 20 testů nad klasifikací a řazením, nezávislých na aktuální síti
- README doplněn o řešení potíží s připojením
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Po sto kolech byla tabule k ničemu: na obrazovku se vešla kola 1–14
a řádek se součty skončil asi 4 500 pixelů pod okrajem. Tabule tedy
ukazovala nejstarší historii a nic z toho, co se právě děje.
- kola se řadí od nejnovějšího, poslední zápis je vždy nahoře
- součty se přesunuly z patičky nad historii, hned pod jména hráčů
- tabule ukazuje posledních 15 kol, zbytek shrne řádka "... a dalších
85 kol"; má ukazovat stav, ne archiv, a nepřekresluje se pak zbytečně
každé dvě vteřiny přes tři sta buněk
- skloňování kol podle češtiny (1 kolo / 2 kola / 5 kol)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- rekordy: nejvyšší tah, nejvyšší konečné skóre, nejrychlejší výhra
- kariéra: počet her, výher, úspěšnost, průměrné pořadí, průměr na tah
a kolikrát koho postihlo vynulování
- do statistik jdou jen dohrané hry, nedohrané a opuštěné se ignorují
- celkové skóre počítá SQL stejným pravidlem jako core.Game.totals(),
tedy součet tahů po posledním vynulování; testem ověřeno, že se obě
cesty shodují
- vědomě chybí celkový součet bodů napříč hrami — cílové skóre je u každé
hry jiné, metrika by odměňovala jen toho, kdo hrál nejvíc
- README se spuštěním a přehledem modulů
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Flask, server-rendered HTML, formuláře přes POST/redirect/GET.
Žádný build step, žádný JS framework.
- / zakládá hru výběrem známých hráčů v pořadí u stolu
- /game/<id> je zadávací pohled: kdo je na tahu, skóre, x/xx,
průběžné pořadí, vrácení posledního zápisu
- /board/<id> je zápisník po kolech; tahy před vynulováním se škrtnou
červeně, sloupec hráče na tahu drží zvýrazňovač
- tabule se doptává serveru každé dvě vteřiny a vyměňuje jen hlavičku
a zápisník, QR s adresou zůstává mimo obnovovanou část
- adresa pro telefon se hledá za běhu, QR se skládá ze čtverečků
přímo do SVG, takže není potřeba Pillow
- 16 funkčních testů přes Flask test client
Vizuálně to stojí na tom, co appka nahrazuje: čtverečkovaný papír,
modrá propiska zapisuje, červená škrtá, zvýrazňovač drží tah.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ručně psané SQL nad pěti tabulkami, žádné ORM.
- hry ukazují na players.id, nikdy na jméno, takže se přejmenování
propíše i do starých her
- párování hráčů napříč hrami přes normalizovaný klíč (trim, casefold),
plus slučování pro případ překlepu
- zapisuje se každý tah hned, ne až na konci — rozehraná hra se po pádu
serveru najde podle stavu a dá se v ní pokračovat
- součty se neukládají nikde, stav hry se rekonstruuje načtením tahů
- časy jako ISO text, sqlite3 vlastní adaptéry pro datetime zavrhl
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Pravidla byla propletená se vstupem a výstupem (add_score se uprostřed
zastavovalo na input()), takže nešla testovat ani použít z webu.
- core.Game drží stav a pravidla, nic nevypisuje a na nic se neptá
- součty jsou vždy odvozené z tahů, díky tomu je undo() jen zahození
posledního tahu — funguje i pro vracení vynulování
- vynulování se ukládá jako hodnota 0 s příznakem reset místo záporného
tahu, aby do historie nepadala čísla, která nikdo nehodil
- zero_streak() je jediný zdroj pravdy pro pravidlo i pro indikátor x/xx
a počítá se od posledního vynulování
- pořadí na tahu plyne z počtu zápisů, globální pointer zmizel
- dice.py zůstává navenek stejné, jen deleguje na Game
- 15 testů nad pravidly
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sliceování [-2:][0] vrátí u seznamu s jediným záznamem tentýž
prvek jako [-1:][0], takže po první nule se zobrazilo rovnou "xx".
Nahrazeno přímým indexováním s kontrolou délky.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Převzato 1:1 z kostky/kostky.py a přizpůsobeno počitadlu:
- volitelné finální skóre při zakládání hry (výchozí 10 000)
- vynulování skóre po třech nulových hodech za sebou
- indikátor "x"/"xx" u hráče na tahu
- check_win() + to_sorted_tuple() + win() s výslednou tabulkou
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>