Elo for ping pong
ELO_DEFAULT = 1500 | |
ELO_K_FACTOR = 16 | |
def expected(Ra, Rb): | |
# https://en.wikipedia.org/wiki/Elo_rating_system | |
Ea = (1.0 / (1.0 + pow(10.0, (Rb-Ra)/400.0))) | |
return Ea, 1-Ea | |
@bot.add_command('!challenge') | |
@gen.coroutine | |
def challenge(message): | |
"""Creates an interactive prompt, and keeps track of scores. | |
This function uses the Elo method of keeping track of ranks. | |
Every participant starts with 1500 and the "k" factor of 16""" | |
Ua = bot._get_user(message.user) | |
ratings = yield bot.memory.get('pong-elo-ratings', {}) | |
Ra = ratings.get(Ua.id) | |
if Ra is None: | |
Ra = yield bot.memory.get('%s-rating' % Ua.id, ELO_DEFAULT) | |
action = yield message.button_prompt( | |
'Who <!here> would like to challenge {}? Rating: {}'.format(Ua.first_name, int(Ra)), | |
['Take on the challenge'] | |
) | |
event = action._meta['event'] | |
accepting_user_id = event.get('user', {}).get('id') | |
Ub = bot._get_user(accepting_user_id) | |
Rb = ratings.get(Ub.id) | |
if Rb is None: | |
Rb = yield bot.memory.get('%s-rating' % Ub.id, ELO_DEFAULT) | |
yield message.reply('{} ({}) takes on the challenge!'.format(Ub.first_name, int(Rb))) | |
yield message.reply('{} vs. {}'.format(Ua.first_name, Ub.first_name)) | |
winner = yield message.button_prompt( | |
'Who won?', [ | |
'{}'.format(Ua.first_name), | |
'{}'.format(Ub.first_name), | |
'Draw', | |
'Cancel'] | |
) | |
if winner == 'Cancel': | |
yield message.reply('Too bad ... :(') | |
raise gen.Return() | |
if winner == 'Draw': | |
Sa, Sb = 0.5, 0.5 | |
elif winner == Ua.first_name: | |
Sa, Sb = 1, 0 | |
elif winner == Ub.first_name: | |
Sa, Sb = 0, 1 | |
else: | |
yield message.reply(('Got some strange button value "{}"...' | |
'ignoring this game').format(winner)) | |
raise gen.Return() | |
Ea, Eb = expected(Ra, Rb) | |
Ra = Ra + ELO_K_FACTOR * (Sa - Ea) | |
Rb = Rb + ELO_K_FACTOR * (Sb - Eb) | |
ratings[Ua.id] = Ra | |
ratings[Ub.id] = Rb | |
yield bot.memory.save('pong-elo-ratings', ratings) | |
yield message.reply('New Ratings:') | |
yield message.reply('{}: {}'.format(Ua.first_name, int(Ra))) | |
yield message.reply('{}: {}'.format(Ub.first_name, int(Rb))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment