MCTS · четыре в ряд
0случайных партий доиграно для последнего хода
Это единственная настройка силы. Поставь 120 — обыграешь его за минуту. Поставь 80 000 — тот же код, ни одной новой строчки, и он перестанет проигрывать. Ум здесь покупается числом, а не идеей.
// один случайный доигрыш: пока игра не кончилась — кидаем монетку function rollout(s){ while(!s.over){ const moves = legal(s); play(s, moves[Math.random()*moves.length|0]); // ← вся «стратегия» } return s.winner; } // какого ребёнка изучать дальше: UCB1 function pick(node){ return best(node.children, c => c.w/c.n + 1.4 * Math.sqrt(Math.log(node.n)/c.n) ); // ↑ доля побед ↑ бонус редко проверенным } // цикл: спустился → добавил ход → доиграл → разнёс результат назад function think(root, iters){ for(let i=0; i<iters; i++){ let node = root; while(node.full && node.children.length) node = pick(node); if(!node.over) node = expand(node); const winner = rollout(copy(node.state)); while(node){ node.n++; node.w += score(node, winner); node = node.parent; } } return most_visited(root.children); // ход, который проверяли чаще всех }
Найди здесь знание про «четыре в ряд». Его нет. Правило победы живёт в функции play, которая просто останавливает партию — она нужна, чтобы игра вообще имела конец. Всё остальное — доля побед и квадратный корень.
Почему это работает: один случайный доигрыш — чистый шум. Но столбец, из которого чаще выигрывают, действительно лучше — и двадцать тысяч бросков это различие вылавливают. Ровно как точки, которыми мы мерили площадь круга: измеряем то, что не умеем вычислить.
Дерево при этом растёт кривым: перспективные линии получают тысячи посещений и глубину в 20 ходов, мусорные — по два визита и забываются. Никто не программировал, какие линии перспективные. Их выбрала дробь w/n.