2023-11-24 12:19:37 +01:00
|
|
|
from typing import List, Tuple
|
2023-11-23 13:18:38 +01:00
|
|
|
|
|
|
|
import psycopg2.extras
|
|
|
|
from database import conn_manager
|
|
|
|
|
|
|
|
import hanabi.hanab_game
|
2023-11-24 12:19:37 +01:00
|
|
|
from log_setup import logger
|
2023-11-23 13:18:38 +01:00
|
|
|
|
|
|
|
|
|
|
|
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()
|
2023-11-23 14:00:25 +01:00
|
|
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
(game_id,))
|
|
|
|
actions = []
|
|
|
|
for action_type, target, value in cur.fetchall():
|
|
|
|
actions.append(
|
|
|
|
hanabi.hanab_game.Action(hanabi.hanab_game.ActionType(action_type), target, value)
|
|
|
|
)
|
2023-11-24 12:19:37 +01:00
|
|
|
if len(actions) == 0:
|
|
|
|
err_msg = "Failed to load actions for game id {} from DB: No actions stored.".format(game_id)
|
|
|
|
logger.error(err_msg)
|
|
|
|
raise ValueError(err_msg)
|
2023-11-23 14:00:25 +01:00
|
|
|
return actions
|
|
|
|
|
|
|
|
|
|
|
|
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 "
|
|
|
|
"WHERE seed = %s "
|
|
|
|
"ORDER BY card_index ASC",
|
|
|
|
(seed,)
|
|
|
|
)
|
|
|
|
deck = []
|
|
|
|
for index, (card_index, suit_index, rank) in enumerate(cur.fetchall()):
|
|
|
|
assert index == card_index
|
|
|
|
deck.append(
|
|
|
|
hanabi.hanab_game.DeckCard(suit_index, rank, card_index)
|
|
|
|
)
|
2023-11-24 12:19:37 +01:00
|
|
|
if len(deck) == 0:
|
|
|
|
err_msg = "Failed to load deck for seed {} from DB: No cards stored.".format(seed)
|
|
|
|
logger.error(err_msg)
|
|
|
|
raise ValueError(err_msg)
|
2023-11-23 14:00:25 +01:00
|
|
|
return deck
|
2023-11-24 12:19:37 +01:00
|
|
|
|
|
|
|
|
2024-01-13 14:27:45 +01:00
|
|
|
def load_game_parts(game_id: int) -> Tuple[hanabi.hanab_game.HanabiInstance, List[hanabi.hanab_game.Action], str]:
|
|
|
|
"""
|
|
|
|
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
|
|
|
|
"""
|
2023-11-24 12:19:37 +01:00
|
|
|
cur = conn_manager.get_new_cursor()
|
|
|
|
cur.execute(
|
2024-01-13 14:27:45 +01:00
|
|
|
"SELECT games.num_players, games.seed, variants.clue_starved, variants.name "
|
2023-11-24 12:19:37 +01:00
|
|
|
"FROM games "
|
|
|
|
"INNER JOIN variants"
|
|
|
|
" ON games.variant_id = variants.id "
|
|
|
|
"WHERE games.id = %s",
|
|
|
|
(game_id,)
|
|
|
|
)
|
|
|
|
res = cur.fetchone()
|
|
|
|
if res is None:
|
|
|
|
err_msg = "Failed to retrieve game details of game {}.".format(game_id)
|
|
|
|
logger.error(err_msg)
|
|
|
|
raise ValueError(err_msg)
|
|
|
|
|
|
|
|
# Unpack results now
|
2024-01-13 14:27:45 +01:00
|
|
|
(num_players, seed, clue_starved, variant_name) = res
|
2023-11-24 12:19:37 +01:00
|
|
|
|
|
|
|
actions = load_actions(game_id)
|
|
|
|
deck = load_deck(seed)
|
|
|
|
|
|
|
|
instance = hanabi.hanab_game.HanabiInstance(deck, num_players, clue_starved=clue_starved)
|
2024-01-13 14:27:45 +01:00
|
|
|
return instance, actions, variant_name
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
for action in actions:
|
|
|
|
game.make_action(action)
|
|
|
|
return game, variant_name
|
|
|
|
|