# ADR-0002: алгоритм поиска групп и дамэ — flood fill Дата: 2026-08-05 | Статус: принято (этап 1) ## Контекст Движку правил (packages/core) на каждый ход нужно находить группы камней и их дамэ: при проверке захватов, самоубийства, при подсчёте и в эвристике мёртвых групп. План этапа 1 предписывает выбрать между flood fill и union-find по микро-бенчмарку и зафиксировать выбор в ADR. ## Альтернативы 1. **Flood fill** — обход группы стеком от стартового камня, дамэ собираются в множество. Простая реализация, локальный обход (только затронутые группы). 2. **Union-find** — массив parent на всю доску, объединение соседей одного цвета, дамэ агрегируются по корням. Теоретически эффективен при инкрементальных обновлениях, но наша позиция неизменяема: структуру пришлось бы перестраивать на каждый ход, что обнуляет его главное преимущество. ## Бенчмарк `packages/core/bench/group-bench.mts` (запуск: `npx tsx ...`): оба алгоритма находят все группы и дамэ на случайных позициях 19×19 (плотности 0.35/0.55/0.75, 40 позиций × 300 итераций на плотность, детерминированный RNG). Среда: Node.js 20, x86-64. Контрольные суммы результатов совпали. | Плотность | flood fill | union-find | u/f | | --------- | ---------- | ---------- | ---- | | 0.35 | 230.4 мс | 373.1 мс | 1.62 | | 0.55 | 288.5 мс | 505.6 мс | 1.75 | | 0.75 | 328.3 мс | 596.8 мс | 1.82 | | Итого | 847.1 мс | 1475.5 мс | 1.74 | Union-find проигрывает на всех плотностях (в 1.6–1.8 раза): на маленькой доске (361 клетка) стоимость полного прохода union-find и аллокаций Map/Set по корням не окупается, а flood fill обходится дешёвыми операциями над массивом и одним множеством дамэ на группу. ## Решение Оставляем **flood fill** (реализован в `groupAt`, packages/core/src/board.ts). ## Причины - Быстрее на целевом профиле (доски 9–19, обходы только затронутых групп). - Существенно проще код и меньше аллокаций; неизменяемость BoardState всё равно не даёт переиспользовать структуру union-find между ходами. - Производительности достаточно с запасом: полный пересчёт всех групп 19×19 — десятки микросекунд, а движок обходит лишь соседние с ходом группы. ## Компромисс Если этапы 3–4 (ИИ) покажут профилировкой, что пересчёт групп — узкое место (например, массовые симуляции MCTS), решение пересматривается: кандидат — инкрементальный union-find с копированием при записи или кэш групп в узлах симуляции. Точка пересмотра — бенчмарк на реальной нагрузке ИИ, не раньше.