diff --git a/src/hanabi/database/games_db_interface.py b/src/hanabi/database/games_db_interface.py index c42a74a..8df26cf 100644 --- a/src/hanabi/database/games_db_interface.py +++ b/src/hanabi/database/games_db_interface.py @@ -3,6 +3,10 @@ from typing import List, Tuple import psycopg2.extras import hanabi.hanab_game +import hanabi.live.hanab_live +from hanabi import logger + +from hanabi.database import conn, cur def store_actions(game_id: int, actions: List[hanabi.hanab_game.Action]): @@ -10,8 +14,6 @@ def store_actions(game_id: int, actions: List[hanabi.hanab_game.Action]): 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) " @@ -28,21 +30,18 @@ def store_deck_for_seed(seed: str, deck: List[hanabi.hanab_game.DeckCard]): 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) " + "INSERT INTO decks (seed, deck_index, suit_index, rank) " "VALUES %s " - "ON CONFLICT (seed, card_index) " - "DO NOTHING", + "ON CONFLICT (seed, deck_index) DO UPDATE SET " + "(suit_index, rank) = (excluded.suit_index, excluded.rank)", vals ) conn.commit() def load_actions(game_id: int) -> List[hanabi.hanab_game.Action]: - cur = conn_manager.get_new_cursor() cur.execute("SELECT type, target, value FROM game_actions " "WHERE game_id = %s " "ORDER BY turn ASC", @@ -60,10 +59,9 @@ def load_actions(game_id: int) -> List[hanabi.hanab_game.Action]: def load_deck(seed: str) -> List[hanabi.hanab_game.DeckCard]: - cur = conn_manager.get_new_cursor() - cur.execute("SELECT card_index, suit_index, rank FROM seeds " + cur.execute("SELECT deck_index, suit_index, rank FROM decks " "WHERE seed = %s " - "ORDER BY card_index ASC", + "ORDER BY deck_index ASC", (seed,) ) deck = [] @@ -79,15 +77,17 @@ def load_deck(seed: str) -> List[hanabi.hanab_game.DeckCard]: return deck -def load_game_parts(game_id: int) -> Tuple[hanabi.hanab_game.HanabiInstance, List[hanabi.hanab_game.Action], str]: +def load_game_parts(game_id: int) -> Tuple[hanabi.live.hanab_live.HanabLiveInstance, List[hanabi.hanab_game.Action]]: """ Loads information on game from database @param game_id: ID of game @return: Instance (i.e. deck + settings) of game, list of actions, variant name """ - cur = conn_manager.get_new_cursor() cur.execute( - "SELECT games.num_players, games.seed, variants.clue_starved, variants.name " + "SELECT " + "games.num_players, games.seed, games.one_extra_card, games.one_less_card, games.deck_plays, " + "games.all_or_nothing," + "variants.clue_starved, variants.name, variants.id, variants.throw_it_in_a_hole " "FROM games " "INNER JOIN variants" " ON games.variant_id = variants.id " @@ -101,19 +101,29 @@ def load_game_parts(game_id: int) -> Tuple[hanabi.hanab_game.HanabiInstance, Lis raise ValueError(err_msg) # Unpack results now - (num_players, seed, clue_starved, variant_name) = res + (num_players, seed, one_extra_card, one_less_card, deck_plays, all_or_nothing, clue_starved, variant_name, variant_id, throw_it_in_a_hole) = res actions = load_actions(game_id) deck = load_deck(seed) - instance = hanabi.hanab_game.HanabiInstance(deck, num_players, clue_starved=clue_starved) - return instance, actions, variant_name + instance = hanabi.live.hanab_live.HanabLiveInstance( + deck=deck, + num_players=num_players, + variant_id=variant_id, + one_extra_card=one_extra_card, + one_less_card=one_less_card, + fives_give_clue=not throw_it_in_a_hole, + deck_plays=deck_plays, + all_or_nothing=all_or_nothing, + clue_starved=clue_starved + ) + return instance, actions -def load_game(game_id: int) -> Tuple[hanabi.hanab_game.GameState, str]: - instance, actions, variant_name = load_game_parts(game_id) - game = hanabi.hanab_game.GameState(instance) +def load_game(game_id: int) -> hanabi.live.hanab_live.HanabLiveGameState: + instance, actions = load_game_parts(game_id) + game = hanabi.live.hanab_live.HanabLiveGameState(instance) for action in actions: game.make_action(action) - return game, variant_name + return game diff --git a/src/hanabi/live/check_game.py b/src/hanabi/live/check_game.py index dbfd2a5..59f1aaa 100644 --- a/src/hanabi/live/check_game.py +++ b/src/hanabi/live/check_game.py @@ -8,6 +8,8 @@ from hanabi.live import hanab_live from hanabi.live import compress from hanabi.solvers import sat +from hanabi.database import games_db_interface + # returns minimal number T of turns (from game) after which instance was infeasible # and a replay achieving maximum score while following the replay for the first (T-1) turns: @@ -19,24 +21,15 @@ from hanabi.solvers import sat def check_game(game_id: int) -> Tuple[int, hanab_game.GameState]: logger.debug("Analysing game {}".format(game_id)) with database.conn.cursor() as cur: - cur.execute("SELECT games.num_players, deck, actions, score, games.variant_id, starting_player FROM games " - "INNER JOIN seeds ON seeds.seed = games.seed " + cur.execute("SELECT games.num_players, score, games.variant_id, starting_player FROM games " "WHERE games.id = (%s)", (game_id,) ) res = cur.fetchone() if res is None: raise ValueError("No game associated with id {} in database.".format(game_id)) - (num_players, compressed_deck, compressed_actions, score, variant_id, starting_player) = res - deck = compress.decompress_deck(compressed_deck) - actions = compress.decompress_actions(compressed_actions) - - instance = hanab_live.HanabLiveInstance( - deck, - num_players, - variant_id=variant_id, - starting_player=starting_player - ) + (num_players, score, variant_id, starting_player) = res + instance, actions = games_db_interface.load_game_parts(game_id) # check if the instance is already won if instance.max_score == score: diff --git a/src/hanabi/live/download_data.py b/src/hanabi/live/download_data.py index 73298c4..ebe0a24 100644 --- a/src/hanabi/live/download_data.py +++ b/src/hanabi/live/download_data.py @@ -11,10 +11,11 @@ from hanabi import constants from hanabi import logger from hanabi import database from hanabi.live import site_api -from hanabi.live import compress from hanabi.live import variants from hanabi.live import hanab_live +from hanabi.database import games_db_interface + class GameExportError(ValueError): @@ -172,18 +173,7 @@ def detailed_export_game( ) logger.debug("New seed {} imported.".format(seed)) - values = [] - for index, card in enumerate(deck): - values.append((seed, index, card.suitIndex, card.rank)) - - psycopg2.extras.execute_values( - database.cur, - "INSERT INTO decks (seed, deck_index, suit_index, rank)" - "VALUES %s " - "ON CONFLICT (seed, deck_index) DO UPDATE SET " - "(suit_index, rank) = (excluded.suit_index, excluded.rank)", - values - ) + games_db_interface.store_deck_for_seed(seed, deck) database.cur.execute( "INSERT INTO games (" @@ -219,18 +209,7 @@ def detailed_export_game( game_participant_values ) - # Insert actions into database - action_values = [] - for turn, action in enumerate(actions): - action: hanab_game.Action - action_values.append((game_id, turn, action.type.value, action.target, action.value or 0)) - - psycopg2.extras.execute_values( - database.cur, - "INSERT INTO game_actions (game_id, turn, type, target, value) " - "VALUES %s", - action_values - ) + games_db_interface.store_actions(game_id, actions) logger.debug("Imported game {}".format(game_id)) @@ -277,6 +256,20 @@ def _process_game_row(game: Dict, var_id, export_all_games: bool = False): database.cur.execute("ROLLBACK TO seed_insert") detailed_export_game(game_id, score=score, var_id=var_id) database.cur.execute("RELEASE seed_insert") + + # Insert participants into database + ids = ensure_users_in_db_and_get_ids(users) + game_participant_values = [] + for index, user_id in enumerate(ids): + game_participant_values.append((game_id, user_id, index)) + psycopg2.extras.execute_values( + database.cur, + "INSERT INTO game_participants (game_id, user_id, seat) VALUES %s " + "ON CONFLICT (game_id, user_id) DO UPDATE SET seat = excluded.seat", + game_participant_values + ) + + logger.debug("Imported game {}".format(game_id))