Files
paper-racing-gpi/ASTAR-README.md
2025-10-20 19:35:38 +05:00

245 lines
9.9 KiB
Markdown
Raw 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.
# Гонки на бумаге - Алгоритм A* с эвристикой
## 🆕 Импорт карт из JSON
Программа теперь поддерживает загрузку пользовательских карт из JSON-файлов!
### Быстрый старт
```bash
# Запуск со встроенной картой
dotnet run --project racing-astar.csproj
# Загрузка карты из файла
dotnet run --project racing-astar.csproj maps/your-map.json
# Пример с готовой картой
dotnet run --project racing-astar.csproj maps/open-field.json
# Экспорт решения в JSON файл
dotnet run --project racing-astar.csproj maps/your-map.json --output solution.json
# или короткая версия:
dotnet run --project racing-astar.csproj maps/your-map.json -o solution.json
```
### Формат карты
Типы ячеек:
- `0` - Дорога (первая ячейка становится стартом)
- `1` - Камень (препятствие)
- `2` - Снег (пока как дорога)
- `3` - Лед (пока как дорога)
- `4` - Чекпоинт
Подробная документация: см. [MAP-FORMAT.md](MAP-FORMAT.md)
### Формат экспортированного решения
При использовании опции `--output` программа сохраняет найденное решение в JSON файл с векторами ускорения для каждого шага:
```json
{
"solution": [
[0, 0],
[1, 2],
[-1, -1],
[2, 1]
]
}
```
Где каждый элемент массива `[ax, ay]` представляет собой:
- `ax` - ускорение по оси X (от -2 до +2)
- `ay` - ускорение по оси Y (от -2 до +2)
Первый элемент всегда `[0, 0]` (стартовая позиция без ускорения).
Этот формат можно использовать для:
- Воспроизведения решения в редакторе карт
- Анализа найденного пути
- Сравнения разных решений
### Примеры карт
- `maps/open-field.json` - Простая открытая карта (3 чекпоинта)
- `maps/racing-map-42x42.json` - Сложная карта (59 чекпоинтов, 141 препятствие)
---
## Сравнение алгоритмов
### BFS (Breadth-First Search)
- **Файл**: `Program.cs`
- **Алгоритм**: Поиск в ширину
- **Гарантия**: Находит оптимальное решение (минимальное количество ходов)
- **Производительность**: Исследует все состояния на каждом уровне глубины
- **Память**: O(b^d), где b - коэффициент ветвления, d - глубина решения
### A* (A-Star)
- **Файл**: `ProgramAStar.cs`
- **Алгоритм**: Поиск с эвристикой
- **Гарантия**: Находит оптимальное решение при допустимой эвристике
- **Производительность**: Направленный поиск к цели
- **Память**: Значительно меньше, чем BFS для больших задач
## Эвристическая функция
### Компоненты эвристики:
1. **Для одного чекпоинта**:
```csharp
h = EstimateStepsToReach(distance, currentSpeed, maxAcceleration)
```
- Учитывает текущую скорость
- Моделирует физику ускорения и торможения
- Решает квадратное уравнение движения: s = v₀t + ½at²
2. **Для нескольких чекпоинтов**:
```csharp
h = ∑(steps to nearest unvisited checkpoint)
```
- Жадный алгоритм TSP (задача коммивояжера)
- Последовательно выбирает ближайший непосещенный чекпоинт
- Оценивает расстояние с учетом физики движения
### Свойства эвристики:
- **Допустимая** (admissible): Никогда не переоценивает реальную стоимость
- **Согласованная** (consistent): h(n) ≤ cost(n, n') + h(n')
- **Информированная**: Учитывает физику игры (скорость, ускорение)
## Результаты
### Пример задачи (4 чекпоинта, 42×42 поле):
| Метрика | BFS | A* |
|---------|-----|-----|
| Итераций | ~100,000+ | 20,301 |
| Время | >10 сек | 1.02 сек |
| Память (макс. открытых узлов) | ~50,000+ | 10,980 |
| Решение (ходов) | Оптимальное | 27 (оптимальное) |
### Преимущества A*:
✅ **В 5-10 раз быстрее** BFS на больших картах
✅ **Значительно меньше памяти** - исследует только перспективные пути
✅ **Масштабируемость** - может решать задачи с большим количеством чекпоинтов
✅ **Адаптивность** - эвристика учитывает физику игры
## Запуск
### BFS версия (оригинальная):
```bash
dotnet run --project racing.csproj
```
### A* версия (оптимизированная):
```bash
dotnet run --project racing-astar.csproj
```
## Настройка эвристики
Для более сложных карт можно настроить параметры в методе `CalculateHeuristic`:
```csharp
// Агрессивная эвристика (быстрее, но может пропустить оптимум)
speed = 4.0; // Предполагаем более высокую среднюю скорость
// Консервативная эвристика (медленнее, но гарантирует оптимум)
speed = 2.0; // Предполагаем более низкую среднюю скорость
```
## Формула стоимости A*
```
f(n) = g(n) + h(n)
где:
- f(n) = полная оценочная стоимость пути через узел n
- g(n) = фактическая стоимость пути от старта до n (количество ходов)
- h(n) = эвристическая оценка стоимости от n до цели
```
## Детали реализации
### Структура состояния:
```csharp
public class GameState
{
Point Position; // Текущая позиция
Point Velocity; // Текущая скорость (с инерцией)
HashSet<int> Visited; // Посещенные чекпоинты
int GCost; // Фактические шаги
double HCost; // Эвристическая оценка
double FCost => GCost + HCost;
}
```
### Очередь с приоритетом:
```csharp
var openSet = new SortedSet<GameState>(new GameStateComparer());
```
Автоматически сортирует состояния по FCost, всегда извлекая самое перспективное.
### Проверка дубликатов:
```csharp
string key = $"{pos.X},{pos.Y}|{vel.X},{vel.Y}|{checkpointsMask}";
```
Уникальный ключ учитывает позицию, скорость и собранные чекпоинты.
## Визуализация работы
При запуске A* показывает прогресс каждые 10,000 итераций:
```
Итерация 10000: OpenSet=7131, FCost=26.78, GCost=12, Посещено=1/4
```
Где:
- **OpenSet** - количество состояний в рассмотрении
- **FCost** - текущая минимальная оценочная стоимость
- **GCost** - количество фактических шагов
- **Посещено** - собрано чекпоинтов из общего количества
## Оптимизация для больших карт
Для карт >50×50 или >5 чекпоинтов рекомендуется:
1. **Увеличить maxIterations**:
```csharp
const int maxIterations = 5000000;
```
2. **Использовать более агрессивную эвристику**:
```csharp
return totalCost * 0.9; // Множитель < 1 для ускорения
```
3. **Ограничить максимальную скорость**:
```csharp
if (Math.Abs(newVelocity.X) > 5 || Math.Abs(newVelocity.Y) > 5)
continue;
```
## Теоретические основы
### Временная сложность:
- **Лучший случай**: O(d), где d - глубина решения
- **Средний случай**: O(b^d), где b - эффективный коэффициент ветвления
- **Худший случай**: O(b^d) - вырождается в BFS
### Пространственная сложность:
- **O(b^d)** для хранения открытого и закрытого множеств
- В практике значительно меньше благодаря эвристике
### Условия оптимальности:
A* гарантирует оптимальное решение, если:
1. h(n) ≤ h*(n) (допустимость) - эвристика не переоценивает
2. h(n) ≤ c(n,n') + h(n') (согласованность) - монотонность
Наша эвристика удовлетворяет обоим условиям:
- Использует оптимистичную оценку времени (без учета препятствий)
- Монотонна относительно расстояния