Přeskočit na obsah
coden

Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search

Hra jako úloha prohledávání, herní strom, minimax, alfa-beta ořezávání, ohodnocovací funkce a MCTS — na piškvorkách, kde se dá spočítat všechno, a s cestou od Deep Blue k AlphaZero.

14 minut Matěj Žalmánek 2026-10-15

Série Základy AI Díl 22 z 83
  1. Mapa umělé inteligence: co je co a jak to do sebe zapadá
  2. Stručná historie umělé inteligence: od Turinga po jazykové modely
  3. Data, model, trénink, inference: základní pojmy na jednom příkladu
  4. Jak číst matematický zápis: symboly, indexy, sumy a kvantifikátory
  5. Množiny a relace: stavebnice, ze které se skládají definice v AI
  6. Funkce a zobrazení: proč je každý model v AI funkce
  7. Logika a důkazy: pravidla, podle kterých se v AI uvažuje
  8. Grafy a stromy: struktura, na které stojí hledání i neuronové sítě
  9. Lineární algebra pro strojové učení: vektory, matice a proč AI hlavně násobí
  10. Derivace, gradient a řetízkové pravidlo: jak model zjistí, kterým směrem se učit
  11. Gradientní sestup: jak se model učí
  12. Co je pravděpodobnost: od hodu kostkou ke Kolmogorovovým axiomům
  13. Podmíněná pravděpodobnost a Bayesova věta: jak změnit odhad, když se dozvíte něco nového
  14. Náhodná veličina a distribuční funkce: jedna funkce, která o rozdělení řekne všechno
  15. Funkce hustoty a pravděpodobnostní funkce: proč má spojitá veličina v bodě pravděpodobnost nula
  16. Střední hodnota, rozptyl a kovariance: kde rozdělení leží, jak je široké a co s čím souvisí
  17. Přehled pravděpodobnostních rozdělení: Bernoulli, binomické, Poisson, rovnoměrné, normální a exponenciální
  18. Zákon velkých čísel a centrální limitní věta: proč se průměry chovají tak předvídatelně
  19. Statistika a odhady parametrů: maximální věrohodnost, MAP a intervaly spolehlivosti
  20. Teorie informace: entropie, křížová entropie a KL divergence — odkud se berou ztrátové funkce
  21. Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi
  22. Hry a protivník: minimax, alfa-beta ořezávání a Monte Carlo tree search
  23. Splňování omezujících podmínek: backtracking, propagace omezení a AC-3 na sudoku a mapě krajů
  24. Logika a znalostní systémy: dopředné a zpětné řetězení, rezoluce a expertní systémy
  25. Plánování: STRIPS, svět kostek, heuristiky z relaxace a plánování v AI agentech
  26. Lokální hledání a simulované žíhání: obchodní cestující přes krajská města
  27. Genetické algoritmy: populace, křížení, mutace a výběr na batohu na výlet
  28. Evoluční strategie a genetické programování: od pravidla jedné pětiny po Keplerův zákon
  29. Optimalizace mravenčí kolonií: jak feromonová stopa najde krátkou cestu
  30. Optimalizace hejnem částic: setrvačnost, vlastní zkušenost a zkušenost hejna
  31. Neuroevoluce: evoluce vah i tvaru neuronových sítí a algoritmus NEAT
  32. Fuzzy množiny a funkce příslušnosti: jak zapsat „trochu teplo“
  33. Fuzzy logika a pravděpodobnost: proč „trochu teplo“ neznamená „pravděpodobně teplo“
  34. Fuzzy logika: t-normy, implikace a pravidla KDYŽ–PAK
  35. Fuzzy řízení: Mamdani a Sugeno od ventilátoru po kyvadlo na vozíku
  36. Fuzzy shlukování: algoritmus fuzzy c-means a body mezi shluky
  37. Neuro-fuzzy systémy (ANFIS): fuzzy pravidla, která se učí z dat
  38. Markovovy řetězce: přechodová matice, stacionární rozdělení a PageRank
  39. Skryté Markovovy modely: Viterbiho algoritmus a nepoctivé kasino
  40. Bayesovské sítě: proč je tráva mokrá a co z toho plyne pro postřikovač
  41. Kalmanův filtr: jak z nepřesných měření odhadnout, kde auto je a jak rychle jede
  42. Druhy strojového učení: s učitelem, bez učitele, s částečným učitelem a další
  43. Přeučení a regularizace: proč model, který zná data nazpaměť, selže
  44. Vyhodnocení modelu: křížová validace, F1 a křivka ROC
  45. Shlukování a snížení dimenze: k-means, PCA a t-SNE
  46. Klasifikace a regrese: dvě úlohy učení s učitelem
  47. Lineární regrese: nejmenší čtverce geometricky i maticově
  48. Polynomiální a nelineární regrese: jak přímku ohnout
  49. Logistická regrese: sigmoida, šance a křížová entropie
  50. Vícetřídní klasifikace a softmax: od dvou tříd k mnoha
  51. Naivní Bayesův klasifikátor: spamový filtr, který funguje lépe, než by měl
  52. Ztrátové funkce: co přesně model minimalizuje
  53. Rozhodovací stromy a k nejbližších sousedů: modely bez vzorců
  54. Ansámbly: náhodný les a gradient boosting
  55. SVM a jádrový trik: nejširší hranice a jak ji ohnout
  56. Signál a vzorkování: proč platí Nyquistův teorém
  57. Fourierova transformace: rozklad signálu na frekvence
  58. Filtry a konvoluce: vyhlazení, hrany a odstranění šumu
  59. Zvuk a řeč: spektrogram, melová škála a MFCC
  60. Obraz jako signál: pixely, barvy, konvoluce a hrany
  61. Perceptron a umělý neuron: nejjednodušší neuronová síť a co neumí
  62. Neuronová síť od nuly: zpětné šíření chyby krok za krokem
  63. Aktivace, inicializace a normalizace: drobnosti, na kterých hluboká síť stojí
  64. Konvoluční sítě: jak síť poznává obrázky
  65. Rekurentní sítě: paměť pro posloupnosti a mizející gradient
  66. LSTM a GRU: brány, které rozhodují, co si síť zapamatuje
  67. Autoenkodéry: síť, která se učí data stlačit a zase rozbalit
  68. Embeddingy a word2vec: jak se slovo stane vektorem
  69. Mechanismus pozornosti: jak se model naučí, kam se dívat
  70. Transformery a velké jazykové modely: architektura krok za krokem
  71. Tokenizace: jak se text rozseká na kousky pro model
  72. Předtrénování a škálování: proč větší model a víc dat funguje
  73. Doladění a RLHF: jak se z doplňovače textu stane asistent
  74. Prompty, kontext a RAG: jak modelu dát správné informace
  75. Variační autoenkodéry (VAE): nové obrázky ze spojitého latentního prostoru
  76. Generativní adversariální sítě (GAN): padělatel proti detektivovi
  77. Difúzní modely: jak se z čistého šumu stane obrázek
  78. Markovovy rozhodovací procesy: stavy, akce, odměny a Bellmanovy rovnice
  79. Q-learning a DQN: učení hodnoty akcí od tabulky po neuronovou síť
  80. Policy gradient a PPO: učení přímo strategie
  81. Jak funguje AI agent: jazykový model ve smyčce s nástroji
  82. Programování s AI agenty: zadání, testy a kontrola
  83. Vyhodnocení a bezpečnost AI systémů: jak měřit a jak hlídat

Celá osnova série 83 z 83 témat hotovo

Co si odnesete
  • Jak se hra dvou hráčů zapíše jako úloha prohledávání a proč je řešením strategie, ne cesta.
  • Jak minimax spočítá zaručenou hodnotu pozice a proč alfa-beta dojde ke stejnému výsledku mnohem rychleji.
  • Jak Monte Carlo tree search najde dobrý tah bez ohodnocovací funkce a co z něj udělalo AlphaGo.

Co se hodí znát předem: Prohledávání stavového prostoru: BFS, DFS, UCS a A* s animacemi, Grafy a stromy: struktura, na které stojí hledání i neuronové sítě

V bludišti z minulého dílu stál panáček sám. Svět se nehýbal a každý tah vedl tam, kam měl. Ve hře ale sedí naproti vám někdo, kdo chce přesný opak — a na každý váš tah odpoví tím, který vás bolí nejvíc. Hledat cestu k cíli už nestačí: musíte hledat strategii, která obstojí proti každé odpovědi. Šachy, dáma i go byly desítky let měřítkem umělé inteligence a algoritmy z tohohle dílu stojí za Deep Blue i za AlphaGo.

Navazuje na díly Prohledávání stavového prostoru a Grafy a stromy.

1. Hra jako úloha prohledávání

Definice — hra dvou hráčů

Hra dvou hráčů (deterministická, s úplnou informací a nulovým součtem) je sedmice

Γ = (S, s0, hráč, A, T, K, U),

která splňuje:

  1. S je neprázdná množina stavů (pozic) a s0 ∈ S je počáteční stav;
  2. K ⊆ S je množina koncových stavů — v nich hra skončí;
  3. hráč : S ∖ K → {MAX, MIN} určuje, kdo je ve stavu na tahu;
  4. A přiřazuje každému stavu s ∈ S ∖ K konečnou neprázdnou množinu A(s) tahů (akcí) a v koncových stavech A(s) = ∅;
  5. T je přechodová funkce: pro s ∈ S ∖ K a a ∈ A(s) je T(s, a) ∈ S stav po tahu a (tahy jsou deterministické);
  6. hráči se střídají: je-li s ∈ S ∖ K, a ∈ A(s) a T(s, a) ∉ K, pak hráč(T(s, a)) ≠ hráč(s);
  7. U : K → ℝ je užitek koncového stavu z pohledu hráče MAX; užitek hráče MIN je −U (nulový součet: U(s) + (−U(s)) = 0 pro každé s ∈ K).

Oba hráči znají celou sedmici a v každém okamžiku vidí aktuální stav (úplná informace). Hra je konečná, právě když neexistuje nekonečná posloupnost s0, s1, s2, … s si = T(si−1, ai) pro nějaká ai ∈ A(si−1) — každá partie tedy po konečně mnoha tazích skončí v K. Všechny hry v tomto díle jsou konečné.

Strategie hráče MAX je funkce σ, která každému stavu s ∈ S ∖ K s hráč(s) = MAX přiřadí tah σ(s) ∈ A(s); strategie τ hráče MIN je definovaná stejně pro stavy s hráč(s) = MIN. Dvojice strategií (σ, τ) jednoznačně určí partii ze stavu s0 a tím i její užitek.

Laicky řečeno

Hra je bludiště, ve kterém se o tahy dělíte s protivníkem. Na konci se sečte skóre — v piškvorkách +1, když vyhraje MAX, −1, když vyhraje MIN, a 0 za remízu. MAX chce skóre co nejvyšší, MIN co nejnižší. „Nulový součet“ znamená, že se nedá vyhrát společně: co jeden získá, druhý ztratí.

Rozdíl proti prohledávání je zásadní. Řešením už není cesta — tu si nevyberete, protože každý druhý tah dělá soupeř. Řešením je strategie: předpis, jak odpovědět na každý tah, který soupeř může zahrát.

