Adjust games_db_interface to database format

Also adjust the check_game method to use new interface.
This commit is contained in:
Maximilian Keßler 2024-03-19 14:57:11 +01:00
parent 6651ef9145
commit 1c656de615
Signed by: max
GPG Key ID: BCC5A619923C0BA5
3 changed files with 54 additions and 58 deletions

View File

@ -3,6 +3,10 @@ from typing import List, Tuple
import psycopg2.extras import psycopg2.extras
import hanabi.hanab_game 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]): 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): for turn, action in enumerate(actions):
vals.append((game_id, turn, action.type.value, action.target, action.value or 0)) 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( psycopg2.extras.execute_values(
cur, cur,
"INSERT INTO game_actions (game_id, turn, type, target, value) " "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): for index, card in enumerate(deck):
vals.append((seed, index, card.suitIndex, card.rank)) vals.append((seed, index, card.suitIndex, card.rank))
conn = conn_manager.get_connection()
cur = conn.cursor()
psycopg2.extras.execute_values( psycopg2.extras.execute_values(
cur, cur,
"INSERT INTO seeds (seed, card_index, suit_index, rank) " "INSERT INTO decks (seed, deck_index, suit_index, rank) "
"VALUES %s " "VALUES %s "
"ON CONFLICT (seed, card_index) " "ON CONFLICT (seed, deck_index) DO UPDATE SET "
"DO NOTHING", "(suit_index, rank) = (excluded.suit_index, excluded.rank)",
vals vals
) )
conn.commit() conn.commit()
def load_actions(game_id: int) -> List[hanabi.hanab_game.Action]: 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 " cur.execute("SELECT type, target, value FROM game_actions "
"WHERE game_id = %s " "WHERE game_id = %s "
"ORDER BY turn ASC", "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]: def load_deck(seed: str) -> List[hanabi.hanab_game.DeckCard]:
cur = conn_manager.get_new_cursor() cur.execute("SELECT deck_index, suit_index, rank FROM decks "
cur.execute("SELECT card_index, suit_index, rank FROM seeds "
"WHERE seed = %s " "WHERE seed = %s "
"ORDER BY card_index ASC", "ORDER BY deck_index ASC",
(seed,) (seed,)
) )
deck = [] deck = []
@ -79,15 +77,17 @@ def load_deck(seed: str) -> List[hanabi.hanab_game.DeckCard]:
return deck 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 Loads information on game from database
@param game_id: ID of game @param game_id: ID of game
@return: Instance (i.e. deck + settings) of game, list of actions, variant name @return: Instance (i.e. deck + settings) of game, list of actions, variant name
""" """
cur = conn_manager.get_new_cursor()
cur.execute( 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 " "FROM games "
"INNER JOIN variants" "INNER JOIN variants"
" ON games.variant_id = variants.id " " 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) raise ValueError(err_msg)
# Unpack results now # 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) actions = load_actions(game_id)
deck = load_deck(seed) deck = load_deck(seed)
instance = hanabi.hanab_game.HanabiInstance(deck, num_players, clue_starved=clue_starved) instance = hanabi.live.hanab_live.HanabLiveInstance(
return instance, actions, variant_name 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]: def load_game(game_id: int) -> hanabi.live.hanab_live.HanabLiveGameState:
instance, actions, variant_name = load_game_parts(game_id) instance, actions = load_game_parts(game_id)
game = hanabi.hanab_game.GameState(instance) game = hanabi.live.hanab_live.HanabLiveGameState(instance)
for action in actions: for action in actions:
game.make_action(action) game.make_action(action)
return game, variant_name return game

View File

@ -8,6 +8,8 @@ from hanabi.live import hanab_live
from hanabi.live import compress from hanabi.live import compress
from hanabi.solvers import sat 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 # 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: # 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]: def check_game(game_id: int) -> Tuple[int, hanab_game.GameState]:
logger.debug("Analysing game {}".format(game_id)) logger.debug("Analysing game {}".format(game_id))
with database.conn.cursor() as cur: with database.conn.cursor() as cur:
cur.execute("SELECT games.num_players, deck, actions, score, games.variant_id, starting_player FROM games " cur.execute("SELECT games.num_players, score, games.variant_id, starting_player FROM games "
"INNER JOIN seeds ON seeds.seed = games.seed "
"WHERE games.id = (%s)", "WHERE games.id = (%s)",
(game_id,) (game_id,)
) )
res = cur.fetchone() res = cur.fetchone()
if res is None: if res is None:
raise ValueError("No game associated with id {} in database.".format(game_id)) raise ValueError("No game associated with id {} in database.".format(game_id))
(num_players, compressed_deck, compressed_actions, score, variant_id, starting_player) = res (num_players, score, variant_id, starting_player) = res
deck = compress.decompress_deck(compressed_deck) instance, actions = games_db_interface.load_game_parts(game_id)
actions = compress.decompress_actions(compressed_actions)
instance = hanab_live.HanabLiveInstance(
deck,
num_players,
variant_id=variant_id,
starting_player=starting_player
)
# check if the instance is already won # check if the instance is already won
if instance.max_score == score: if instance.max_score == score:

View File

@ -11,10 +11,11 @@ from hanabi import constants
from hanabi import logger from hanabi import logger
from hanabi import database from hanabi import database
from hanabi.live import site_api from hanabi.live import site_api
from hanabi.live import compress
from hanabi.live import variants from hanabi.live import variants
from hanabi.live import hanab_live from hanabi.live import hanab_live
from hanabi.database import games_db_interface
class GameExportError(ValueError): class GameExportError(ValueError):
@ -172,18 +173,7 @@ def detailed_export_game(
) )
logger.debug("New seed {} imported.".format(seed)) logger.debug("New seed {} imported.".format(seed))
values = [] games_db_interface.store_deck_for_seed(seed, deck)
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
)
database.cur.execute( database.cur.execute(
"INSERT INTO games (" "INSERT INTO games ("
@ -219,18 +209,7 @@ def detailed_export_game(
game_participant_values game_participant_values
) )
# Insert actions into database games_db_interface.store_actions(game_id, actions)
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
)
logger.debug("Imported game {}".format(game_id)) 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") database.cur.execute("ROLLBACK TO seed_insert")
detailed_export_game(game_id, score=score, var_id=var_id) detailed_export_game(game_id, score=score, var_id=var_id)
database.cur.execute("RELEASE seed_insert") 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)) logger.debug("Imported game {}".format(game_id))