From 7fdee4bae015c7753b30177efd27ff16c1a73caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maximilian=20Ke=C3=9Fler?= Date: Thu, 23 Nov 2023 13:18:38 +0100 Subject: [PATCH] Store actions and deck to database --- fetch_games.py | 24 ++++++++++++++------- games_db_interface.py | 42 +++++++++++++++++++++++++++++++++++++ install/database_schema.sql | 2 +- 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 games_db_interface.py diff --git a/fetch_games.py b/fetch_games.py index e7b1eb2..8867ab7 100644 --- a/fetch_games.py +++ b/fetch_games.py @@ -9,6 +9,7 @@ import hanabi.live.hanab_live import hanabi.hanab_game import constants +import games_db_interface import database import utils from database import conn_manager @@ -181,7 +182,12 @@ def store_new_games(games: Dict[int, GameInfo]): conn.commit() -def detailed_fetch_game(game_id: int): +def detailed_fetch_game(game_id: int) -> bool: + """ + Fetches full game details from the server and stores it in local DB if this game is a league game. + @param game_id: Game ID from hanab.live + @return: Whether the processed game was accepted as a league game, i.e. inserted into the DB + """ url = "https://hanab.live/export/{}".format(game_id) response = session.get(url) if not response.status_code == 200: @@ -191,8 +197,6 @@ def detailed_fetch_game(game_id: int): game_json = json.loads(response.text) instance, actions = hanabi.live.hanab_live.parse_json_game(game_json, False) - print(instance, actions, instance.deck) - print(game_json) game_id = game_json["id"] players = game_json["players"] @@ -202,15 +206,15 @@ def detailed_fetch_game(game_id: int): var_name = game_options.get("variant", "No Variant") if not utils.are_game_options_allowed(game_id, game_options): - return + return False if not utils.is_player_count_allowed(game_id, num_players): - return + return False var_id = database.get_variant_id(var_name) if var_id is None: logger.debug("Rejected game {} due to invalid variant id {}".format(game_id, var_id)) - return + return False # All game options are ok, now check if the number of players is okay. normalized_usernames = [utils.normalize_username(username) for username in players] @@ -218,11 +222,12 @@ def detailed_fetch_game(game_id: int): # The return value here is a str if there was an unregistered participant if type(user_ids) is str: logger.debug("Rejected game {} due to unregistered participant {}".format(game_id, user_ids)) - return + return False # Now, we can start to actually process the game details instance, actions = hanabi.live.hanab_live.parse_json_game(game_json, False) game = hanabi.hanab_game.GameState(instance) + # In order to figure out the score, we will need to play the game once for action in actions: game.make_action(action) @@ -256,3 +261,8 @@ def detailed_fetch_game(game_id: int): ) # DB is now in a consistent state again: We made sure the game and its participants are added. conn.commit() + + # It remains to store the seed and action data for this game + games_db_interface.store_deck_for_seed(seed, instance.deck) + games_db_interface.store_actions(game_id, actions) + return True diff --git a/games_db_interface.py b/games_db_interface.py new file mode 100644 index 0000000..7c305ba --- /dev/null +++ b/games_db_interface.py @@ -0,0 +1,42 @@ +from typing import List + +import psycopg2.extras +from database import conn_manager + +import hanabi.hanab_game + + +def store_actions(game_id: int, actions: List[hanabi.hanab_game.Action]): + vals = [] + for turn, action in enumerate(actions): + vals.append((game_id, turn, action.type.value, action.target, action.value or 0)) + + conn = conn_manager.get_connection() + cur = conn.cursor() + psycopg2.extras.execute_values( + cur, + "INSERT INTO game_actions (game_id, turn, type, target, value) " + "VALUES %s " + "ON CONFLICT (game_id, turn) " + "DO NOTHING", + vals + ) + conn.commit() + + +def store_deck_for_seed(seed: str, deck: List[hanabi.hanab_game.DeckCard]): + vals = [] + for index, card in enumerate(deck): + vals.append((seed, index, card.suitIndex, card.rank)) + + conn = conn_manager.get_connection() + cur = conn.cursor() + psycopg2.extras.execute_values( + cur, + "INSERT INTO seeds (seed, card_index, suit_index, rank) " + "VALUES %s " + "ON CONFLICT (seed, card_index) " + "DO NOTHING", + vals + ) + conn.commit() diff --git a/install/database_schema.sql b/install/database_schema.sql index 906e671..ab8078e 100644 --- a/install/database_schema.sql +++ b/install/database_schema.sql @@ -225,7 +225,7 @@ CREATE TABLE seeds ( card_index SMALLINT NOT NULL, suit_index SMALLINT NOT NULL, rank SMALLINT NOT NULL, - CONSTRAINT cards_unique UNIQUE (seed, card_index) + PRIMARY KEY (seed, card_index) );