diff --git a/README.md b/README.md index 8bc605d..e53fb93 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,31 @@ Mastodon Chess (mastochess) uses [python-chess](https://python-chess.readthedocs ### How to play: -To get help: +- To get help: @your_bot_username help -To start a game: +- To start a game: @your_bot_username new -To make a move: +- To make a move: @your_bot_username move e2e4 -To finish game at any time: +- To finish game at any time: @your_bot_username end -To list on going games: +- To list on going games: @your_bot_username games -To get any game anotations, in ex. game 1, in pgn format: +- To get any game anotations, in ex. game 1, in pgn format: @your_bot_username send 1 -To promote a pawn use first letter of desired piece: +- To promote a pawn use first letter of desired piece: @your_bot_username move g7g8r (if you want a rook) @@ -38,6 +38,12 @@ r = rook Don't use q for queen. Pawn is promoted to Queen by default. +- To claim a draw: + +@your_bot_username draw + +### Commands table + | ca | en | es | ex. | Observ. | |:-----:|:-----:|:--------:|:----:|:-----------:| | nova | new | nueva | | | @@ -45,6 +51,8 @@ Don't use q for queen. Pawn is promoted to Queen by default. | fi | end | fin | | | | jocs | games | partidas | | | | envia | send | envia | 1 | game number | +| taules| draw | tablas | | | +| ajuda | help | ayuda | | | ### Dependencies @@ -78,3 +86,4 @@ Within Python Virtual Environment: 28.11.2020 - New feature! Now any fediverse user can play Mastodon Chess! 28.11.2020 - New feature! Added help 03.12.2020 - New feature! Added pgn save & send support +04.12.2020 - New feature! Now players can claim a draw. diff --git a/app/locales/ca.txt b/app/locales/ca.txt index 4903d2e..5132615 100644 --- a/app/locales/ca.txt +++ b/app/locales/ca.txt @@ -4,6 +4,7 @@ search_new: nova search_games: jocs search_send: envia search_help: ajuda +search_draw: taules new_game_started: partida iniciada! Esperant jugador... playing_with: jugues amb your_turn: el teu torn @@ -52,7 +53,11 @@ start_or_join_a_new_game: nova (iniciar partida o unirse a una en espera) move_a_piece: mou e2e3 (per exemple) leave_a_game: fi (per a deixar la partida en qualsevol moment) list_games: jocs (mostra un llistat de partides actives) -get_a_game_anotation: envia 1 (1 és el número de la partida. Envia les anotacions de la partida per correu electrònic, només usuaris del servidor local) +get_a_game_anotation: envia 1 (1 és el número de la partida. Envia les anotacions per correu electrònic, en format pgn. Només usuaris locals.) show_help: ajuda (mostra aquesta ajuda i, per tant, és l'ajuda de l'ajuda) stalemate_str: taules! partida finalitzada. - +ask_for_draw: taules +claim_draw_str: ha proposat taules a +draw_and_str: i +agreed_draw_str: han acordat taules. +claim_a_draw: taules (per a proposar/acceptar taules) diff --git a/app/locales/en.txt b/app/locales/en.txt index a6c6af7..307835c 100644 --- a/app/locales/en.txt +++ b/app/locales/en.txt @@ -4,6 +4,7 @@ search_new: new search_games: games search_send: send search_help: help +search_draw: draw new_game_started: game started! Waiting for the second player... playing_with: you play with your_turn: it's your turn @@ -52,7 +53,11 @@ start_or_join_a_new_game: new (start a new game or join a waiting one) move_a_piece: move e2e3 (in ex.) leave_a_game: end (to leave the game any time) list_games: games (show an on going games list) -get_a_game_anotation: send 1 (1 is the game number. It send the game's anotations by email but local users only) +get_a_game_anotation: send 1 (1 is the game number. It send the game's anotations by email, pgn format. Local users only.) show_help: help (show this help so, it's the help of the help) stalemate_str: stalemate! game is over. - +ask_for_draw: draw +claim_draw_str: had claimed draw to +draw_and_str: and +agreed_draw_str: agreed draw. +claim_a_draw: draw (to claim/accept a draw) diff --git a/app/locales/es.txt b/app/locales/es.txt index 008c827..2d00b01 100644 --- a/app/locales/es.txt +++ b/app/locales/es.txt @@ -4,6 +4,7 @@ search_new: nueva search_games: partidas search_send: envia search_help: ayuda +search_draw: tablas new_game_started: partida iniciada! Esperando jugador... playing_with: juegas con your_turn: tu turno @@ -50,9 +51,13 @@ king_piece_letter: R email_subject: Anotaciones partida n. start_or_join_a_new_game: nueva (empezar una partida o unirse a una en espera) move_a_piece: mueve e2e3 (por ejemplo) -leave_a_game: fin (para dejar la partida en cualquier momento) +leave_a_game: fin (dejar la partida en cualquier momento) list_games: partidas (muestra un listado de partidas activas) -get_a_game_anotation: envia 1 (1 es el número de la partida. Envia las anotaciones de la partida pedida por correo electrónico pero sólo a usuarios del servidor local) +get_a_game_anotation: envia 1 (1 es el número de la partida. Envia las anotaciones por correo electrónico, en formato pgn. Sólo usuarios locales.) show_help: ayuda (muestra esta ayuda y, por tanto, es la ayuda de la ayuda) stalemate_str: Tablas! la partida ha terminado. - +ask_for_draw: tablas +claim_draw_str: ha propuesto tablas a +draw_and_str: y +agreed_draw_str: han acordado tablas. +claim_a_draw: tablas (para proponer/aceptar tablas) diff --git a/db-setup.py b/db-setup.py index f04524a..14a42d4 100644 --- a/db-setup.py +++ b/db-setup.py @@ -160,7 +160,7 @@ if __name__ == '__main__': table = "games" sql = "create table "+table+" (created_at timestamptz, game_id serial, white_user varchar(40), black_user varchar(40), chess_game varchar(200), " sql +=" chess_status varchar(12), waiting boolean, updated_at timestamptz, next_move varchar(40), last_move varchar(40), moves int, finished boolean default False, " - sql += "chess_link varchar(100), PRIMARY KEY(game_id))" + sql += "chess_link varchar(100), white_stalemate boolean default False, black_stalemate boolean default False, PRIMARY KEY(game_id))" create_table(db, db_user, table, sql) table = "stats" diff --git a/mastochess.py b/mastochess.py index 688a7b7..e8047f8 100644 --- a/mastochess.py +++ b/mastochess.py @@ -128,6 +128,8 @@ def get_piece_name(captured_piece): def get_notification_data(): + conn = None + try: account_id_lst = [] @@ -140,9 +142,7 @@ def get_notification_data(): url_lst = [] - search_text = [search_end, search_move, search_new, search_games, search_send, search_help] - - conn = None + search_text = [search_end, search_move, search_new, search_games, search_send, search_help, search_draw] conn = psycopg2.connect(database = mastodon_db, user = mastodon_db_user, password = "", host = "/var/run/postgresql", port = "5432") @@ -653,6 +653,73 @@ def send_anotation(game_id): return (emailed, game_id, game_found) +def claim_draw(username): + + try: + + conn = None + + conn = psycopg2.connect(database = chess_db, user = chess_db_user, password = "", host = "/var/run/postgresql", port = "5432") + + cur = conn.cursor() + + cur.execute("select white_user, black_user from games where game_id=(%s)", (game_id,)) + + row = cur.fetchone() + + if row != None: + + white_player = row[0] + + black_player = row[1] + + if white_player == username: + + toot_text = '@'+username + ' ' + claim_draw_str + ' @'+black_player + '\n' + + cur.execute("update games set white_stalemate = 't' where game_id=(%s)", (game_id,)) + + else: + + toot_text = '@'+username + ' ha proposat taules a ' + '@'+white_player + '\n' + + cur.execute("update games set black_stalemate = 't' where game_id=(%s)", (game_id,)) + + conn.commit() + + cur.execute("select white_stalemate, black_stalemate from games where game_id=(%s)", (game_id,)) + + row = cur.fetchone() + + if row != None: + + white_stalemate = row[0] + + black_stalemate = row[1] + + cur.close() + + if white_stalemate == True and black_stalemate == True: + + stalemate = True + + else: + + stalemate = False + + return (white_player, black_player, toot_text, stalemate) + + except (Exception, psycopg2.DatabaseError) as error: + + sys.exit(error) + + finally: + + if conn is not None: + + conn.close() + + def close_game(username, checkmate): try: @@ -963,7 +1030,7 @@ def next_move(playing_user): def toot_help(): - help_text = '@'+username + ' ' + search_help + ':\n' + help_text = '@'+username + '\n' help_text += '\n' help_text += '@'+bot_username + ' ' + start_or_join_a_new_game + '\n' help_text += '\n' @@ -975,7 +1042,7 @@ def toot_help(): help_text += '\n' help_text += '@'+bot_username + ' ' + get_a_game_anotation + '\n' help_text += '\n' - help_text += '@'+bot_username + ' ' + show_help + '\n' + help_text += '@'+bot_username + ' ' + claim_a_draw + '\n' return help_text @@ -1038,6 +1105,10 @@ def replying(): reply = True + elif query_word == search_draw: + + reply = True + else: reply = False @@ -1136,8 +1207,19 @@ def load_strings6(bot_lang): list_games = get_parameter("list_games", language_filepath) get_a_game_anotation = get_parameter("get_a_game_anotation", language_filepath) show_help = get_parameter("show_help", language_filepath) + search_draw = get_parameter("search_draw", language_filepath) + ask_for_draw = get_parameter("ask_for_draw", language_filepath) - return (start_or_join_a_new_game, move_a_piece, leave_a_game, list_games, get_a_game_anotation, show_help) + return (start_or_join_a_new_game, move_a_piece, leave_a_game, list_games, get_a_game_anotation, show_help, search_draw, ask_for_draw) + +def load_strings7(bot_lang): + + claim_draw_str = get_parameter("claim_draw_str", language_filepath) + draw_and_str = get_parameter("draw_and_str", language_filepath) + agreed_draw_str = get_parameter("agreed_draw_str", language_filepath) + claim_a_draw = get_parameter("claim_a_draw", language_filepath) + + return (claim_draw_str, draw_and_str, agreed_draw_str, claim_a_draw) def mastodon(): @@ -1281,7 +1363,9 @@ if __name__ == '__main__': pawn_piece_letter, knight_piece_letter, bishop_piece_letter, rook_piece_letter, queen_piece_letter, king_piece_letter, email_subject = load_strings5(bot_lang) - start_or_join_a_new_game, move_a_piece, leave_a_game, list_games, get_a_game_anotation, show_help = load_strings6(bot_lang) + start_or_join_a_new_game, move_a_piece, leave_a_game, list_games, get_a_game_anotation, show_help, search_draw, ask_for_draw = load_strings6(bot_lang) + + claim_draw_str, draw_and_str, agreed_draw_str, claim_a_draw = load_strings7(bot_lang) mastodon, mastodon_hostname, bot_username = mastodon() @@ -1434,6 +1518,8 @@ if __name__ == '__main__': help_text = toot_help() + help_text = (help_text[:490] + '... ') if len(help_text) > 490 else help_text + mastodon.status_post(help_text, in_reply_to_id=status_id,visibility=visibility) update_replies(status_id, username, now) @@ -1805,6 +1891,36 @@ if __name__ == '__main__': update_replies(status_id, username, now) + elif query_word == search_draw: + + white_player, black_player, toot_text, stalemate = claim_draw(username) + + if stalemate == True: + + checkmate = False + + close_game(username, checkmate) + + toot_text = '@'+white_player + ' ' + draw_and_str + ' ' + '@'+black_player + ' ' + agreed_draw_str + '\n\n' + + toot_text += '\n' + winned_games + "\n" + + played_games, wins = get_stats(white_player) + + toot_text += white_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" + + played_games, wins = get_stats(black_player) + + toot_text += black_player + ': ' + str(wins) + ' ' + wins_of_many + ' ' + str(played_games) + "\n" + + mastodon.status_post(toot_text, in_reply_to_id=status_id,visibility=visibility) + + else: + + mastodon.status_post(toot_text, in_reply_to_id=status_id,visibility=visibility) + + update_replies(status_id, username, now) + elif query_word == search_help: help_text = toot_help()