# ВП03 — «Датчики в непогоду»: игровая лабораторная

[План реализации ВП03](https://gitlab.astersky.ru/science/learncourses/-/blob/main/ИТЛН/План_реализации_ВП03.md#game) · [Открыть лабораторную](index.html) · [Стенд «Склад»](../../stands/warehouse/index.html) · [Стенд «Сцены 3D»](../../stands/scenes3d/README.md)

Учебная лабораторная ИТЛН (с 23.10.2026): кампания из пяти миссий в трёх мирах, в стиле компьютерной игры. Стенд «Склад», с которого начиналась ВП03, теперь общий: [`../../stands/warehouse/`](../../stands/warehouse/README.md).

<a id="lab"></a>
## Лабораторная: как устроена

**Ход игры.** Экран загрузки → титул (номер варианта 1–15, фамилия и группа) → карта кампании → миссии по порядку → итоги и отчёт. Каждая миссия проходит пять этапов: брифинг, теория, расчёт, заезд, разбор. Теория — карточки с формулами (MathML), живыми графиками на ползунках и трёхмерными демонстрациями прямо в мире: импульс лидара уходит к мишени и возвращается, гаснет в тумане, перехватывается снежинкой; тормозной путь рисуется на земле. Справочник (C) и журнал опытов (J) доступны всегда; камера — кнопки 1–5.

| Миссия | Мир | Опыт плана | Что делает студент |
|---|---|---|---|
| 1. Калибровка | Полярная станция, ясно | Э1 | Рассчитывает $R_{\mathrm c}$ двух мишеней; робот снимает шум дальности на 10, 20 и 30 м и отъезжает, пока тёмная мишень не пропадёт |
| 2. Белая мгла | Город, дым и туман | Э2 | Рассчитывает $\alpha$ для трёх видимостей и $R_{\max}$ — делением отрезка пополам в тренажёре; три отъезда в тумане, сравнение с расчётом |
| 3. Метель (или ливень — по варианту) | Полярная станция или город | Э3 | Рассчитывает $p(R)$ для двух мишеней; две серии по 30 оборотов; доля ложных точек по лучам на мишень и гистограмма их дальностей против экспоненциального закона; кнопка подсветки ложных точек |
| 4. Чистый сигнал | Те же осадки | Э4 | Пишет на Python функцию `filter_points` (NumPy); проверка по скрытой разметке: удалить ≥ 90 % ложных, потерять ≤ 5 % истинных; результат — цветное облако в 3D |
| 5. Буря | Марс, пылевая буря | Э5 | Рассчитывает дальности обнаружения лидаром и камерой и безопасную скорость по (5); заезды на тёмную скалу с маркером; кадр камеры робота с распознаванием маркера; столкновение — вспышка и тряска |

**Измерения — только моделью.** Ядро трассирует луч и даёт истинную пару $(R, \rho)$; модель `lab/model.js` решает, будет ли точка истинной, ложной или пропадёт. Туман на экране и в камере робота переведён на точный закон $e^{-\alpha d}$ (в three.js по умолчанию — $e^{-(\alpha d)^2}$), поэтому изображение подчиняется закону Кошмидера с тем же $\alpha$, что у лидара.

**Звёзды и оценка.** За миссию до трёх звёзд: расчёт без лишних ошибок (в миссии 4 — отличный фильтр), достигнутая цель опыта, верный ответ на контрольный вопрос. Звёзды — игровая мотивация. Предварительная оценка программы — до 3 баллов: расчёт, полный протокол, совпадение расчёта и опыта; четвёртый балл — выводы и защита у преподавателя (индивидуальный вопрос варианта показывается на экране итогов).

**Оформление.** Светлая и тёмная темы — из общего стиля `../shared/` (переключатель на титуле, в кампании и на панели миссии; выбор общий для всех страниц лаборатории). В светлой теме панели — светлое стекло над сценой, графики теории перекрашиваются под тему.

**Отчёт.** Самостоятельная HTML-страница (формулы — MathML) и JSON: ответы и попытки, журнал опытов, код фильтра, ответы на вопросы, выводы студента, эталонные значения. Прогресс хранится в браузере: обновление страницы работу не теряет.

## Лабораторная: запуск на сервере

Страница рассчитана на веб-сервер (VPS кафедры). Исходники (`lab/`, `../../engine/`) студенту не нужны — достаточно `index.html`, `lab.css`, `lab.bundle.js` и общего стиля `../../shared/`.

- **Python.** Pyodide 0.27.7 с NumPy загружается в фоне во время миссий 1–3, около 15 МБ. По умолчанию — с CDN jsDelivr. Чтобы не зависеть от внешней сети, скачайте полный выпуск Pyodide 0.27.7 на сервер и укажите адрес в `index.html`: `window.VP03_CONFIG = { pyodideUrl: '/pyodide/0.27.7/' }`. Без Python недоступна только миссия 4.
- **Отчёты на сервер.** Если указать `submitUrl`, на экране итогов появится кнопка «Отправить преподавателю»: отчёт JSON уходит методом POST. Без неё студент скачивает HTML и JSON.
- **Кэш.** При обновлении сборки сбрасывайте кэш (`Cache-Control: no-cache` для `lab.bundle.js` и `lab.css` или версия в имени файла).

## Лабораторная: проверка 23.10.2026

- **Модель:** `node --test lab/model.test.mjs` — 21 тест, все проходят: формулы (1)–(5), деление пополам против функции Ламберта (включая $\alpha R_{\max} > 1$), метод Монте-Карло для $p(R)$ на 200 000 лучей, корень (5), равная трудность 15 вариантов.
- **Сквозной прогон** в Chrome 152 (Apple M1 Pro, видеокарта, окно 1440 × 900) сценарием, который проходит кампанию с эталонными ответами и эталонным фильтром. Варианты 7 (снег) и 2 (дождь): все пять миссий пройдены на три звезды, предварительная оценка 3 из 3, ошибок на странице нет, 58–60 кадров/с, загрузка 1,7–2,4 с.

| Опыт | Вариант 7 | Вариант 2 |
|---|---|---|
| Шум дальности, см (паспорт) | 2,0 (2,0) | 3,1 (3,0) |
| Тёмная мишень пропала в ясную погоду, м (расчёт $R_{\mathrm c}$) | 31,7 (31,8) | 35,7 (35,8) |
| $R_{\max}$ в тумане, м: тёмная / светлая (расчёт) | 15,0 / 28,0 (15,0 / 28,1) при $V$ = 60 м; 7,4 / 11,6 (7,3 / 11,5) при 15 м | 19,8 / 35,9 (19,8 / 36,0) при $V$ = 100 м; 7,7 / 11,3 (7,7 / 11,2) при 15 м |
| Доля ложных точек на 4 и 20 м (3 и 15 м) при сильных осадках: опыт (расчёт) | 0,78 / 0,96 (0,75 / 0,96) | 0,33 / 0,46 (0,30 / 0,45) |
| Эталонный фильтр: удалено ложных / потеряно истинных | 100 % / 0 % | 100 % / 0 % |
| Обнаружение скалы лидаром, м (расчёт) | 9,3 (9,8) | 11,1 (11,4) |
| Маркер распознан камерой, м (расчёт) | 17,3 (17,3) | 13,7 (13,7) |
| Заезд на 1,5 $v_{\mathrm{safe}}$ / 0,97 $v_{\mathrm{safe}}$ | столкновение / остановка за 0,36 м | столкновение / остановка за 0,86 м |

Найдено и исправлено при проверке: обломки на полосе опыта в городе закрывали мишени (миры получили «чистые коридоры»); дальность потери мишени записывалась по положению робота в конце оборота — теперь это наибольшая дальность, измеренная самим лидаром; первые обороты после переноса робота содержали лучи из старого положения.

**Не проверено:** учебные компьютеры кафедры (есть [проверка компьютера](../../stands/scenes3d/README.md#bench) на стенде «Сцены 3D»), Firefox и Safari, работа с собственной копией Pyodide на VPS, открытие страницы файлом без сервера. Звуков в игре нет.

## Файлы лабораторной

| Файл | Назначение |
|---|---|
| `index.html`, `lab.css` | Страница: сцена, игровой интерфейс, экраны загрузки, титула, кампании и итогов; настройки сервера |
| `lab/game.js` | Точка входа: загрузка, кампания, ход миссии, приборы, журнал, справочник, прогресс, итоги и оценка |
| `lab/missions.js` | Пять миссий: миры, полосы опытов, брифинги, теория с графиками и 3D-демонстрациями, расчёт, сценарии заездов, разборы, контрольные вопросы; справочник |
| `lab/model.js` | Модель среды и датчиков без графики: формулы (1)–(5), деление пополам, функция Ламберта, луч лидара с погодой, 15 вариантов, эталонные ответы, метрики |
| `lab/model.test.mjs` | Тесты модели (`node --test`) |
| `lab/weather.js` | Модель погоды на каждом луче лидара; точный закон тумана в шейдерах |
| `lab/props.js` | Мишени, скала с маркером, луч-импульс, тормозной путь, повтор облака точек |
| `lab/charts.js` | Графики на canvas |
| `lab/py.js` | Python (Pyodide с NumPy) в фоновом потоке, шаблон `filter_points`, ограничение времени |
| `lab/math.js` | Перевод LaTeX → MathML, формулы занятия, числа с десятичной запятой |
| `lab/report.js` | Отчёт студента в HTML |
| `lab.bundle.js` | Собранный скрипт: `lab/game.js` с общим ядром стенда «Сцены 3D» (`engine.js`, миры), three.js 0.186.1 и three-mesh-bvh 0.9.16 |

## Сборка лабораторной

Из корня репозитория — `npm run build`. Лабораторная использует общее 3D-ядро `../../engine/` (`engine.js`, миры `polar`, `rescue`, `mars`); после его изменения сборка пересобирает и стенды, и лабораторную.