2. Herní strom

Definice — herní strom

Nechť Γ = (S, s0, hráč, A, T, K, U) je konečná hra dvou hráčů. Herní strom hry Γ je kořenový strom (viz díl Grafy a stromy), pro který platí:

  1. uzly jsou všechny posloupnosti tahů (a1, …, ak), k ≥ 0, které lze ze s0 zahrát, tj. si−1 ∉ K, ai ∈ A(si−1) a si = T(si−1, ai) pro i = 1, …, k; uzlu přísluší stav sk;
  2. kořen je prázdná posloupnost () se stavem s0;
  3. děti uzlu (a1, …, ak) se stavem sk ∉ K jsou uzly (a1, …, ak, a) pro všechna a ∈ A(sk) se stavy T(sk, a);
  4. listy jsou právě uzly, jejichž stav je koncový (sk ∈ K).

Uzel tedy není pozice, ale historie, která k ní vedla — do stejného stavu se lze dostat různými posloupnostmi tahů a ve stromu se pak objeví víckrát. Uzly, kde je na tahu MAX, kreslíme jako trojúhelník špičkou nahoru, uzly MIN špičkou dolů.

Nechť b = maxs ∈ S ∖ K |A(s)| je větvicí faktor a m největší délka partie (počet tahů). Pak má strom nejvýš bm listů.

Laicky řečeno

Všechny partie, které se dají odehrát, nakreslené jako rozvětvený strom: z kořene vede jedna větev pro každý první tah, z každé z nich větev pro každou odpověď a tak dál, až ke konci hry. Jeden list = jedna dohraná partie.

Piškvorky na hracím poli 3 × 3 jsou malá hra, a přesto má jejich strom 549 946 uzlů a 255 168 listů — tolik různých partií se dá odehrát. Různých pozic je přitom jen 5 478: do stejné pozice se dostanete mnoha pořadími tahů. Šachy mají větvicí faktor kolem 35 a partie trvá desítky tahů; Claude Shannon v roce 1950 odhadl jejich strom na 10120 partií. Go s větvicím faktorem kolem 250 je ještě o mnoho řádů dál. Celý strom tedy projdeme jen u malých her — u velkých se musíme naučit, které větve vynechat.

Příklad — horní odhad stromu piškvorek a Shannonovo číslo

Kdyby se piškvorky hrály vždy až do zaplnění pole, měl by strom v hloubce k právě 9 · 8 · … · (9 − k + 1) = 9!/(9 − k)! uzlů (k = 0, …, 9). Celkem

∑k=09 9!/(9 − k)! = 1 + 9 + 72 + 504 + 3 024 + 15 120 + 60 480 + 181 440 + 362 880 + 362 880 = 986 410 uzlů a 9! = 362 880 listů.

Skutečný strom má 549 946 uzlů a 255 168 listů, protože partie, ve které někdo složí tři v řadě, končí dřív a její větev se dál nevětví. Odhad bm je tedy horní mez; tady s b klesajícím od 9 k 1.

Shannon (Programming a Computer for Playing Chess, 1950) počítal pro šachy s asi 103 možnostmi na jednu dvojici tahů (bílý a černý) a typickou partií o 40 dvojicích tahů: (103)40 = 10120. Je to hrubý řádový odhad, ne přesné číslo.

3. Minimax

Definice — minimaxová hodnota

Nechť Γ = (S, s0, hráč, A, T, K, U) je konečná hra dvou hráčů. Minimaxová hodnota je funkce MM : S → ℝ definovaná rekurzivně pro každé s ∈ S:

  1. MM(s) = U(s), je-li s ∈ K;
  2. MM(s) = maxa ∈ A(s) MM(T(s, a)), je-li s ∉ K a hráč(s) = MAX;
  3. MM(s) = mina ∈ A(s) MM(T(s, a)), je-li s ∉ K a hráč(s) = MIN.

Rekurze je dobře definovaná: hra je konečná, takže každý řetězec rekurzivních volání skončí v koncovém stavu, a A(s) je konečná neprázdná, takže maximum i minimum existují.

Tah a* ∈ A(s) je optimální tah hráče MAX ve stavu s s hráč(s) = MAX, právě když

a* ∈ argmaxa ∈ A(s) MM(T(s, a)), tj. MM(T(s, a*)) = MM(s);

optimální tah hráče MIN je obdobně prvek argmin. Strategie, která v každém stavu volí optimální tah, je minimaxová strategie.

Laicky řečeno

Hodnotu pozice spočítáte odzadu. Na konci hry ji znáte — je to skóre. O tah dřív: když hraje MAX, vybere si to nejlepší z toho, co ho čeká; když hraje MIN, vybere to nejhorší pro MAX. Takhle se hodnoty přelévají patro po patru nahoru až ke kořeni. Je to přesně úvaha „když půjdu sem, on půjde tam, a pak já…“, jen dotažená do konce.

1 4 2 4 6 2 10 3 3 4 4 6 5 9 7 2 8 7 9 8 11 5 12 3 13 9 MAX MIN
Minimax: hodnoty probublávají od listů ke kořeni

Uzel MIN vlevo si z listů 4, 6 a 9 vybere 4, prostřední z 2, 7 a 8 vybere 2, pravý z 5, 3 a 9 vybere 3. MAX v kořeni pak volí mezi 4, 2 a 3 a zahraje levý tah s hodnotou 4. Všimněte si, že pravá větev skrývá devítku — jenže na ni MAX nikdy nedosáhne, protože MIN by místo ní zahrál trojku.

Věta — co minimax zaručuje

