Files
football/docs/plans/2026-05-09-tactical-ai.md
2026-05-12 10:54:09 +03:00

152 lines
5.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# План: Тактический ИИ и Ролевая Логика (M4)
**Цель:** Реализовать роль Вратаря с логикой перекрытия углов и систему зонирования для нападающих и защитников.
**Архитектура:**
- Введение `RoleGoalie` в перечисление ролей.
- Реализация специализированного метода `updateGoalieAI`, который вычисляет целевую точку на векторе «Центр ворот -> Шайба» с ограничением по радиусу.
- Внедрение системы зон (Защитная, Средняя, Атакующая) для динамического изменения агрессивности игроков.
**Стек:** Go
**Спека:** [docs/specs/2026-05-09-tactical-ai-design.md](../specs/2026-05-09-tactical-ai-design.md)
---
## Файловая структура
- `internal/entities/player.go` — добавление `RoleGoalie`.
- `internal/game/world.go` — константы зон, логика ИИ вратаря и зонирования.
- `internal/game/world_test.go` — тесты на поведение вратаря и смену зон.
---
## Задачи
### Задача 1: Расширение ролей и константы зон
**Файлы:**
- Изменить: `internal/entities/player.go`
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Добавить `RoleGoalie` в `PlayerRole`**
```go
type PlayerRole int
const (
RoleStriker PlayerRole = iota
RoleDefender
RoleGoalie // Добавить это
)
```
- [ ] **Шаг 2: Добавить константы зон в `world.go`**
```go
const (
ZoneWidth = WorldWidth / 3
GoalieMaxDistance = 80.0 // Максимальный выход вратаря из ворот
)
```
- [ ] **Шаг 3: Коммит**
`git add internal/entities/player.go internal/game/world.go`
`git commit -m "feat(ai): add RoleGoalie and zone constants"`
### Задача 2: Реализация ИИ Вратаря (Перехватчик)
**Файлы:**
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Реализовать `updateGoalieAI`**
Логика:
1. Определить центр своих ворот (`GoalLeft` или `GoalRight`).
2. Вычислить вектор от центра ворот к шайбе.
3. Целевая точка = Центр ворот + (Нормализованный вектор * min(дистанция_доайбы, GoalieMaxDistance)).
4. Ограничить Y в пределах ворот (например, +/- 100 пикселей от центра).
```go
func (w *World) updateGoalieAI(p *entities.Player, puckPos entities.Vector2D) entities.Vector2D {
goalPos := GoalLeft
if p.Team == TeamRight {
goalPos = GoalRight
}
// Вектор от ворот к шайбе
dir := puckPos.Sub(goalPos)
dist := dir.Len()
// Ограничиваем выход из ворот
moveDist := dist
if moveDist > GoalieMaxDistance {
moveDist = GoalieMaxDistance
}
target := goalPos.Add(dir.Normalize().Mul(moveDist))
// Ограничение по Y (чтобы не уходил за пределы ворот)
if target.Y < WorldCenterY-100 { target.Y = WorldCenterY-100 }
if target.Y > WorldCenterY+100 { target.Y = WorldCenterY+100 }
return target
}
```
- [ ] **Шаг 2: Интегрировать в `updatePlayerAI`**
```go
switch p.Role {
case entities.RoleGoalie:
target = w.updateGoalieAI(p, puckPos)
// ... остальные роли
}
```
- [ ] **Шаг 3: Коммит**
`git commit -m "feat(ai): implement goalie interceptor logic"`
### Задача 3: Система зонирования для полевых игроков
**Файлы:**
- Изменить: `internal/game/world.go`
- [ ] **Шаг 1: Реализовать определение зоны**
```go
func (w *World) getPlayerZone(p *entities.Player) int {
// 0: Защитная, 1: Средняя, 2: Атакующая
// Для TeamLeft: X < ZoneWidth (Защитная), X < 2*ZoneWidth (Средняя), else (Атакующая)
// Для TeamRight: X > 2*ZoneWidth (Защитная), X > ZoneWidth (Средняя), else (Атакующая)
if p.Team == TeamLeft {
if p.Pos.X < ZoneWidth { return 0 }
if p.Pos.X < 2*ZoneWidth { return 1 }
return 2
} else {
if p.Pos.X > 2*ZoneWidth { return 0 }
if p.Pos.X > ZoneWidth { return 1 }
return 2
}
}
```
- [ ] **Шаг 2: Обновить логику Striker и Defender с учетом зон**
- **Striker**: В зоне 0 (защитной) стремится к центру поля, в зоне 2 (атакующей) — агрессивно к шайбе.
- **Defender**: В зоне 0 — агрессивно к шайбе, в зоне 2 — возвращается к своим воротам.
- [ ] **Шаг 3: Коммит**
`git commit -m "feat(ai): implement player zoning logic"`
### Задача 4: Тестирование и верификация
**Файлы:**
- Изменить: `internal/game/world_test.go`
- [ ] **Шаг 1: Тест `TestWorld_GoaliePositioning`**
- Проверить, что вратарь TeamLeft при шайбе в центре поля стоит в районе `GoalLeft` и не уходит дальше `GoalieMaxDistance`.
- Проверить, что вратарь смещается вслед за шайбой по Y.
- [ ] **Шаг 2: Тест `TestWorld_ZoningBehavior`**
- Проверить, что защитник в атакующей зоне стремится вернуться назад.
- [ ] **Шаг 3: Запуск тестов**
`go test ./internal/game/ -v`
- [ ] **Шаг 4: Коммит**
`git commit -m "test(ai): add goalie and zoning tests"`