New feature! Added Elo rating system!

This commit is contained in:
spla 2020-12-21 10:23:04 +01:00
pare ca9ec58dd3
commit 13ddb3b25b
S'han modificat 7 arxius amb 123 adicions i 20 eliminacions

Veure arxiu

@ -1,6 +1,7 @@
# Mastodon Chess # Mastodon Chess
Play with other fediverse users a Chess game! Mastodon Chess control games, players and boards and even it post, graphically, every move to both players! Play with other fediverse users a Chess game! Mastodon Chess control games, players and boards and even it post, graphically, every move to both players!
Mastodon Chess (mastochess) uses [python-chess](https://python-chess.readthedocs.io/en/latest/) library. Mastodon Chess (mastochess) uses [python-chess](https://python-chess.readthedocs.io/en/latest/) library.
Mastodon Chess uses Elo rating system to calculate the relative skill levels of fediverse players!
### How to play: ### How to play:
@ -99,4 +100,5 @@ Within Python Virtual Environment:
04.12.2020 - New feature! Now players can claim a draw. 04.12.2020 - New feature! Now players can claim a draw.
05.12.2020 - New feature! Add panel stats. 05.12.2020 - New feature! Add panel stats.
19.12.2020 - New feature! Now you can configure bot's language! 19.12.2020 - New feature! Now you can configure bot's language!
19.12.2020 - New feature! Added french language! 19.12.2020 - New feature! Added french language!
21.12.2020 - New feature! Added Elo rating system!

Veure arxiu

@ -71,3 +71,4 @@ post_my_panel_str: panell (publica les estadístiques)
locale_change_successfully: llengua canviada amb èxit a locale_change_successfully: llengua canviada amb èxit a
locale_not_changed: encara no és suportada :-( locale_not_changed: encara no és suportada :-(
change_lang_str: conf ca (per a configurar el bot en català) change_lang_str: conf ca (per a configurar el bot en català)
panel_elo_rating_str: Elo

Veure arxiu

@ -71,3 +71,4 @@ post_my_panel_str: panel (post player stats)
locale_change_successfully: language sucessfully changed to locale_change_successfully: language sucessfully changed to
locale_not_changed: is not supported yet :-( locale_not_changed: is not supported yet :-(
change_lang_str: conf en (to configure the bot in english) change_lang_str: conf en (to configure the bot in english)
panel_elo_rating_str: Elo

Veure arxiu

@ -71,3 +71,4 @@ post_my_panel_str: panel (publica el panel de datos)
locale_change_successfully: idioma cambiado con éxito a locale_change_successfully: idioma cambiado con éxito a
locale_not_changed: no es soportado aún :-( locale_not_changed: no es soportado aún :-(
change_lang_str: conf es (para configurar el bot en castellano) change_lang_str: conf es (para configurar el bot en castellano)
panel_elo_rating_str: Elo

Veure arxiu

@ -71,3 +71,4 @@ post_my_panel_str: panneau (publie les statistiques)
locale_change_successfully: langue modifiée avec succès en locale_change_successfully: langue modifiée avec succès en
locale_not_changed: n'est pas encore pris en charge :-( locale_not_changed: n'est pas encore pris en charge :-(
change_lang_str: conf fr (pour configurer le bot en français) change_lang_str: conf fr (pour configurer le bot en français)
panel_elo_rating_str: Elo

Veure arxiu

@ -169,7 +169,7 @@ if __name__ == '__main__':
create_table(db, db_user, table, sql) create_table(db, db_user, table, sql)
table = "players" table = "players"
sql = "create table "+table+" (player_id bigint PRIMARY KEY, player_name varchar(40), lang varchar(2))" sql = "create table "+table+" (player_id bigint PRIMARY KEY, player_name varchar(40), lang varchar(2), elo_rating float)"
create_table(db, db_user, table, sql) create_table(db, db_user, table, sql)
############################################################ ############################################################

Veure arxiu

@ -20,7 +20,7 @@ import chess.svg
from cairosvg import svg2png from cairosvg import svg2png
import chess.pgn import chess.pgn
from PIL import Image, ImageFont, ImageDraw from PIL import Image, ImageFont, ImageDraw
import lichess.api import math
def cleanhtml(raw_html): def cleanhtml(raw_html):
cleanr = re.compile('<.*?>') cleanr = re.compile('<.*?>')
@ -31,7 +31,48 @@ def unescape(s):
s = s.replace("&apos;", "'") s = s.replace("&apos;", "'")
return s return s
def create_panel(username, played_games, wins): # Function to calculate the Probability
def Probability(rating1, rating2):
return 1.0 * 1.0 / (1 + 1.0 * math.pow(10, 1.0 * (rating1 - rating2) / 400))
# Function to calculate Elo rating
# K is a constant.
# d determines whether
# Player A wins or Player B.
def EloRating(Ra, Rb, K, d):
# To calculate the Winning
# Probability of Player B
Pb = Probability(Ra, Rb)
# To calculate the Winning
# Probability of Player A
Pa = Probability(Rb, Ra)
# Case -1 When Player A wins
# Updating the Elo Ratings
if (d == 1) :
Ra = Ra + K * (1 - Pa)
Rb = Rb + K * (0 - Pb)
# Case -2 When Player B wins
# Updating the Elo Ratings
else :
Ra = Ra + K * (0 - Pa)
Rb = Rb + K * (1 - Pb)
Ra = round(Ra, 6)
Rb = round(Rb, 6)
print("Updated Ratings:-")
print("Ra =", Ra," Rb =", Rb)
return(Ra, Rb)
# This code is contributed by
# Smitha Dinesh Semwal
def create_panel(username, rating, played_games, wins):
if played_games > 0 and wins > 0: if played_games > 0 and wins > 0:
@ -77,10 +118,12 @@ def create_panel(username, played_games, wins):
panel_games_str = get_locale("panel_games_str", player_lang) panel_games_str = get_locale("panel_games_str", player_lang)
panel_wins_str = get_locale("panel_wins_str", player_lang) panel_wins_str = get_locale("panel_wins_str", player_lang)
panel_ratio_str = get_locale("panel_ratio_str", player_lang) panel_ratio_str = get_locale("panel_ratio_str", player_lang)
panel_elo_rating_str = get_locale("panel_elo_rating_str", player_lang)
draw.text((y+70,x+120), panel_games_str + ': ' + str(played_games), font=fnt, fill=(255,255,255,220)) #fill=(255,255,255,255)) ## full opacity draw.text((y+70,x+80), panel_games_str + ': ' + str(played_games), font=fnt, fill=(255,255,255,220)) #fill=(255,255,255,255)) ## full opacity
draw.text((y+70,x+170), panel_wins_str + ': ' + str(wins), font=fnt, fill=(255,255,255,220)) #fill=(255,255,255,255)) ## full opacity draw.text((y+70,x+130), panel_wins_str + ': ' + str(wins), font=fnt, fill=(255,255,255,220)) #fill=(255,255,255,255)) ## full opacity
draw.text((y+70,x+220), panel_ratio_str + ': ' + str(ratio) + '%', font=fnt, fill=(255,255,255,220)) draw.text((y+70,x+180), panel_ratio_str + ': ' + str(ratio) + '%', font=fnt, fill=(255,255,255,220))
draw.text((y+70,x+230), panel_elo_rating_str + ': ' + str(round(rating)), font=fnt, fill=(255,255,255,220))
fnt = ImageFont.truetype('app/fonts/DroidSans.ttf', 15, layout_engine=ImageFont.LAYOUT_BASIC) fnt = ImageFont.truetype('app/fonts/DroidSans.ttf', 15, layout_engine=ImageFont.LAYOUT_BASIC)
@ -978,6 +1021,8 @@ def claim_draw(username):
def close_game(username, checkmate): def close_game(username, checkmate):
d = 0
try: try:
conn = None conn = None
@ -996,6 +1041,30 @@ def close_game(username, checkmate):
black_player = row[1] black_player = row[1]
cur.execute("select elo_rating from players where player_name = (%s)", (white_player,))
row = cur.fetchone()
if row[0] != None:
white_rating = row[0]
else:
white_rating = 1500
cur.execute("select elo_rating from players where player_name = (%s)", (black_player,))
row = cur.fetchone()
if row[0] != None:
black_rating = row[0]
else:
black_rating = 1500
cur.close() cur.close()
except (Exception, psycopg2.DatabaseError) as error: except (Exception, psycopg2.DatabaseError) as error:
@ -1028,16 +1097,28 @@ def close_game(username, checkmate):
winner = username winner = username
if winner == white_player:
d = 1
else: else:
if query_word == search_end and username == white_user and stalemate == False: if query_word == search_end and username == white_user and stalemate == False:
winner = black_user winner = black_user
d = 2
elif query_word == search_end and username == black_user and stalemate == False: elif query_word == search_end and username == black_user and stalemate == False:
winner = white_user winner = white_user
d = 1
K = 30
new_white_rating, new_black_rating = EloRating(white_rating, black_rating, K, d)
try: try:
conn = None conn = None
@ -1050,6 +1131,10 @@ def close_game(username, checkmate):
cur.execute("update stats set winner=(%s), finished=(%s), updated_at=(%s) where game_id=(%s)", (winner, finished, now, game_id)) cur.execute("update stats set winner=(%s), finished=(%s), updated_at=(%s) where game_id=(%s)", (winner, finished, now, game_id))
cur.execute("update players set elo_rating=(%s) where player_name=(%s)", (new_white_rating, white_user))
cur.execute("update players set elo_rating=(%s) where player_name=(%s)", (new_black_rating, black_user))
conn.commit() conn.commit()
cur.close() cur.close()
@ -1094,9 +1179,21 @@ def get_stats(player):
wins = row[0] wins = row[0]
cur.execute("select elo_rating from players where player_name = (%s)", (player,))
row = cur.fetchone()
if row[0] != None:
rating = row[0]
else:
rating = 1500
cur.close() cur.close()
return (played_games, wins) return (rating, played_games, wins)
except (Exception, psycopg2.DatabaseError) as error: except (Exception, psycopg2.DatabaseError) as error:
@ -1745,9 +1842,9 @@ if __name__ == '__main__':
elif query_word == search_panel: elif query_word == search_panel:
played_games, wins = get_stats(username) rating, played_games, wins = get_stats(username)
create_panel(username, played_games, wins) create_panel(username, rating, played_games, wins)
toot_text = '@'+username toot_text = '@'+username
@ -1969,11 +2066,11 @@ if __name__ == '__main__':
toot_text += '\n' + winned_games + "\n" toot_text += '\n' + winned_games + "\n"
played_games, wins = get_stats(username) rating, played_games, wins = get_stats(username)
wins_of_many = get_locale("wins_of_many", player_lang1) wins_of_many = get_locale("wins_of_many", player_lang1)
toot_text += username + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += username + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + ' (Elo: ' + str(round(rating)) + ')' + '\n'
player_lang2 = get_lang(playing_user) player_lang2 = get_lang(playing_user)
@ -1981,7 +2078,7 @@ if __name__ == '__main__':
toot_text += "\n@"+playing_user + ': ' + well_done + "\n" toot_text += "\n@"+playing_user + ': ' + well_done + "\n"
played_games, wins = get_stats(playing_user) rating, played_games, wins = get_stats(playing_user)
winned_games = get_locale("winned_games", player_lang2) winned_games = get_locale("winned_games", player_lang2)
@ -1989,7 +2086,7 @@ if __name__ == '__main__':
toot_text += '\n\n' + winned_games + "\n" toot_text += '\n\n' + winned_games + "\n"
toot_text += playing_user + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += playing_user + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + ' (Elo: ' + str(round(rating)) + ')' + '\n'
elif check == False and stalemate == True: elif check == False and stalemate == True:
@ -1999,11 +2096,11 @@ if __name__ == '__main__':
toot_text += '\n' + winned_games + "\n" toot_text += '\n' + winned_games + "\n"
played_games, wins = get_stats(username) rating, played_games, wins = get_stats(username)
toot_text += username + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += username + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n"
played_games, wins = get_stats(playing_user) rating, played_games, wins = get_stats(playing_user)
toot_text += playing_user + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += playing_user + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n"
@ -2258,7 +2355,7 @@ if __name__ == '__main__':
toot_text += '\n' + winned_games + "\n" toot_text += '\n' + winned_games + "\n"
played_games, wins = get_stats(white_player) rating, played_games, wins = get_stats(white_player)
toot_text += white_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += white_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n"
@ -2274,7 +2371,7 @@ if __name__ == '__main__':
toot_text += '\n' + winned_games + "\n" toot_text += '\n' + winned_games + "\n"
played_games, wins = get_stats(black_player) rating, played_games, wins = get_stats(black_player)
toot_text += black_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" toot_text += black_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n"
@ -2288,9 +2385,9 @@ if __name__ == '__main__':
elif query_word == search_panel: elif query_word == search_panel:
played_games, wins = get_stats(username) rating, played_games, wins = get_stats(username)
create_panel(username, played_games, wins) create_panel(username, rating, played_games, wins)
toot_text = '@'+username toot_text = '@'+username