Nechť Γ je konečná hra dvou hráčů a σ* minimaxová strategie hráče MAX. Pak

  1. pro každou strategii τ hráče MIN má partie hraná dvojicí (σ*, τ) užitek ≥ MM(s0);
  2. je-li i τ* minimaxová strategie hráče MIN, má partie hraná dvojicí (σ*, τ*) užitek právě MM(s0).

Důkaz (náčrt), indukcí podle výšky uzlu: v listu MAX získá přesně U(s) = MM(s). V uzlu MAX zahraje tah do dítěte s největší hodnotou a podle indukčního předpokladu si v něm uhájí aspoň tuto hodnotu, tedy aspoň MM(s). V uzlu MIN si soupeř vybere libovolné dítě, ale každé má hodnotu ≥ min = MM(s), a v každém si MAX podle předpokladu uhájí aspoň jeho hodnotu. Pro s = s0 to je bod 1. Stejnou úvahou s prohozenými rolemi si MIN minimaxovou strategií τ* zajistí užitek nejvýš MM(s0) proti každé strategii MAX; obě nerovnosti dohromady dávají bod 2. ∎

Minimax prochází strom do hloubky: čas O(bm), paměť O(b · m).

Laicky řečeno

Minimax počítá s nejhorším: předpokládá, že soupeř nikdy neudělá chybu. Když ji udělá, dopadnete jen lépe. Proto je minimax hodnota zaručená — to, co si uhájíte, ať soupeř hraje jakkoli.

4. Minimax na piškvorkách

Piškvorky 3 × 3 jsou dost malé, aby minimax prošel celý strom. Výsledek zná každý, kdo je hrál déle než pár minut: minimaxová hodnota prázdného pole je 0 — když oba hrají bez chyby, je to vždycky remíza. Zajímavější je, co minimax řekne o konkrétní pozici. Na tahu je X (MAX) a v každém volném políčku je hodnota tahu na něj:

X O −1 X +1 −1 O 0 −1
Hodnota každého tahu X podle minimaxu +1 výhra0 remíza−1 prohra

Vyhrává jediný tah — střed. X tím postaví vidličku: hrozí dokončit prostřední řádek i úhlopříčku a O nemůže zablokovat obojí. Tah dolů doprostřed drží remízu. Zbylé tři tahy vypadají nevinně, ale prohrávají: O na ně odpoví vlastní vidličkou. Člověk by to musel promyslet; minimax to prostě spočítá.

def minimax(deska):
    konec = vitez(deska)                 # "X", "O", "remiza", nebo None
    if konec:
        return {"X": 1, "O": -1, "remiza": 0}[konec]
    hodnoty = [minimax(zahraj(deska, tah)) for tah in volna_pole(deska)]
    return max(hodnoty) if na_tahu(deska) == "X" else min(hodnoty)

5. Alfa-beta ořezávání

Minimax projde celý strom, i když je z poloviny zbytečný. Podívejte se znovu na prostřední větev: první list ukázal 2. MIN tedy v té větvi dosáhne 2 nebo méně — a MAX už má levou větev s hodnotou 4 jistou. Ať jsou zbylé dva listy jakékoli, MAX do prostřední větve nepůjde. Nemusí se na ně ani dívat.

Definice — alfa-beta

Nechť Γ je konečná hra dvou hráčů. Alfa-beta je prohledávání do hloubky, které si s sebou nese dvě meze α, β ∈ ℝ ∪ {−∞, +∞}:

  1. α — nejvyšší hodnota, kterou si MAX už zajistil někde na cestě od kořene (na začátku −∞);
  2. β — nejnižší hodnota, kterou si už zajistil MIN (na začátku +∞).

Funkce AB(s, α, β) pro stav s ∈ S:

  1. Je-li s ∈ K, vrať U(s).
  2. Je-li hráč(s) = MAX, polož v ← −∞; jinak v ← +∞.
  3. Pro tahy a ∈ A(s) postupně (v pevném pořadí) spočítej h ← AB(T(s, a), α, β) a
    • v uzlu MAX polož v ← max(v, h) a α ← max(α, v),
    • v uzlu MIN polož v ← min(v, h) a β ← min(β, v);
    jakmile α ≥ β, zbylé tahy se ořežou — neprohledávají se — a pokračuje se krokem 4.
  4. Vrať v.

Alfa-beta v kořeni je volání AB(s0, −∞, +∞).

Věta. Nechť Γ je konečná hra dvou hráčů. Pak AB(s0, −∞, +∞) = MM(s0) — alfa-beta vrátí v kořeni stejnou hodnotu jako minimax (ve vnitřních uzlech, kde došlo k ořezu, vrací jen mez, ne přesnou hodnotu). Má-li strom větvicí faktor b a hloubku m a jsou-li tahy seřazené v nejlepším možném pořadí, prozkoumá alfa-beta jen O(bm/2) uzlů.

Laicky řečeno

α je „tohle už mám v kapse“, β je „víc mi soupeř stejně nedovolí“. Když v nějaké větvi zjistíte, že soupeř vás v ní může srazit pod to, co už máte jistého jinde, nemá smysl ji zkoumat dál — stačí jediný vyvracející tah. Hodnota v kořeni zůstane stejná, jen ji najdete rychleji.

ořízni, když α ≥ β

