- А кто из нас лучше всех играет в настольный футбол?
- С кем бы мне сейчас пойти поиграть?
- Кого надо уволить, потому что он не работает а только играет?
Наш опыт решения данных вопросов с помощью системы рейтинга Elo будет рассмотрен в статье. А также ссылка на репозиторий и на сайт будут разбросаны по статье.
Когда компания маленькая, а игроков еще меньше, то вопрос лучшего решается простым проведением турнира в пятницу вечером раз в пару месяцев. <совет>Шикарнейший повод выпить за счет компании.</совет>(Мы по неопытности это не сразу поняли. И сначала просто так играли.) Но компания растет, лига тоже увеличивается, и вот уже отыграть турнир, даже с учетом предварительного разбиения на группы, становится очень сложно. Это просто физически тяжело на большом футбольном столе провести 15 партий за вечер.
На данном этапе опытные
Про Elo
Разработал систему американский профессор физики и шахматист Арпад Эло.
Каждый новый игрок обычно получает рейтинг 1400. На самом деле не принципиально сколько. По итогам каждого матча часть рейтинга переходит от одного игрока к другому. И чтобы не уходить в минус берется изначально с запасом.
Будем считать, что игрок A в случае выигрыша получает 1 очко, в случае поражения — 0, а при ничьей — 0.5. Назовем эту переменную Sa.
Введем ожидаемое количество очков(Ea), которое игрок A получит за игру:
Ea = 1 / (1 + 10^((Rb-Ra)/400))
где Rb и Ra — это текущий рейтинг игроков B и A соответственно. Ea принадлежит интервалу (0, 1).
Коэффициенты подобраны таким образом, чтобы при разнице в рейтинге в 200 пунктов, ожидаемое количество очков равнялось приблизительно 0.75. Новый рейтинг игрока A считаем по формуле:
Ra’ = Ra + K * (Sa — Ea)
где K — коэффициент. Это максимальное количество пунктов рейтинга, который игрок может получить/потерять за одну игру. Обычно равняется 16. В ФИДЕ зависит от уровня игроков и варьируется от 10 до 30.
Аналогично считается рейтинг второго игрока Rb'.
Очевидно, что Ea + Eb = 1, Sa + Sb = 1 и следовательно Ra’ — Ra + Rb’ — Rb = 0, то есть у нас игра с нулевой суммой. Из формул видно, что сильный игрок за победу над слабым игроком получает меньше рейтинга, чем если слабый выиграет у сильного.
Мы рейтингом пользуемся уже около года. Отыграли более тысячи матчей. По моему субъективному мнению рейтинг отображает достаточно точно расстановку игроков в текущий момент времени. Как только кто-то в компании начинает играть лучше, например освоив удар, в течение недели занимает соответствующее место в рейтинге.
Также не проблема, если неделю или две не заносили результаты. При возобновлении рейтинг быстро восстанавливается.
После введения рейтинга сильно изменилось поведение во время игры. Матчи стали зрелищней. Если раньше, пропустив пару мячей в начале, проще было уже слить этот матч и начать новый, то теперь есть стимул биться до конца, чтобы не потерять (или не подарить сопернику) очки рейтинга! Автор статьи недавно проигрывал 1:6. А выиграл 7:6. Это был жаркий матч.
Естественно, когда мы решили попробовать рейтинг, первым делом поискали готовые реализации. И хотя многие онлайн игры используют Elo, не нашли ничего толкового, где бы мы могли просто заносить результаты наших игр. Поэтому в пятницу вечером был накидан google-скрипт для google-доков.
Пол года назад захотелось посмотреть на Asp.Net Core в действии(тогда RC1 был). И объективно google-скрипта уже давно не хватало. А там как раз выходные были. В итоге появилась система рейтинга, которой мы успешно пользуемся до сих пор. Нам нравится. Мне точно, а остальные может боятся сознаться, что нет.
Я думаю будет правильным поделиться со всеми. Исходники доступны здесь.
Получилось что-то явно большее чем просто MVP. В том числе сейчас реализовано:
- Подсчет рейтинга Elo;
- Дополнительная статистика: соотношение побед, забито/пропущено, победы и поражения подряд;
- Подсчет очков получаемых/теряемых в случае победы/поражения при игре с конкретным игроком в следующем матче. Надо же как-то планировать с кем лучше сейчас играть;
- Импорт результатов матчей из csv. Это мы с google-скриптов переезжали;
- Аутентификация с поддержкой OAuth. Пока только google, так как нам хватает. Но добавить еще какую систему несложно;
- Упрощенная система прав доступа. Существует админ лиги с возможностью управлять лигой и просто игроки;
- Приглашение новых пользователей. С уведомлением по емеил;
- Раздельные лиги. Каждый пользователь может создать свою приватную лигу, которая будет видна только игрокам лиги;
- Поддержка двух языков: английского и русского. У меня давнишние счеты с локализацией приложений. И сильно хотелось посмотреть как это реализовано в Asp.Net Core;
- Адаптивный дизайн. Ничего сверх естественного. Просто Bootstrap. Чтобы удобно было заносить результаты с телефона;
- Должно работать с выключенным JavaScript. Удобнее конечно с включенным. Но так как было желание посмотреть на некоторые фичи именно MVC, то получилось многостраничное приложение.
Во время разработки для хостинга я использовал Azure. Будучи уверенным, что потом спокойно перееду на какой-нибудь хостинг. Так уж и быть, даже оплачу его. И попытался переехать… Даже был морально готов заплатить баксов 50 в год за самый скромный вариант. Но когда я провозился сначала день с миграцией базы, а потом еще и не завелся проект, потому что хостер не очень-то готов к Asp.Net Core, вынужден был остаться на Azure. Но ценник там большой. А с другой стороны есть с чем сравнивать, Azure значительно удобнее.
Вспомнилась реклама на Хабре про хостинг Azure для стартапов. Почитал условия. Написал жалобное письмо на указанный емеил. И проект добавили в программу поддержки стартапов. Надеюсь, после статьи не исключат. Хотя я считаю, что проект всем требованиям удовлетворяет. В итоге, вопрос с хостингом теперь решен на 3 года! Так что если кто не хочет разворачивать проект локально, присоединяйтесь к нам, создавайте свою лигу. Экспериментально было установлено, что название не очень запоминающееся. Поэтому мы общим голосованием решили использовать learningstreet.ru.
Теоретически, если у кого есть идеи доменных имен подходящих для сайта, можно прикрутить. У меня как раз есть бонусы у одного из хостеров.
Ах да, чуть не забыл. Кого надо уволить? Судя по всему меня:
Комментарии (25)
ZOXEXIVO
02.09.2016 09:34+1За теорию, спасибо конечно, но код…
Логика в контроллерах, станная структура проекта и можно продолжать дальше, если, конечно, вашей целью не было накидать небольшой прототип.
Про Unit тесты сто раз уже говорили, что вы фактически тестирутете функционал EntityFramework, у которой есть свои юнит-тесты.
Или вы ей не доверяете?JacobL
02.09.2016 09:49Я очень положительно отношусь к критике. Постараюсь использовать ее, чтобы стать лучше как специалист. Поэтому не могли бы вы более подробно расписать ваши претензии с объяснениями, чем это плохо? А то сейчас вы как-то необоснованно набросили. Спасибо :)
Про Unit тесты сто раз уже говорили, что вы фактически тестирутете функционал EntityFramework, у которой есть свои юнит-тесты.
1) Мне кажется вы невнимательно читали. Иначе бы у вас были более серьезные претензии ;)
2) Конкретно где там в юнит тестах тестируется EF
zelenin
02.09.2016 09:45попробуйте параллельно внедрить glicko2 как эволюцию эло и первого глико.
Система отличается добавлением двух параметров — отклонением рейтинга и его волатильностью, за счет чего: а) мы можем сказать насколько рейтинг игрока реален на текущий момент (очевидно, что рейтинг игрока, сыгравшего менее 5 матчей еще не стабилизирован и не доверителен), б) рейтинг игрока намного быстрее стабилизируется, чем рейтинг по эло.JacobL
02.09.2016 09:53Мы пробовали glicko2. Не понравилось. Мне кажется, что в glicko2 очень важно, чтобы игроки играли примерно одинаковое количество матчей. Нам тяжело этого достичь.
zelenin
02.09.2016 10:12как раз наоборот. глико менее важно кол-во матчей, чем эло. плюс он практически не подвержен такому https://habrahabr.ru/post/308920/#comment_9784950 чем меньше матчей сыграл игрок, тем сильнее будет колбасить его рейтинг, и тем быстрее он найдет именно свой рейтинг. Соответственно соперники получают разное кол-во баллов за игру (сумма не равна 0), что опять же более справедливо — по-разному оценивать соперников. В эло в расчет принимается только сила соперника (по факту разница в рейтингах), в глико же кол-во матчей с начала «карьеры» и стабильность. Если эло-игроку понадобиться матчей 10, чтобы добраться с 1400 (как я понял, ваш дефолт) до своих 2000 очков, на которых его рейтинг стабилизируется, то глико-игроку понадобиться матча 3. (цифры условные, примерные, следующие из многолетнего опыта увлечения подобными рейтингами).
PatientZero
02.09.2016 09:47Кому-то удалось забраться на пятое место, достойно проиграв (со счётом 3:7) всего в одном матче, забавно.
JacobL
02.09.2016 09:55А вы внимательный :) Есть такой маленький недостаток у эло. Если игрок сыграл мало матчей, то он будет очень близок к стандартному рейтингу 1400. И его положение необоснованно. Теоретически можно прятать игроков, отыгравших мало матчей.
zelenin
02.09.2016 10:17на самом деле это не маленький недостаток, а достаточно большой. Рейтингов существует очень много, и они все показывают похожую точность (на достаточной базе). Вся соль именно в «тюнингах» — как быстро рейтинг будет реагировать на сторонние обстоятельства (точный рейтинг со старта, временная инфляция, другие уточняющие показатели). Эло был одним из первых рейтингов, основанных не на фиксированных очках, и оттого самым «дубовым», хоть и на голову выше традиционных очковых рейтингов.
codeschemer
02.09.2016 09:55Подсчет очков получаемых/теряемых в случае победы/поражения при игре с конкретным игроком в следующем матче. Надо же как-то планировать с кем лучше сейчас играть;
Как лучше организовать вычисление шансов для каждого соперника, с учетом последних результатов. Чтобы при прочих равных играть с тем, против кого 000111, а не тем, против кого 111000? И потом шанс соотнести с получаемыми очками, для того чтобы получился ранкинг пригодный для накопления Эло. Есть идеи/решения?JacobL
02.09.2016 11:04Надеюсь, я правильно понял ваш вопрос.
На самом деле, каждый игрок интуитивно оценивает вероятность победы над конкретным игроком в данный момент времени. И может посмотреть сколько он очков получит/потеряет в случае победы/поражения и на основе этого принять решение.
Интуитивное представление можно вполне формализовать. Посчитав, например, количество побед/поражений за последние матчей 10. И на основе этого посчитать мат ожидание получаемых очков.
keenz
02.09.2016 10:02А когда 2х2 играете, как идет подсчет рейтинга для каждого игрока?
JacobL
02.09.2016 10:34Сейчас рейтинг для двух не считаем. Раньше пробовали считать для команд. Но есть проблема, что команд получается очень много. Фактически, комбинация всех возможных вариантов 2х игроков из компании. То есть для маленькой компании еще ок, но как начинается рост количества игроков, то уже совсем неинтересно. И я согласен, что надо пытаться вводить рейтинг для каждого командного игрока, но удачного ничего придумать не получилось
PetrovSerega
02.09.2016 11:12а при ничьей — 0.5.
По Вашим правилам ничья возможна?JacobL
02.09.2016 11:15По нашим — нет. Но система вполне допускает, что будут заноситься матчи с результатом — ничья. Вдруг, кто играет по времени, а не до конкретного счета.
Sing
02.09.2016 11:23+1Мы используем рейтинг Эло для подсчёта индивидуальных рейтингов игроков в реальном футболе (который бегать-мяч-поле-команда). Используем модификацию для футбола https://ru.wikipedia.org/wiki/Футбольный_рейтинг_Эло. В ней учитывается разница мячей, так что игра идёт не только за победу, но и буквально за каждый мяч.
qadmium
02.09.2016 11:56забавно, как раз 2 года назад на ASP.NET MVC написали прилагу с рейтингом эло для кикера. Я аж сначала подумал, что кто-то из наших запостил, настолько похоже ))
LoadRunner
А подробнее про правила, по которым идёт игра? Длительность матча? Забавные истории?
JacobL
Для рейтинга важно лишь чтобы была возможно определить кто победил или ничью. Мы играем до 7 голов. Но можно играть и по времени. А вообще мы стараемся придерживаться вот этих правил — http://rbk.moy.su/rules/short-rules.pdf
И рейтинг, кстати, необязательно использовать для футбола. Отлично подойдут любые игры для двух: теннис, го.
Про забавные истории я подумаю :)
LoadRunner
И сколько же в итоге длится матч в среднем?
Не пробовали анализировать матчи разных игроков с одинаковым счётом по длительности? У кого сколько времени уходит на забитие гола? Понимаю, что это всё ситуационно, но может есть какая-то корреляция с уровнем игрока?
JacobL
Глубокого анализа мы не делали. Хотя переодически возникает такое желание. Опишу свои ощущения по времени игры.
Матч в среднем 5-10 минут. Но если столкнутся два сильных игрока, играющих от обороны, и в воинственном настроении, то можно дотянуть до 15-20. Скорее всего время матча коррелирует со стилем игры. На превью, кстати, фотография нашего стола. И там видно, что игроки широкие. В результате, с первой линии в ворота забить непросто, потому что вратарь и защитники очень хорошо закрывают ворота. Нужно делать какую-нибудь комбинацию, разыгрывать мяч на первой линии, чтобы обмануть соперника. Либо очень популярно рандомом от борта из своей обороны.
Мы еще практикуем играть двое на двое. Тогда один игрок встает только на защиту, второй только на нападение. И такие матчи переваливали у сильных игроков за пол часа. И это было больше испытание на износ. Потому что слегка наклонившись(большинство парней высокие) простоять пол часа — физически сложно.
LoadRunner
JacobL
На второй турнир я принес бутылку вискаря со словами «мне трезвые соперники не нужны». Но не прокатило. У нас к турнирам очень серьезно относятся и на такой слабый развод не ведутся. Разве что слегка снять напряжение. Кстати, да, во время турнира очень сильно меняется поведение. Из-за переживаний тяжело делать что-то натренированное и сводится все к удару посильнее. Алкоголь скорее после турнира или для зрителей.
Еще очень популярен способ выигрыша — вывести соперника из себя подколами, поддевками. Так что игра тренирует еще и стойкость к язвительным комментариям.
saboteur_kiev
«Для рейтинга важно лишь чтобы была возможно определить кто победил или ничью.»
то есть 7:0 и 7:6 — это одинаково влияет на рейтинг? IMHO не совсем верно…
JacobL
Ниже предложили модификацию — https://habrahabr.ru/post/308920/#comment_9785216. И она мне нравится