Готовьтесь, будет лонгрид...
Недавно, на прошедших офлайн тестах нашего приложения, меня в очередной раз спросили: "А что будет, если время ответа у двух или более пользователей будет одинаковым?".
Во время разработки MVP было достаточно считать до тысячных, т.к. больше 10 участников за раз у нас не было, что сводило вероятность корреляции к 5-10% при общем времени на ответ в 30сек, но чем ближе к релизу, тем больше этот вопрос меня триггерил, т.к. точность времени ответа пользователя является максимально важным фактором при распределении мест.
К вопросу я подошел основательно, хотел один раз сделать и больше никогда не возвращаться к этой задаче.
Проблемы, которые я пытался решить:
- Ограниченная точность — миллисекунды дают всего 1000 возможных значений в 30-секундном окне.
- Шанс совпадения времени растет с числом участников:
- При 10 игроках – 5-10%
- При 20 игроках – 40-50%
- При 30 игроках – 75-80%
- При 40+ игроках – почти 100%
-
Таймер на фронте не идеален — performance.now() работает с точностью до микросекунд, но его точность зависит от кадровой частоты экрана (requestAnimationFrame). Например, при 60 Гц возможные значения прыгают с шагом 16.67 мс.
-
Корреляция во времени ответа — игроки нажимают с похожей скоростью, так как у всех одинаковый UI, анимации и реакция человека имеет биологические ограничения (обычно 200-300 мс).
Можно, конечно, сделать по простому: увеличить точность до 4 (или больше) знаков после запятой (десятитысячные). Это дало бы 10 000 возможных значений и уменьшило вероятность совпадений, но не устранило проблему полностью. Ведь если у нас 100 игроков, а всего 10 000 возможных значений, вероятность совпадения все еще достаточно велика и резко растет с числом пользователей.
Типичные практики в данном случае - увеличение точности до микросекунд (0,000001), тогда вероятность корреляции для 100 игроков уменьшится до 0.0167%, при 1000 - 1.65%, не нравится)
Я начал копать и случайно наткнулся на аттофизику и технику измерения времени в аттосекундах.
Что такое аттосекунда?
Аттосекунда (ас) — это 10⁻¹⁸ секунды. Это настолько малый промежуток времени, что свет за аттосекунду проходит всего лишь расстояние, меньшее атома водорода. Если миллисекунды – это вечность по сравнению с реакцией человека, то аттосекунды – это уровень квантовой механики.
Что же я решил сделать?)
Решил использовать то, что изначально предназначено для изучения явлений взаимодействия света и материи и реализовать аналогичную механику на python (зачем? ну хайп же 😁):
Вместо фиксированной точности добавил случайное смещение внутри миллисекунды при обработке времени ответа.
Ввел виртуальную "аттосекунду" — число после запятой, которое математически моделирует субмиллисекундную точность, но без необходимости реально измерять такие времена.
Это позволяет в случае совпадений разруливать ситуацию максимально честно, не добавляя обычный рандом, а используя структурированный алгоритм.
Таким образом, мы получили систему, где вероятность одинакового времени стала почти нулевой, но при этом всё выглядит естественно и справедливо для пользователей.
Задачу можно закрывать, добавление виртуальных аттосекунд делает совпадения математически невозможными.
Да, кто - то скажет, ты просто добавил 18 знаков после запятой, а я скажу - нет, это аттосекундная техника измерения времени 😎!