α
to nejlepší, co si MAX už zajistil jinde na cestě od kořene. Do větve, která dá méně, nikdy nepůjde — má lepší volbu
β
to nejhorší pro MAX, co mu MIN v téhle větvi už může vnutit. Víc než β odsud MAX nedostane, ať zbylé děti vyjdou jakkoli
≥
okno [α, β] je prázdné: hodnota, o kterou by se tu ještě dalo hrát, by musela být zároveň aspoň α a nejvýš β. Taková neexistuje (při rovnosti by nebyla lepší, než co MAX už má), takže zbytek větve kořen nemůže ovlivnit
V prostřední větvi stromu: α = 4 (levá větev), po prvním listu β = 2. Protože 4 ≥ 2, listy 7 a 8 se nezkoumají.
1 4 2 4 6 ≤2 8 ≤3 α=−∞ β=∞ α=−∞ β=∞ α=−∞ β=4 α=−∞ β=4 α=−∞ β=4 α=4 β=∞ α=4 β=∞ α=4 β=2 α=4 β=∞ α=4 β=∞ α=4 β=5 α=4 β=3 α=4 β=∞ 3 4 4 6 5 9 7 2 7 8 9 5 10 3 9 MAX MIN
Alfa-beta na stejném stromu: čísla jsou pořadí návštěv u uzlů okno α, β; oranžově, když α ≥ β a zbytek větve se ořízneořezáno listů: 3 / 9

Alfa-beta došla ke stejnému výsledku — MAX hraje vlevo a získá 4 — ale ohodnotila jen 6 listů z 9. V prostřední větvi ořízla dva listy hned po dvojce, v pravé jeden po trojce. U ořezaného uzlu MIN je proto jen mez „≤ 2“ a „≤ 3“: přesnou hodnotu neznáme, a nepotřebujeme ji.

Totéž, co animace ukazuje u uzlů, krok po kroku v tabulce. Řádek zachycuje okno uzlu při vstupu do něj a pak po každém dítěti, které vrátilo hodnotu:

krokuzelco se staloαβpoznámka
1A (MAX)vstup−∞+∞
2B (MIN)vstup−∞+∞
3B (MIN)b1 vrátil 4−∞4
4B (MIN)b2 vrátil 6−∞4
5B (MIN)b3 vrátil 9−∞4B vrací 4
6A (MAX)B vrátil 44+∞
7C (MIN)vstup4+∞
8C (MIN)c1 vrátil 242α ≥ β: ořez c2, c3; C vrací jen mez ≤ 2
9A (MAX)C vrátil 24+∞
10D (MIN)vstup4+∞
11D (MIN)d1 vrátil 545
12D (MIN)d2 vrátil 343α ≥ β: ořez d3; D vrací jen mez ≤ 3
13A (MAX)D vrátil 34+∞A vrací 4

Uzel MIN dostane od rodiče α = 4 a mění jen svoje β; uzel MAX naopak mění jen α. Okno každého uzlu se tak jen zužuje. V pravé větvi první list (5) ořez nevyvolá — 5 je víc než 4, MIN by tu MAXovi mohl dát víc než vlevo —, až druhý list (3) stáhne β pod α.

Na piškvorkách je rozdíl dramatičtější. Úplný minimax z prázdného pole navštíví 549 946 pozic, alfa-beta se stejným pořadím tahů jen 18 297 — asi třicetkrát méně — a vrátí stejnou nulu. Exponent m/2 ve větě znamená, že za stejný čas dohlédnete dvakrát hlouběji. Proto na pořadí tahů tolik záleží: šachové programy zkoušejí jako první braní a tahy, které byly dobré minule.

Příklad — kolik listů ušetří alfa-beta při nejlepším pořadí

Přesnou mez dokázali D. E. Knuth a R. W. Moore (An Analysis of Alpha-Beta Pruning, 1975): ve stromu s větvicím faktorem b a hloubkou d ohodnotí alfa-beta při nejlepším pořadí tahů

b⌈d/2⌉ + b⌊d/2⌋ − 1 listů místo bd.

Šachy, b = 35, hloubka d = 6 půltahů: minimax 356 = 1 838 265 625 listů, alfa-beta 353 + 353 − 1 = 42 875 + 42 875 − 1 = 85 749 listů — asi 21 000krát méně. A obráceně: 12 půltahů projde alfa-beta s 356 + 356 − 1 ≈ 3,7 · 109 listy, tedy jen za dvojnásobek práce, kterou minimax potřebuje na 6 půltahů.

Malý strom z obrázku (b = 3, d = 2): mez je 3 + 3 − 1 = 5 listů. Alfa-beta jich ohodnotila 6, protože pořadí listů není nejlepší možné — v pravé větvi stojí trojka až na druhém místě.

def alfabeta(deska, alfa=-inf, beta=inf):
    konec = vitez(deska)
    if konec:
        return {"X": 1, "O": -1, "remiza": 0}[konec]
    maximalizuje = na_tahu(deska) == "X"
    v = -inf if maximalizuje else inf
    for tah in volna_pole(deska):
        h = alfabeta(zahraj(deska, tah), alfa, beta)
        if maximalizuje:
            v = max(v, h); alfa = max(alfa, v)
        else:
            v = min(v, h); beta = min(beta, v)
        if alfa >= beta:
            break                          # ořez: zbytek větve nic nezmění
    return v

6. Omezená hloubka a ohodnocovací funkce

Ani alfa-beta neprojde šachový strom do konce partie. Skutečné programy proto hledají jen do pevné hloubky a pozici, ve které skončí, odhadnou.

Definice — minimax s omezenou hloubkou

Nechť Γ = (S, s0, hráč, A, T, K, U) je hra dvou hráčů. Ohodnocovací funkce je funkce E : S → ℝ taková, že E(s) = U(s) pro všechna s ∈ K; pro s ∉ K je E(s) odhad MM(s). Obvykle je to vážený součet n ≥ 1 příznaků pozice f1, …, fn : S → ℝ s vahami w1, …, wn ∈ ℝ:

E(s) = w1f1(s) + … + wnfn(s).

