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 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

View File

@ -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:

View File

@ -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))