New feature! Added Elo rating system!
This commit is contained in:
parent
ca9ec58dd3
commit
13ddb3b25b
7 changed files with 123 additions and 20 deletions
|
@ -1,6 +1,7 @@
|
|||
# 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!
|
||||
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:
|
||||
|
||||
|
@ -99,4 +100,5 @@ Within Python Virtual Environment:
|
|||
04.12.2020 - New feature! Now players can claim a draw.
|
||||
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! Added french language!
|
||||
19.12.2020 - New feature! Added french language!
|
||||
21.12.2020 - New feature! Added Elo rating system!
|
||||
|
|
|
@ -71,3 +71,4 @@ post_my_panel_str: panell (publica les estadístiques)
|
|||
locale_change_successfully: llengua canviada amb èxit a
|
||||
locale_not_changed: encara no és suportada :-(
|
||||
change_lang_str: conf ca (per a configurar el bot en català)
|
||||
panel_elo_rating_str: Elo
|
||||
|
|
|
@ -71,3 +71,4 @@ post_my_panel_str: panel (post player stats)
|
|||
locale_change_successfully: language sucessfully changed to
|
||||
locale_not_changed: is not supported yet :-(
|
||||
change_lang_str: conf en (to configure the bot in english)
|
||||
panel_elo_rating_str: Elo
|
||||
|
|
|
@ -71,3 +71,4 @@ post_my_panel_str: panel (publica el panel de datos)
|
|||
locale_change_successfully: idioma cambiado con éxito a
|
||||
locale_not_changed: no es soportado aún :-(
|
||||
change_lang_str: conf es (para configurar el bot en castellano)
|
||||
panel_elo_rating_str: Elo
|
||||
|
|
|
@ -71,3 +71,4 @@ post_my_panel_str: panneau (publie les statistiques)
|
|||
locale_change_successfully: langue modifiée avec succès en
|
||||
locale_not_changed: n'est pas encore pris en charge :-(
|
||||
change_lang_str: conf fr (pour configurer le bot en français)
|
||||
panel_elo_rating_str: Elo
|
||||
|
|
|
@ -169,7 +169,7 @@ if __name__ == '__main__':
|
|||
create_table(db, db_user, table, sql)
|
||||
|
||||
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)
|
||||
|
||||
############################################################
|
||||
|
|
133
mastochess.py
133
mastochess.py
|
@ -20,7 +20,7 @@ import chess.svg
|
|||
from cairosvg import svg2png
|
||||
import chess.pgn
|
||||
from PIL import Image, ImageFont, ImageDraw
|
||||
import lichess.api
|
||||
import math
|
||||
|
||||
def cleanhtml(raw_html):
|
||||
cleanr = re.compile('<.*?>')
|
||||
|
@ -31,7 +31,48 @@ def unescape(s):
|
|||
s = s.replace("'", "'")
|
||||
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:
|
||||
|
||||
|
@ -77,10 +118,12 @@ def create_panel(username, played_games, wins):
|
|||
panel_games_str = get_locale("panel_games_str", player_lang)
|
||||
panel_wins_str = get_locale("panel_wins_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+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+220), panel_ratio_str + ': ' + str(ratio) + '%', font=fnt, fill=(255,255,255,220))
|
||||
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+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+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)
|
||||
|
||||
|
@ -978,6 +1021,8 @@ def claim_draw(username):
|
|||
|
||||
def close_game(username, checkmate):
|
||||
|
||||
d = 0
|
||||
|
||||
try:
|
||||
|
||||
conn = None
|
||||
|
@ -996,6 +1041,30 @@ def close_game(username, checkmate):
|
|||
|
||||
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()
|
||||
|
||||
except (Exception, psycopg2.DatabaseError) as error:
|
||||
|
@ -1028,16 +1097,28 @@ def close_game(username, checkmate):
|
|||
|
||||
winner = username
|
||||
|
||||
if winner == white_player:
|
||||
|
||||
d = 1
|
||||
|
||||
else:
|
||||
|
||||
if query_word == search_end and username == white_user and stalemate == False:
|
||||
|
||||
winner = black_user
|
||||
|
||||
d = 2
|
||||
|
||||
elif query_word == search_end and username == black_user and stalemate == False:
|
||||
|
||||
winner = white_user
|
||||
|
||||
d = 1
|
||||
|
||||
K = 30
|
||||
|
||||
new_white_rating, new_black_rating = EloRating(white_rating, black_rating, K, d)
|
||||
|
||||
try:
|
||||
|
||||
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 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()
|
||||
|
||||
cur.close()
|
||||
|
@ -1094,9 +1179,21 @@ def get_stats(player):
|
|||
|
||||
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()
|
||||
|
||||
return (played_games, wins)
|
||||
return (rating, played_games, wins)
|
||||
|
||||
except (Exception, psycopg2.DatabaseError) as error:
|
||||
|
||||
|
@ -1745,9 +1842,9 @@ if __name__ == '__main__':
|
|||
|
||||
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
|
||||
|
||||
|
@ -1969,11 +2066,11 @@ if __name__ == '__main__':
|
|||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -1981,7 +2078,7 @@ if __name__ == '__main__':
|
|||
|
||||
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)
|
||||
|
||||
|
@ -1989,7 +2086,7 @@ if __name__ == '__main__':
|
|||
|
||||
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:
|
||||
|
||||
|
@ -1999,11 +2096,11 @@ if __name__ == '__main__':
|
|||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
||||
|
@ -2258,7 +2355,7 @@ if __name__ == '__main__':
|
|||
|
||||
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"
|
||||
|
||||
|
@ -2274,7 +2371,7 @@ if __name__ == '__main__':
|
|||
|
||||
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"
|
||||
|
||||
|
@ -2288,9 +2385,9 @@ if __name__ == '__main__':
|
|||
|
||||
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
|
||||
|
||||
|
|
Loading…
Reference in a new issue