Minimax s omezenou hloubkou je pro každé d ∈ ℕ0 funkce MMd : S → ℝ definovaná rekurzivně podle d:

  1. MMd(s) = E(s), je-li s ∈ K nebo d = 0;
  2. MMd(s) = maxa ∈ A(s) MMd−1(T(s, a)), je-li s ∉ K, d ≥ 1 a hráč(s) = MAX;
  3. MMd(s) = mina ∈ A(s) MMd−1(T(s, a)), je-li s ∉ K, d ≥ 1 a hráč(s) = MIN.

Hodnota MMd(s) tedy počítá minimax jen d půltahů dopředu a pozice, ve kterých skončí, nahradí odhadem E. Je-li d aspoň délka nejdelší partie ze s, je MMd(s) = MM(s).

Laicky řečeno

Neumíte domyslet partii do konce, tak se podíváte pár tahů dopředu a zeptáte se: „Jak dobře to tu vypadá?“ V šachu je nejjednodušší odpověď spočítat materiál — pěšec 1, jezdec a střelec 3, věž 5, dáma 9 — a odečíst soupeřův. Lepší funkce přidají aktivitu figur, bezpečnost krále nebo strukturu pěšců.

E(s) = ∑i wi · (pi(s) − p′i(s))

E(s)
odhad hodnoty pozice z pohledu MAX (bílého) — dosadí se tam, kde hledání skončí, místo skutečné minimaxové hodnoty
∑i
přes druhy figur: pěšec, jezdec, střelec, věž, dáma. Součet, protože materiál různých figur se v nejjednodušším modelu prostě sčítá
wi
cena figury: 1, 3, 3, 5, 9. Váha převádí „kusy“ na společnou měnu, aby šlo porovnat věž s dvěma jezdci
pi − p′i
kolik figur daného druhu má bílý víc než černý. Rozdíl, ne počet, protože hra má nulový součet: co má soupeř navíc, je ztráta
Bílý má o jezdce víc, černý o dva pěšce víc: E = 3 · (+1) + 1 · (−2) = +1, tedy mírná výhoda bílého. Ceny figur jsou tradiční šachová konvence, ne výsledek výpočtu.
def minimax_d(s, d):
    if je_konec(s) or d == 0:
        return E(s)                        # dál nevidíme: odhad místo skutečné hodnoty
    hodnoty = [minimax_d(T(s, a), d - 1) for a in akce(s)]
    return max(hodnoty) if hrac(s) == "MAX" else min(hodnoty)

def iterativni_prohlubovani(s, cas):      # v s je na tahu MAX
    d, nejlepsi = 1, None
    while zbyva(cas):
        nejlepsi = max(akce(s), key=lambda a: minimax_d(T(s, a), d - 1))
        d += 1                             # další kolo o půltah hlouběji
    return nejlepsi

Omezená hloubka má svou past: efekt horizontu. Když hledání skončí uprostřed výměny figur — vy jste právě vzali dámu, soupeř ji za tah vezme zpátky —, ohodnocovací funkce vidí jen první polovinu a pozici přecení. Programy se brání tím, že „neklidné“ pozice prohledávají dál, dokud se neuklidní. A protože nikdy nevědí, kolik mají času, hledají iterativním prohlubováním z minulého dílu: hloubka 1, 2, 3, … dokud nedojde čas. Výsledky mělkých průchodů navíc poslouží jako pořadí tahů pro hlubší — a alfa-beta pak ořezává mnohem víc.

7. Monte Carlo tree search

Ohodnocovací funkci pro šachy lidé ladili desítky let. Pro go se ji napsat nedařilo — pozice, která vypadá klidně, může být o dvacet tahů později prohraná. Monte Carlo tree search (MCTS) na ohodnocovací funkci úplně rezignuje. Místo odhadu pozici dohraje: náhodně, mnohokrát, a podívá se, jak často to dopadlo dobře.

Definice — jedna iterace MCTS

Nechť Γ = (S, s0, hráč, A, T, K, U) je konečná hra dvou hráčů, ve které má každá partie výsledek výhra, remíza, nebo prohra. Vstup: stav s0 ∉ K (kořen) a počet iterací (nebo časový limit). Výstup: tah a ∈ A(s0).

MCTS buduje prohledávací strom — část herního stromu, která začíná jen kořenem a v každé iteraci se o jeden uzel rozroste. Každý uzel i stromu si pamatuje:

  1. počet návštěv ni ∈ ℕ0 — kolik simulací prošlo uzlem;
  2. součet výsledků wi ∈ [0, ni] z pohledu hráče, který do uzlu táhl, přičemž výsledek jedné partie je 1 za výhru, ½ za remízu a 0 za prohru.

Uzel je plně rozšířený, právě když má ve stromu dítě pro každý tah a ∈ A(s) svého stavu s. Jedna iterace MCTS má čtyři kroky:

  1. Výběr — začni v kořeni; dokud je aktuální uzel plně rozšířený a jeho stav není koncový, přejdi do dítěte s nejvyšší hodnotou UCT (definice níže).
  2. Rozšíření — není-li stav aktuálního uzlu koncový, vyber dosud nezkoušený tah a, přidej dítě se stavem T(s, a) a n = w = 0 a přejdi do něj.
  3. Simulace — ze stavu aktuálního uzlu dohraj partii náhodnými tahy (každý z A(s) se stejnou pravděpodobností) až do koncového stavu sK ∈ K.
  4. Zpětné šíření — každému uzlu i na cestě od aktuálního uzlu zpět ke kořeni (včetně obou) polož ni ← ni + 1 a wi ← wi + výsledek partie sK z pohledu hráče, který do uzlu i táhl.

