New feature! Added Elo rating system!
This commit is contained in:
pare
ca9ec58dd3
commit
13ddb3b25b
S'han modificat 7 arxius amb 123 adicions i 20 eliminacions
|
@ -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!
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
|
|
133
mastochess.py
133
mastochess.py
|
@ -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("'", "'")
|
s = s.replace("'", "'")
|
||||||
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
|
||||||
|
|
||||||
|
|
Loading…
Referencia en una nova incidència