Iterace se opakují, dokud nevyprší počet iterací nebo čas. Pak se zahraje tah z kořene do dítěte s největším ni.

Laicky řečeno

Jako když se rozhodujete mezi restauracemi: chodíte tam, kde vám zatím chutnalo nejvíc, ale občas zkusíte i jinou. Každý tah dostane šanci, slibné tahy dostanou víc pokusů, a strom roste právě tam, kde se hraje o hodně. Náhodné dohrávky jsou hloupé, jenže když jich je tisíc, průměr už něco říká.

1 výběr 2 rozšíření výhra 3 simulace +1+1+1+1 4 zpětné šíření
Čtyři kroky jedné iterace MCTS
def mcts(koren, iteraci):
    for _ in range(iteraci):
        u = koren
        while u.vsechny_deti() and u.deti:         # 1. výběr
            u = max(u.deti, key=uct)
        if u.nezkusene and not je_konec(u.stav):   # 2. rozšíření
            u = u.pridej_dite(nahodny(u.nezkusene))
        s = u.stav
        while not je_konec(s):                     # 3. simulace
            s = T(s, nahodny(akce(s)))
        while u is not None:                       # 4. zpětné šíření
            u.n += 1
            u.w += vysledek(s, pro=u.kdo_tahl)     # 1, ½ nebo 0
            u = u.rodic
    return max(koren.deti, key=lambda d: d.n).tah
Definice — UCT

Nechť uzel prohledávacího stromu MCTS má N ≥ 1 návštěv a děti i = 1, …, k, každé s ni ≥ 1 návštěvami a součtem výsledků wi ∈ [0, ni] (značení z definice MCTS výše). Nechť c > 0 je pevná konstanta průzkumu, obvykle c = √2. Hodnota UCT (Upper Confidence bounds applied to Trees) dítěte i je

UCT(i) = wi/ni + c · √ln N/ni.

Ve kroku výběru se volí dítě i* ∈ argmaxi ∈ {1, …, k} UCT(i). Kocsis a Szepesvári (2006) dokázali, že s rostoucím počtem iterací pravděpodobnost, že MCTS s UCT doporučí jiný než minimaxově optimální tah, klesá k nule.

Laicky řečeno

První člen je „jak dobře to zatím dopadalo“, druhý „jak málo to znám“. Tah, který jste dlouho nezkusili, dostává bonus, který s každou návštěvou jiného tahu pomalu roste. Je to stejné dilema jako u zpětnovazebního učení: využívat to, co funguje, nebo prozkoumávat, co by mohlo fungovat líp?

UCT(i) = wi/ni + c · √ln N/ni

UCT(i)
skóre dítěte i ve výběru; vyhraje největší. Není to odhad hodnoty tahu, ale „jak moc se vyplatí ho zkusit znovu“
wi/ni
průměrný výsledek tahu (0 až 1) — využívání: tahy, které zatím vycházely dobře, dostanou přednost
c
konstanta průzkumu — kolik váží zvědavost proti dosavadním výsledkům. Hodnota √2 pochází z pravidla UCB1 pro mnohoruké bandity (Auer, Cesa-Bianchi a Fischer, 2002) pro výsledky v ⟨0, 1⟩; na stromy ho přenesli Kocsis a Szepesvári (2006). V praxi se ladí
ln N
roste s počtem návštěv rodiče, ale jen pomalu. Díky němu bonus málo zkoušených tahů pomalu roste: každý tah se dřív nebo později zkusí znovu
ni
kolikrát už byl tah zkoušen — ve jmenovateli, takže čím méně ho známe, tím větší bonus. Odmocnina odpovídá (zjednodušeně) tomu, jak rychle se zpřesňuje průměr: jeho nejistota klesá jako 1/√n
Druhý člen dohromady je prozkoumávání. Jeho vliv slábne, jak tah sbírá návštěvy, ale protože ln N roste, nespadne nikdy na nulu.

Pusťme MCTS na pozici, kterou minimax rozluštil výše. Čísla v políčkách jsou návštěvy po 100, 300 a 1000 iteracích, pod nimi průměrný výsledek pro X:

X O X O 12 0,42 47 0,86 7 0,14 19 0,61 15 0,50 100 iterací 20 0,38 197 0,89 24 0,44 33 0,55 26 0,44 300 iterací 27 0,33 856 0,94 30 0,38 52 0,55 35 0,43 1000 iterací
MCTS v téže pozici: kolikrát který tah navštívil nahoře návštěvy, dole průměrný výsledek pro X

Po 100 iteracích má střed 47 návštěv a ostatní tahy dohromady víc. Po tisíci jich má 856 a průměrný výsledek 0,94; remízový tah dole uprostřed dostal 52 návštěv, prohrávající tahy ještě méně. MCTS přitom nezná ani pojem vidlička, ani žádnou ohodnocovací funkci — jen pravidla a náhodu. A přesto našel stejný tah jako minimax, který musel projít celý zbytek stromu.

Proč zrovna takové rozložení návštěv? Spočítejme UCT tahů z kořene po 1000 iteracích (N = 1000, ln N ≈ 6,908, c = √2; barvy podle vzorce výše):

tahniwi/nibonus c · √ln N/niUCT
vpravo nahoře (2)270,3330,7151,049
střed (4)8560,9410,1271,068
vpravo uprostřed (5)300,3830,6791,062
dole uprostřed (7)520,5480,5151,064
vpravo dole (8)350,4290,6281,057

Hodnoty UCT jsou skoro stejné — v rozmezí 1,049 až 1,068. Není to náhoda: výběr pokaždé navštíví tah s nejvyšším UCT, a tím mu sníží bonus (průměr se přitom změní jen málo), takže se hodnoty postupně vyrovnají. Střed má nejlepší průměr, a proto mu na vyrovnání stačí malý bonus — tedy hodně návštěv. Ostatní tahy mají horší průměr a dorovnávají ho velkým bonusem, na který stačí málo návštěv. (Součty v tabulce počítáme z nezaokrouhlených hodnot, v posledním místě se proto mohou lišit o 1.)

8. Od Deep Blue k AlphaZero

  • Deep Blue (1997) porazil mistra světa Garriho Kasparova. Uvnitř byla alfa-beta s ručně psanou ohodnocovací funkcí a specializovaný hardware, který zvládl kolem 200 milionů pozic za sekundu.
  • Chinook hrál dámu proti mistrům světa už v 90. letech a v roce 2007 jeho autoři hru vyřešili: prošli tolik pozic, že dokázali, že bezchybná partie končí remízou — stejně jako piškvorky 3 × 3.
  • AlphaGo (2016) porazil Lee Se-dola 4 : 1. Spojil MCTS s neuronovými sítěmi: jedna síť navrhovala slibné tahy (místo náhodného výběru), druhá odhadovala hodnotu pozice (místo celé náhodné dohrávky).
  • AlphaZero (2017) zahodil i lidské partie. Naučil se šachy, šogi a go jen hraním sám proti sobě — zpětnovazebním učením — a v každé z her porazil nejlepší dosavadní program.
  • Hry s náhodou a skrytou informací potřebují víc. V backgammonu rozhoduje kostka, takže se do stromu přidávají uzly náhody se střední hodnotou (expectiminimax). V pokeru nevidíte soupeřovy karty; program Libratus (2017) přesto porazil profesionály v pokeru dvou hráčů.
Definice — expectiminimax

Nechť Γ = (S, s0, hráč, A, T, K, U) je konečná hra jako v definici hry dvou hráčů, jen ke hráčům MAX a MIN přibude „hráč“ NÁHODA: hráč : S ∖ K → {MAX, MIN, NÁHODA} a podmínka střídání se nevyžaduje. Pro každý stav s s hráč(s) = NÁHODA je A(s) konečná neprázdná množina možných výsledků náhody r (třeba čísel na kostce) a je dáno rozdělení pravděpodobnosti Ps : A(s) → [0, 1] s ∑r ∈ A(s) Ps(r) = 1 (viz díl o pravděpodobnosti); výsledek r nastane s pravděpodobností Ps(r) a vede do stavu T(s, r).

Expectiminimaxová hodnota je funkce EMM : S → ℝ definovaná rekurzivně:

  1. EMM(s) = U(s), je-li s ∈ K;
  2. EMM(s) = maxa ∈ A(s) EMM(T(s, a)), je-li hráč(s) = MAX;
  3. EMM(s) = mina ∈ A(s) EMM(T(s, a)), je-li hráč(s) = MIN;
  4. je-li hráč(s) = NÁHODA, je EMM(s) střední hodnota hodnot následníků: EMM(s) = ∑r ∈ A(s) Ps(r) · EMM(T(s, r)).

V uzlech MAX a MIN se tedy hodnota počítá jako u minimaxu a v uzlech náhody jako průměr vážený pravděpodobnostmi výsledků. Rozbor posledního vzorce (Ps zkráceně jako P):

EMM(s) = ∑r P(r) · EMM(T(s, r))

EMM(s)
hodnota uzlu náhody — co může MAX od pozice čekat v průměru, protože výsledek hodu neovlivní ani on, ani soupeř
∑r
přes všechny možné výsledky náhody; místo výběru nejlepšího (max) nebo nejhoršího (min) se tu nevybírá nic — započítá se každý
P(r)
pravděpodobnost výsledku jako váha: častý výsledek ovlivní hodnotu víc než vzácný
EMM(T(s, r))
hodnota pozice po daném výsledku, spočítaná rekurzivně stejným pravidlem
Hod mincí: panna (s pravděpodobností 1/2) vede do pozice s hodnotou 4, orel (1/2) do pozice s hodnotou −2. EMM = 1/2 · 4 + 1/2 · (−2) = 2 − 1 = 1. Tah do jisté pozice s hodnotou 0,5 je tedy horší, i když nehrozí ztráta.

Myšlenka „podívej se dopředu, než něco uděláš“ ze šachovnic nezmizela. Plánující jazykoví agenti zkoušejí několik variant postupu, ohodnotí je a pokračují tou nejslibnější — jen místo tahů figur volí kroky řešení.

9. Shrnutí

  • Hra dvou hráčů s nulovým součtem je úloha prohledávání, ve které se o tahy dělíte se soupeřem; řešením je strategie, ne cesta.
  • Minimax počítá hodnotu odzadu: MAX bere maximum, MIN minimum. Výsledek je zaručený proti jakémukoli soupeři.
  • Alfa-beta vrátí stejnou hodnotu, ale ořízne větve, které výsledek nemůžou změnit; s dobrým pořadím tahů dohlédne dvakrát hlouběji.
  • Velké hry se prohledávají do omezené hloubky s ohodnocovací funkcí — a pozor na efekt horizontu.
  • MCTS místo ohodnocení pozici mnohokrát náhodně dohraje a strom rozvíjí tam, kde je to slibné; s neuronovými sítěmi z něj vznikl AlphaGo.

Chcete si to osahat? Nechte AI agenta napsat piškvorky s minimaxem a pak spočítejte, kolik pozic ušetří alfa-beta, když tahy seřadíte od středu k okrajům.

Máte na to jiný názor? Napište na support@coden-app.com.

Agent na vašem počítači, ovládaný z telefonu