Merge pull request #49 from ThomasRubini/python_refactor

Python refactor
This commit is contained in:
Djalim Simaila 2023-01-15 21:58:02 +01:00 committed by GitHub
commit a8fc8b139d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 425 additions and 296 deletions

View File

@ -1,36 +1,36 @@
from tables import Answer
ANSWERS = [
Answer(1,0,1,1),
Answer(2,0,1,2),
Answer(3,1,1,3),
Answer(4,1,1,4),
Answer(5,0,2,6),
Answer(6,0,2,7),
Answer(7,1,2,8),
Answer(8,1,2,9),
Answer(9,0,3,11),
Answer(10,0,3,12),
Answer(11,1,3,13),
Answer(12,1,3,14),
Answer(13,0,4,16),
Answer(14,0,4,17),
Answer(15,1,4,18),
Answer(16,1,4,19),
Answer(17,0,5,21),
Answer(18,0,5,22),
Answer(19,1,5,23),
Answer(20,1,5,24),
Answer(21,0,6,26),
Answer(22,0,6,27),
Answer(23,1,6,28),
Answer(24,1,6,29),
Answer(25,0,7,31),
Answer(26,0,7,32),
Answer(27,1,7,33),
Answer(28,1,7,34),
Answer(29,0,8,36),
Answer(30,0,8,37),
Answer(31,1,8,38),
Answer(32,1,8,39)
]
Answer(1, 0, 1, 1),
Answer(2, 0, 1, 2),
Answer(3, 1, 1, 3),
Answer(4, 1, 1, 4),
Answer(5, 0, 2, 6),
Answer(6, 0, 2, 7),
Answer(7, 1, 2, 8),
Answer(8, 1, 2, 9),
Answer(9, 0, 3, 11),
Answer(10, 0, 3, 12),
Answer(11, 1, 3, 13),
Answer(12, 1, 3, 14),
Answer(13, 0, 4, 16),
Answer(14, 0, 4, 17),
Answer(15, 1, 4, 18),
Answer(16, 1, 4, 19),
Answer(17, 0, 5, 21),
Answer(18, 0, 5, 22),
Answer(19, 1, 5, 23),
Answer(20, 1, 5, 24),
Answer(21, 0, 6, 26),
Answer(22, 0, 6, 27),
Answer(23, 1, 6, 28),
Answer(24, 1, 6, 29),
Answer(25, 0, 7, 31),
Answer(26, 0, 7, 32),
Answer(27, 1, 7, 33),
Answer(28, 1, 7, 34),
Answer(29, 0, 8, 36),
Answer(30, 0, 8, 37),
Answer(31, 1, 8, 38),
Answer(32, 1, 8, 39)
]

View File

@ -1,66 +1,66 @@
from tables import Locale
LOCALES = [
Locale(0,"FR","Le Médecin"),
Locale(1,"FR","Il y avait {SALLE} ça m'a intrigué."),
Locale(2,"FR","{SALLE} avait l'air sympa donc j'y suis allé."),
Locale(3,"FR","Il me semble qu'il y avait {NPC}."),
Locale(4,"FR","Je suis pratiquement sûr que j'étais avec {NPC}."),
Locale(5,"FR","Le Diplomate"),
Locale(6,"FR","Je profitais d'une collation dans {SALLE}."),
Locale(7,"FR","J'admirais la décoration subtile de {SALLE} ... je m'en inspirerais pour chez moi."),
Locale(8,"FR","Je m'instruisais auprès de {NPC}."),
Locale(9,"FR","Avec {NPC} pour exposer nos différents points de vus sur divers sujets."),
Locale(10,"FR","Le Combattant"),
Locale(11,"FR","{SALLE} nous a servi de salle de duel."),
Locale(12,"FR","J'ai festoillé dans {SALLE}."),
Locale(13,"FR","On faisait un bras de fer avec {NPC}."),
Locale(14,"FR","{NPC} et moi nous sommes engagés dans une joute verbale des plus palpitante."),
Locale(15,"FR","La Duchesse"),
Locale(16,"FR","Pour votre gouverne je me trouvais dans {SALLE}."),
Locale(17,"FR","s'il vous faut savoir ... j'étais en train de me reposer dans {SALLE}."),
Locale(18,"FR","{NPC} me tenait compagnie."),
Locale(19,"FR","J'était avec {NPC}."),
Locale(20,"FR","La Diva"),
Locale(21,"FR","{SALLE} me semblait être la plus belle pièce de la maison."),
Locale(22,"FR","Je buvais un verre dans {SALLE}."),
Locale(23,"FR","Je profitais de la compagnie de {NPC}."),
Locale(24,"FR","J'étais avec {NPC} à partager une délicieuse conversation ainsi qu'une coupe de champagne."),
Locale(25,"FR","La Parieuse"),
Locale(26,"FR","J'avis monté une table de jeu dans {SALLE}."),
Locale(27,"FR","{SALLE} est tout de même plus agréable une fois changé en casino."),
Locale(28,"FR","Vous saviez que {NPC} était incroyable avec des cartes à la mains?"),
Locale(29,"FR","Si vous tenez à votre argent ne jouez jamisa au poker avec {NPC}."),
Locale(30,"FR","L'Agent"),
Locale(31,"FR","On pouvait me retrouver dans {SALLE}."),
Locale(32,"FR","{SALLE}"),
Locale(33,"FR","J'étais avec {NPC} au moment des faits."),
Locale(34,"FR","{NPC}"),
Locale(35,"FR","La Voyageuse"),
Locale(36,"FR","{SALLE} me semblais un bon endroit pour me poser"),
Locale(37,"FR","{SALLE} me rappelais mes voyages."),
Locale(38,"FR","Nous organisions notre prochain voyage avec {NPC}."),
Locale(39,"FR","Avec {NPC} on parler des lieux que lon avait visité. Cétait très instructif."),
Locale(100,"FR","Ce manoir est plutôt grand ... vous pouvez me dire où vous étiez?"),
Locale(101,"FR","Vous étiez où au moment des faits?"),
Locale(102,"FR","Dans quelle salle étiez-vous pendant que le coffre était subtilisé ?"),
Locale(105,"FR","Etiez-vous seul au moment des faits ?"),
Locale(106,"FR","Quelquun peu valider vous alibi pour la soirée ?"),
Locale(107,"FR","Vous étiez accompagné ce soir-là ?"),
Locale(120,"FR","méfiant(e)"),
Locale(110,"FR","un maintien rigide des traits du visage, un regard de travers. Une crispation des sourcils et parfois des rides autour de la bouche. Ces caractéristiques sont synonmes d'incompréhension ou de peur de ce que peut nous annoncer la personne en face."),
Locale(121,"FR","heureux(se)"),
Locale(111,"FR","un visage decontracté et ouvert, les muscles des joues contractés qui laissent apparaître un sourie. On le détermine aussi par des yeux plissés en accord avec les sourcils qui marque la différence avec un faux sourire où les sourcils ne sont pas contractés. Cela montre une complicité avec l'interlocuteur ou un moyen de ne pas laisser paraître ses réelles émotions."),
Locale(122,"FR","triste"),
Locale(112,"FR","des sourcils contractés et resserés vers le centre du visage auxquels s'ajoute un regard vide ou fuyant de l'interlocuteur soit en fermant les yeux soit en évitant un contact visuel. Ces caractéristiques témoignent d'un sentiment puissant ou du fait d'être atteint par les propos ou accusations de son interlocuteur."),
Locale(123,"FR","stressé(e)"),
Locale(113,"FR","un visage crispé qui s'accompagne habituellement de sourcils froncés, un regard perdu qui se détourne de celui de son interlocuteur. Cela s'accompagne souvent de mouvements de la tête et de la bouche en se mordant les lèvres par exemple. Tout cela traduit une difficulté de concentration ou une peur de ce qu'annonce ou peut nous annoncer l'interlocuteur en face."),
Locale(124,"FR","surpris(e)"),
Locale(114,"FR","généralement par des yeux écarquillés et un haussement des sourcils. Cela peut également se distinguer par une bouche ouvert ou au contraire des gens serrées et parfois par un relâchement du visage. Ces caractéristiques correspondent à un choc, une incompréhension ou encore un étonnement de ce que voit ou entend la personne."),
Locale(130,"FR","Le salon"),
Locale(131,"FR","La salle de reception"),
Locale(132,"FR","Le hall d'entrée"),
Locale(133,"FR","La cuisine"),
Locale(134,"FR","La chambre du maitre"),
Locale(135,"FR","Le jarin")
Locale(0, "FR", "Le Médecin"),
Locale(1, "FR", "Il y avait {SALLE} ça m'a intrigué."),
Locale(2, "FR", "{SALLE} avait l'air sympa donc j'y suis allé."),
Locale(3, "FR", "Il me semble qu'il y avait {NPC}."),
Locale(4, "FR", "Je suis pratiquement sûr que j'étais avec {NPC}."),
Locale(5, "FR", "Le Diplomate"),
Locale(6, "FR", "Je profitais d'une collation dans {SALLE}."),
Locale(7, "FR", "J'admirais la décoration subtile de {SALLE} ... je m'en inspirerais pour chez moi."),
Locale(8, "FR", "Je m'instruisais auprès de {NPC}."),
Locale(9, "FR", "Avec {NPC} pour exposer nos différents points de vus sur divers sujets."),
Locale(10, "FR", "Le Combattant"),
Locale(11, "FR", "{SALLE} nous a servi de salle de duel."),
Locale(12, "FR", "J'ai festoillé dans {SALLE}."),
Locale(13, "FR", "On faisait un bras de fer avec {NPC}."),
Locale(14, "FR", "{NPC} et moi nous sommes engagés dans une joute verbale des plus palpitante."),
Locale(15, "FR", "La Duchesse"),
Locale(16, "FR", "Pour votre gouverne je me trouvais dans {SALLE}."),
Locale(17, "FR", "s'il vous faut savoir ... j'étais en train de me reposer dans {SALLE}."),
Locale(18, "FR", "{NPC} me tenait compagnie."),
Locale(19, "FR", "J'était avec {NPC}."),
Locale(20, "FR", "La Diva"),
Locale(21, "FR", "{SALLE} me semblait être la plus belle pièce de la maison."),
Locale(22, "FR", "Je buvais un verre dans {SALLE}."),
Locale(23, "FR", "Je profitais de la compagnie de {NPC}."),
Locale(24, "FR", "J'étais avec {NPC} à partager une délicieuse conversation ainsi qu'une coupe de champagne."),
Locale(25, "FR", "La Parieuse"),
Locale(26, "FR", "J'avis monté une table de jeu dans {SALLE}."),
Locale(27, "FR", "{SALLE} est tout de même plus agréable une fois changé en casino."),
Locale(28, "FR", "Vous saviez que {NPC} était incroyable avec des cartes à la mains?"),
Locale(29, "FR", "Si vous tenez à votre argent ne jouez jamisa au poker avec {NPC}."),
Locale(30, "FR", "L'Agent"),
Locale(31, "FR", "On pouvait me retrouver dans {SALLE}."),
Locale(32, "FR", "{SALLE}"),
Locale(33, "FR", "J'étais avec {NPC} au moment des faits."),
Locale(34, "FR", "{NPC}"),
Locale(35, "FR", "La Voyageuse"),
Locale(36, "FR", "{SALLE} me semblais un bon endroit pour me poser"),
Locale(37, "FR", "{SALLE} me rappelais mes voyages."),
Locale(38, "FR", "Nous organisions notre prochain voyage avec {NPC}."),
Locale(39, "FR", "Avec {NPC} on parler des lieux que lon avait visité. Cétait très instructif."),
Locale(100, "FR", "Ce manoir est plutôt grand ... vous pouvez me dire où vous étiez?"),
Locale(101, "FR", "Vous étiez où au moment des faits?"),
Locale(102, "FR", "Dans quelle salle étiez-vous pendant que le coffre était subtilisé ?"),
Locale(105, "FR", "Etiez-vous seul au moment des faits ?"),
Locale(106, "FR", "Quelquun peu valider vous alibi pour la soirée ?"),
Locale(107, "FR", "Vous étiez accompagné ce soir-là ?"),
Locale(120, "FR", "méfiant(e)"),
Locale(110, "FR", "un maintien rigide des traits du visage, un regard de travers. Une crispation des sourcils et parfois des rides autour de la bouche. Ces caractéristiques sont synonmes d'incompréhension ou de peur de ce que peut nous annoncer la personne en face."),
Locale(121, "FR", "heureux(se)"),
Locale(111, "FR", "un visage decontracté et ouvert, les muscles des joues contractés qui laissent apparaître un sourie. On le détermine aussi par des yeux plissés en accord avec les sourcils qui marque la différence avec un faux sourire où les sourcils ne sont pas contractés. Cela montre une complicité avec l'interlocuteur ou un moyen de ne pas laisser paraître ses réelles émotions."),
Locale(122, "FR", "triste"),
Locale(112, "FR", "des sourcils contractés et resserés vers le centre du visage auxquels s'ajoute un regard vide ou fuyant de l'interlocuteur soit en fermant les yeux soit en évitant un contact visuel. Ces caractéristiques témoignent d'un sentiment puissant ou du fait d'être atteint par les propos ou accusations de son interlocuteur."),
Locale(123, "FR", "stressé(e)"),
Locale(113, "FR", "un visage crispé qui s'accompagne habituellement de sourcils froncés, un regard perdu qui se détourne de celui de son interlocuteur. Cela s'accompagne souvent de mouvements de la tête et de la bouche en se mordant les lèvres par exemple. Tout cela traduit une difficulté de concentration ou une peur de ce qu'annonce ou peut nous annoncer l'interlocuteur en face."),
Locale(124, "FR", "surpris(e)"),
Locale(114, "FR", "généralement par des yeux écarquillés et un haussement des sourcils. Cela peut également se distinguer par une bouche ouvert ou au contraire des gens serrées et parfois par un relâchement du visage. Ces caractéristiques correspondent à un choc, une incompréhension ou encore un étonnement de ce que voit ou entend la personne."),
Locale(130, "FR", "Le salon"),
Locale(131, "FR", "La salle de reception"),
Locale(132, "FR", "Le hall d'entrée"),
Locale(133, "FR", "La cuisine"),
Locale(134, "FR", "La chambre du maitre"),
Locale(135, "FR", "Le jarin")
]

View File

@ -1,12 +1,12 @@
from tables import Npc
NPCS = [
Npc(1,0),
Npc(2,5),
Npc(3,10),
Npc(4,15),
Npc(5,20),
Npc(6,25),
Npc(7,30),
Npc(8,35)
]
Npc(1, 0),
Npc(2, 5),
Npc(3, 10),
Npc(4, 15),
Npc(5, 20),
Npc(6, 25),
Npc(7, 30),
Npc(8, 35)
]

View File

@ -1,10 +1,10 @@
from tables import Place
PLACES = [
Place(1,130),
Place(2,131),
Place(3,132),
Place(4,133),
Place(5,134),
Place(6,135)
]
Place(1, 130),
Place(2, 131),
Place(3, 132),
Place(4, 133),
Place(5, 134),
Place(6, 135)
]

View File

@ -1,10 +1,10 @@
from tables import Question
QUESTIONS = [
Question(1,0,100),
Question(2,0,101),
Question(3,0,102),
Question(4,1,105),
Question(5,1,106),
Question(6,1,107)
]
Question(1, 0, 100),
Question(2, 0, 101),
Question(3, 0, 102),
Question(4, 1, 105),
Question(5, 1, 106),
Question(6, 1, 107)
]

View File

@ -1,44 +1,44 @@
from tables import Reaction
REACTIONS = [
Reaction(1,110,1,1),
Reaction(2,110,2,1),
Reaction(3,110,3,1),
Reaction(4,110,4,1),
Reaction(5,110,5,1),
Reaction(6,110,6,1),
Reaction(7,110,7,1),
Reaction(8,110,8,1),
Reaction(9,111,1,2),
Reaction(10,111,2,2),
Reaction(11,111,3,2),
Reaction(12,111,4,2),
Reaction(13,111,5,2),
Reaction(14,111,6,2),
Reaction(15,111,7,2),
Reaction(16,111,8,2),
Reaction(17,112,1,3),
Reaction(18,112,2,3),
Reaction(19,112,3,3),
Reaction(20,112,4,3),
Reaction(21,112,5,3),
Reaction(22,112,6,3),
Reaction(23,112,7,3),
Reaction(24,112,8,3),
Reaction(25,113,1,4),
Reaction(26,113,2,4),
Reaction(27,113,3,4),
Reaction(28,113,4,4),
Reaction(29,113,5,4),
Reaction(30,113,6,4),
Reaction(31,113,7,4),
Reaction(32,113,8,4),
Reaction(33,114,1,5),
Reaction(34,114,2,5),
Reaction(35,114,3,5),
Reaction(36,114,4,5),
Reaction(37,114,5,5),
Reaction(38,114,6,5),
Reaction(39,114,7,5),
Reaction(40,114,8,5)
]
Reaction(1, 110, 1, 1),
Reaction(2, 110, 2, 1),
Reaction(3, 110, 3, 1),
Reaction(4, 110, 4, 1),
Reaction(5, 110, 5, 1),
Reaction(6, 110, 6, 1),
Reaction(7, 110, 7, 1),
Reaction(8, 110, 8, 1),
Reaction(9, 111, 1, 2),
Reaction(10, 111, 2, 2),
Reaction(11, 111, 3, 2),
Reaction(12, 111, 4, 2),
Reaction(13, 111, 5, 2),
Reaction(14, 111, 6, 2),
Reaction(15, 111, 7, 2),
Reaction(16, 111, 8, 2),
Reaction(17, 112, 1, 3),
Reaction(18, 112, 2, 3),
Reaction(19, 112, 3, 3),
Reaction(20, 112, 4, 3),
Reaction(21, 112, 5, 3),
Reaction(22, 112, 6, 3),
Reaction(23, 112, 7, 3),
Reaction(24, 112, 8, 3),
Reaction(25, 113, 1, 4),
Reaction(26, 113, 2, 4),
Reaction(27, 113, 3, 4),
Reaction(28, 113, 4, 4),
Reaction(29, 113, 5, 4),
Reaction(30, 113, 6, 4),
Reaction(31, 113, 7, 4),
Reaction(32, 113, 8, 4),
Reaction(33, 114, 1, 5),
Reaction(34, 114, 2, 5),
Reaction(35, 114, 3, 5),
Reaction(36, 114, 4, 5),
Reaction(37, 114, 5, 5),
Reaction(38, 114, 6, 5),
Reaction(39, 114, 7, 5),
Reaction(40, 114, 8, 5)
]

View File

@ -1,9 +1,9 @@
from tables import Trait
TRAITS = [
Trait(1,120),
Trait(2,121),
Trait(3,122),
Trait(4,123),
Trait(5,124)
]
Trait(1, 120),
Trait(2, 121),
Trait(3, 122),
Trait(4, 123),
Trait(5, 124)
]

View File

@ -1,10 +1,10 @@
import os
import random
import truthseeker.logic.data_persistance.tables as tables
from sqlalchemy import create_engine
from sqlalchemy.orm import Session
from sqlalchemy import engine as eg
import random
import truthseeker.logic.data_persistance.tables as tables
url_object = eg.URL.create(
"mariadb+pymysql",
@ -17,42 +17,105 @@ url_object = eg.URL.create(
engine = create_engine(url_object)
session = Session(engine)
def get_text_from_lid(lang,lid) -> str:
def get_text_from_lid(lang: str, lid: int) -> str:
"""
Returns the text linked to a language and a locale id
:param lang: the lang to return the text in
:param lid: the locale id the get the text from
:return: the text associated to the lang and lid
"""
return session.query(tables.Locale).filter_by(LANG=lang, TEXT_ID=lid).one().TEXT
def get_random_place() -> tables.Place:
"""
Returns a random place from the database.
:return: a Place object
"""
return random.choice(session.query(tables.Place).all())
def get_random_npc() -> tables.Npc :
"""
Returns a random npc from the database
:return: a Npc object
"""
return random.choice(session.query(tables.Npc).all())
def get_npc_random_trait_id(npc) -> int:
reactions = session.query(tables.Reaction).filter_by(NPC_ID=npc.NPC_ID).all()
def get_npc_random_trait_id(npc_id: int) -> int:
"""
Returns a random reaction for a given npc
:param npc_id: the npc to get the reaction from
:return: a reaction identified by it's trait id
"""
reactions = session.query(tables.Reaction).filter_by(NPC_ID=npc_id.NPC_ID).all()
reaction = random.choice(reactions)
return reaction.TRAIT_ID
def get_npc_random_answer(npc, QA_TYPE) -> tables.Answer :
answers = session.query(tables.Answer).filter_by(QA_TYPE=QA_TYPE,NPC_ID=npc.NPC_ID).all()
def get_npc_random_answer(npc_id:int, qa_type:int) -> tables.Answer :
"""
Returns a random answser from a given npc and question type
:param npc_id: the npc to get the answer from
:param qa_type: the type of the question
:return: an Answer object
"""
answers = session.query(tables.Answer).filter_by(QA_TYPE=qa_type,NPC_ID=npc_id.NPC_ID).all()
return random.choice(answers)
def get_random_question(QA_TYPE) -> tables.Answer :
answers = session.query(tables.Question).filter_by(QUESTION_TYPE=QA_TYPE).all()
def get_random_question(qa_type: int) -> tables.Question :
"""
Returns a random inspector question from a question type
:param qa_type: the type of the question
:return: a Question object
"""
answers = session.query(tables.Question).filter_by(QUESTION_TYPE=qa_type).all()
return random.choice(answers)
def get_trait_from_text(text):
def get_trait_from_text(text: str) -> int:
"""
Returns the trait_id from its text value
:param text: the text representation of the trait in any lang
:return: the trait_id linked to this text
"""
trait_lid = session.query(tables.Locale).filter_by(TEXT=text).one().TEXT_ID
return session.query(tables.Trait).filter_by(NAME_LID=trait_lid).one().TRAIT_ID
def get_trait_from_trait_id(trait_id):
def get_trait_from_trait_id(trait_id: int) -> tables.Trait:
"""
Gets a Trait object from a trait_id
:param trait_id: the id of the trait to search for
:return: a Trait object
"""
trait = session.query(tables.Trait).filter_by(TRAIT_ID=trait_id).one()
return trait
def get_reaction_description(lang,npc_id,trait_id):
def get_reaction_description(lang,npc_id,trait_id) -> str:
"""
Returns the description of the reaction of a given npc in the language specified by the parametter lang
:param lang: the language to return the description in
:param npc_id: the id of the npc to get the reaction description from
:trait_id: the trait associated to the reaction to get the description from
:return: the description in the given language
"""
desc_lid = session.query(tables.Reaction).filter_by(NPC_ID=npc_id,TRAIT_ID=trait_id).one().DESC_LID
return get_text_from_lid(lang,desc_lid)
def get_traits(lang):
def get_traits(lang: str) -> list:
"""
Returns the list of all possible reactions trait in the given language
:param lang: the lang to return the reactions traits in
:return: a list of string reprensentation of the reactions traits
"""
traits = []
for trait in session.query(tables.Trait).all():
traits.append(get_text_from_lid(lang,trait.NAME_LID))
return traits
return traits

View File

@ -34,45 +34,39 @@ with Session(engine) as session:
print(locale)
session.add(locale)
session.commit()
print("adding places")
for place in PLACES:
print(place)
session.add(place)
session.commit()
print("adding NPCS")
for npc in NPCS:
print(npc)
session.add(npc)
session.commit()
print("adding trait")
for trait in TRAITS:
print(trait)
session.add(trait)
session.commit()
print("adding questions")
for question in QUESTIONS:
print(question)
session.add(question)
session.commit()
print("adding answers")
for answer in ANSWERS:
print(answer)
session.add(answer)
session.commit()
print("adding reactions")
for reaction in REACTIONS:
print(reaction)
session.add(reaction)
session.commit()
session.commit()

View File

@ -4,6 +4,7 @@ from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class Locale(Base):
__tablename__ = 'T_LOCALE'
TEXT_ID = Column(Integer, primary_key=True)
@ -18,6 +19,7 @@ class Locale(Base):
def __str__(self):
return f"{self.TEXT_ID} {self.LANG} {self.TEXT}"
class Place(Base):
__tablename__ = 'T_PLACE'
PLACE_ID = Column(Integer, primary_key=True)
@ -31,6 +33,7 @@ class Place(Base):
def __str__(self):
return f"{self.PLACE_ID} {self.NAME_LID}"
class Question(Base):
__tablename__ = "T_QUESTION"
QUESTION_ID = Column(Integer, primary_key=True)
@ -46,6 +49,7 @@ class Question(Base):
def __str__(self):
return f"{self.QUESTION_ID} {self.QUESTION_TYPE} {self.TEXT_LID}"
class Answer(Base):
__tablename__ = "T_ANSWER"
ANSWER_ID = Column(Integer, primary_key=True)
@ -64,6 +68,7 @@ class Answer(Base):
def __str__(self):
return f"{self.ANSWER_ID} {self.QA_TYPE} {self.NPC_ID} {self.TEXT_LID}"
class Npc(Base):
__tablename__ = "T_NPC"
NPC_ID = Column(Integer, primary_key=True)
@ -76,6 +81,7 @@ class Npc(Base):
def __str__(self) -> str:
return f"{self.NPC_ID} {self.NAME_LID}"
class Trait(Base):
__tablename__ = "T_TRAIT"
TRAIT_ID = Column(Integer, primary_key=True)
@ -88,11 +94,12 @@ class Trait(Base):
def __str__(self) -> str:
return f"{self.TRAIT_ID} {self.NAME_LID}"
class Reaction(Base):
__tablename__ = "T_REACTION"
REACTION_ID = Column(Integer, primary_key=True)
NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"),primary_key=True)
TRAIT_ID = Column(Integer, ForeignKey("T_TRAIT.TRAIT_ID"),primary_key=True)
NPC_ID = Column(Integer, ForeignKey("T_NPC.NPC_ID"), primary_key=True)
TRAIT_ID = Column(Integer, ForeignKey("T_TRAIT.TRAIT_ID"), primary_key=True)
DESC_LID = Column(Integer, ForeignKey("T_LOCALE.TEXT_ID"))
LOCALE = relationship("Locale")
NPC = relationship("Npc")

View File

@ -5,16 +5,18 @@ from typing import Union
from truthseeker.logic.data_persistance.data_access import *
from truthseeker import APP
def random_string(length: int) ->str:
def random_string(length: int) -> str:
"""
This function create a random string as long as the lint passed as
This function create a random string as long as the lint passed as
parameter
:param length: the length of the random string to create
:return: a random string
"""
return "".join(random.choice(string.ascii_letters) for _ in range(length))
class Member:
"""
stores information related to the member of a given game
@ -23,28 +25,29 @@ class Member:
:attr TODO progress: TODO
:attr TODO results: TODO
"""
def __init__(self, username):
self.username = username
self.progress = 0
self.results = None
def __str__(self) -> str:
return "Member[username={}]".format(self.username)
return f"Member[username={self.username}]"
def __repr__(self) -> str:
return self.__str__()
class Game:
"""
The game info class stores all information linked to a active game
:attr str game_id: str, the game identifier of the game
:attr str game_id: the game identifier of the game
:attr owner Member: the player start created the game. It is also stored in self.members
:attr Member[] members: the members of the game
:attr bool has_started: TODO
:attr TODO gamedata: TODO
:attr TODO reaction_table: TODO
:attr bool has_started: status of the current game
:attr dict gamedata: data of the game (npcs, their text, their reactions and rooms placement)
:attr dict reaction_table: mapping of the npc_ids in the game to their reactions id
"""
def __init__(self):
@ -65,20 +68,22 @@ class Game:
self.owner = Member(username)
self.members.append(self.owner)
return self.owner
def generate_game_results(self) -> None:
def generate_game_results(self) -> dict:
"""
TODO + TODO RET TYPE
Create the final leaderboard of the game, containing all members score.
:return: a dictionnary representation of the leaderboard
"""
data = {}
npcs = data["npcs"] = {}
for npc_id in self.gamedata["npcs"]:
npcs[npc_id] = {}
npcs[npc_id]["name"] = self.gamedata["npcs"][npc_id]["name"]
traitId = self.reaction_table[npc_id]
trait = get_trait_from_trait_id(traitId)
npcs[npc_id]["reaction"] = get_text_from_lid("FR",trait.NAME_LID)
npcs[npc_id]["description"] = get_reaction_description("FR",npc_id,trait.TRAIT_ID)
trait_id = self.reaction_table[npc_id]
trait = get_trait_from_trait_id(trait_id)
npcs[npc_id]["reaction"] = get_text_from_lid("FR", trait.NAME_LID)
npcs[npc_id]["description"] = get_reaction_description("FR", npc_id, trait.TRAIT_ID)
player_results = data["player"] = {}
for member in self.members:
player_results[member.username] = member.results
@ -86,9 +91,9 @@ class Game:
def generate_data(self) -> None:
"""
TODO
Creates and sets the game's data (npcs, their text, their reactions and rooms placement)
"""
#TODO Get language from player
# TODO Get language from player
self.gamedata, self.reaction_table = generate_game_data("FR")
self.gamedata["game_id"] = self.game_id
@ -97,12 +102,12 @@ class Game:
Get a Member object from a username
:param username: the username of the member to search for
:return the member corresponding to the username, or None if none if found:
:return: the member corresponding to the username, or None if none if found:
"""
for member in self.members:
if member.username == username:
return member
def add_member(self, username: str) -> Union[Member, None]:
"""
Add a Member to the game
@ -116,18 +121,25 @@ class Game:
self.members.append(member)
return member
def get_npc_reaction(self, npc_id) -> None:
def get_npc_reaction(self, npc_id) -> bytes:
"""
TODO + TODO TYPES
Returns the reaction image of a npc, if found in the reaction table
:param npc_id: the id of the npc, to get the reactions from, must be in the current game
:return: the reaction image as bytes
"""
if npc_id not in self.reaction_table.keys():
if npc_id not in self.reaction_table:
return 0
reaction_id = self.reaction_table[npc_id]
return read_image(f"./truthseeker/static/images/npc/{npc_id}/{reaction_id}.png")
def get_player_results(self, responses: dict) -> None:
def get_player_results(self, responses: dict) -> Union[dict, None]:
"""
TODO + TODO RETTYPE
Checks the player's answers againts the reaction map.
Return None when a npc is not found in the reaction table, meaning an invalid npc was sent
:param responses: the player anwsers, a dictionnary of npc_id to the string representation of the npc's reaction
:return: a dictionnary of npc_id to a boolean, true if they got the correct answer, false if not.
"""
results = {}
try:
@ -138,26 +150,27 @@ class Game:
except:
return False
def has_finished(self) -> bool:
"""
Checks if the game has finished by checking if every Member has submitted answers
:return: True if the game has finished, else False
"""
for member in self.members:
if member.results == None : return False
if member.results is None:
return False
return True
def __str__(self) -> str:
return "Game[game_id={}, owner={}, members={}]".format(self.game_id, self.owner, self.members)
return f"Game[game_id={self.game_id}, owner={self.owner}, members={self.members}]"
def __repr__(self) -> str:
return self.__str__()
def create_game(owner: str) -> Game:
"""
This function creates a new game by creating a Game object and stores
This function creates a new game by creating a Game object and stores
it into the games_list dictionnary
:return: a new Game
@ -169,6 +182,7 @@ def create_game(owner: str) -> Game:
APP.games_list[game.game_id] = game
return game
def get_game(game_id: str) -> Union[Game, None]:
"""
Get a game from its ID
@ -181,6 +195,7 @@ def get_game(game_id: str) -> Union[Game, None]:
else:
return None
def check_username(username: str) -> bool:
"""
Check if a username is valid using a set of rules
@ -188,7 +203,7 @@ def check_username(username: str) -> bool:
:param username: the username to check
:return: True or False depending on if the rules are respected
"""
if not username:
return False
if not username.isalnum():
@ -197,44 +212,69 @@ def check_username(username: str) -> bool:
return False
if not len(username) < 16:
return False
return True
def generate_npc_text(npc: tables.Npc, lang: str) -> dict:
"""
Creates the dictionnary of a npc names and dialogs, it searches the npc's pool of answser for both question
types
:param npc: a Npc object
:param lang: the lang to get the text in
:return: a dictionnary object containing the npc's name and both answers
"""
data = {}
data["name"] = get_text_from_lid(lang, npc.NAME_LID)
data["QA_0"] = get_text_from_lid(lang, get_npc_random_answer(npc,0).TEXT_LID)
data["QA_1"] = get_text_from_lid(lang, get_npc_random_answer(npc,1).TEXT_LID)
data["QA_0"] = get_text_from_lid(lang, get_npc_random_answer(npc, 0).TEXT_LID)
data["QA_1"] = get_text_from_lid(lang, get_npc_random_answer(npc, 1).TEXT_LID)
return data
def generate_npc_reactions(npc: tables.Npc) ->list:
return get_npc_random_trait_id(npc)
def generate_place_data(npcs: list, places: list, lang: str) -> dict:
def generate_place_data(npc_list: list, places: list, lang: str) -> dict:
"""
Create the place dictionnary for a game, assigns two npc for each room given in the place_list
except the last one who will be alone :(
:param npcs_list: the list of all npcs in the game
:param place_list: the list of the given rooms
:param lang: the language to seach the name of the room in
:return: a dictionnary of place_id to an array of npc_id and a string of the room name
"""
data = {}
random.shuffle(npcs)
random.shuffle(npc_list)
for place in places:
placedata = data[str(place.PLACE_ID)] = {}
placedata["name"] = get_text_from_lid(lang,place.NAME_LID)
placedata["name"] = get_text_from_lid(lang, place.NAME_LID)
placedata["npcs"] = []
for _ in npcs:
placedata["npcs"].append(npcs.pop().NPC_ID)
if len(placedata["npcs"]) == 2: break
for _ in npc_list:
placedata["npcs"].append(npc_list.pop().NPC_ID)
if len(placedata["npcs"]) == 2:
break
return data
def generate_game_data(LANG):
def generate_game_data(lang: str) -> tuple[dict, dict]:
"""
Create the gamedata of a game for a given language, chooses 5 random npcs, generate their texts and reactions,
chooses 3 random rooms and places the npcs in them and chooses an inspector question for each type of question
availible in the Question Table.
:param lang: the lang to generate all the texts in
:return: two dictionnaries, one containing the game data, the second containing the reaction table
"""
data = {}
data["npcs"] = {}
reactions_table = {}
npcs = []
while len(npcs) != 5:
npc = get_random_npc()
if npc not in npcs :
if npc not in npcs:
npcs.append(npc)
for npc in npcs:
data["npcs"][str(npc.NPC_ID)] = generate_npc_text(npc,LANG)
reactions_table[str(npc.NPC_ID)] = generate_npc_reactions(npc)
data["npcs"][str(npc.NPC_ID)] = generate_npc_text(npc, lang)
reactions_table[str(npc.NPC_ID)] = get_npc_random_trait_id(npc)
places = []
while len(places) != 3:
@ -242,22 +282,43 @@ def generate_game_data(LANG):
if place not in places:
places.append(place)
data["rooms"] = generate_place_data(npcs,places,LANG)
data["rooms"] = generate_place_data(npcs, places, lang)
data["questions"] = {}
data["questions"]["QA_0"] = get_text_from_lid("FR",get_random_question(0).TEXT_LID)
data["questions"]["QA_1"] = get_text_from_lid("FR",get_random_question(1).TEXT_LID)
data["traits"] = get_traits(LANG)
data["questions"]["QA_0"] = get_text_from_lid("FR", get_random_question(0).TEXT_LID)
data["questions"]["QA_1"] = get_text_from_lid("FR", get_random_question(1).TEXT_LID)
data["traits"] = get_traits(lang)
return data, reactions_table
def read_image(path:str):
def read_image(path: str) -> bytes:
"""
Returns the byte representation of an image given its path
:param path: the path to the image
:return: the byte representation of the image, none if its not found or not readable
"""
try:
with open(path, "rb") as f:
return f.read()
with open(path, "rb") as file:
return file.read()
except IOError:
return None
def get_trait_id_from_string(trait):
def get_trait_id_from_string(trait: str) -> int:
"""
Returns the trait_id from its text value
:param text: the text representation of the trait in any lang
:return: the trait_id linked to this text
"""
return get_trait_from_text(trait)
def get_npc_image(npc_id):
def get_npc_image(npc_id: int):
"""
Returns the byte representation of the neutral image for an npc
:param npc_id: npc to get the neutral image from
:return: the byte representation of the image, none if its not found or not readable
"""
return read_image(f"./truthseeker/static/images/npc/{npc_id}/0.png")

View File

@ -1,5 +1,4 @@
import json
import flask
from truthseeker import APP
@ -11,7 +10,7 @@ routes_api = flask.Blueprint("api", __name__)
@routes_api.route("/createGame", methods=["GET", "POST"])
def create_game():
username = flask.request.values.get("username")
if username==None:
if username is None:
return {"error": 1, "msg": "username not set"}
if not game_logic.check_username(username):
return {"error": 1, "msg": "invalid username"}
@ -30,31 +29,31 @@ def create_game():
return response
@routes_api.route("/getGameMembers", methods=["GET", "POST"])
def getMembers():
def get_members():
if not flask.session:
return {"error": 1, "msg": "No session"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
response = {"error" : 0}
player_list = [member.username for member in game.members]
response["members"] = player_list
return response
@routes_api.route("/joinGame", methods=["GET", "POST"])
def join_game():
game_id = flask.request.values.get("game_id")
username = flask.request.values.get("username")
if game_id==None or username==None:
if game_id is None or username is None:
return {"error": 1, "msg": "username or game id not set"}
if not game_logic.check_username(username):
return {"error": 1, "msg": "invalid username"}
game = game_logic.get_game(game_id)
if game == None:
if game is None:
return {"error": 1, "msg": "game does not exist"}
if not game.add_member(username):
return {"error": 1, "msg": f"Username '{username}' already used in game {game.game_id}"}
@ -71,10 +70,10 @@ def is_owner():
if not flask.session:
return {"error": 0, "owner": False}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 0, "owner": False}
if not flask.session["is_owner"]:
if not flask.session["is_owner"]:
return {"error": 0, "owner": False}
return {"error": 0, "owner": True}
@ -84,7 +83,7 @@ def has_joined():
if not flask.session:
return {"error": 0, "joined": False}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 0, "joined": False}
return {"error": 0, "joined": True}
@ -95,7 +94,7 @@ def start_game():
if not flask.session["is_owner"]:
return {"error": 1, "msg": "you are not the owner of this game"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
if game.has_started:
return {"error": 1, "msg": "this game is already started"}
@ -109,35 +108,35 @@ def get_data():
if not flask.session:
return {"error": 1, "msg": "No session"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
response = {}
response["error"] = 0
response["gamedata"] = game.gamedata
return response
@routes_api.route("/getNpcImage", methods=["GET", "POST"])
def getNpcImage():
def get_npc_image():
npc_id = flask.request.values.get("npcid")
if npc_id is None:
return {"error": 1, "msg": "no npc was given"}
image = game_logic.get_npc_image(npc_id)
if image is None:
return {"error": 1, "msg": "npc not found"}
return {"error": 1, "msg": "npc not found"}
response = flask.make_response(image)
response.headers.set('Content-Type', 'image/png')
response.headers.set(
'Content-Disposition', 'attachment', filename=f'0.png')
'Content-Disposition', 'attachment', filename='0.png')
return response
@routes_api.route("/getNpcReaction", methods=["GET", "POST"])
def getNpcReaction():
def get_npc_reaction():
if not flask.session:
return {"error": 1, "msg": "No session"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
npc_id = flask.request.values.get("npcid")
@ -145,58 +144,59 @@ def getNpcReaction():
errors = ["npc not in game","error reading file"]
if image in [0,1]:
return {"error" :1, "msg": errors[image]} , 500
response = flask.make_response(image)
response.headers.set('Content-Type', 'image/png')
response.headers.set(
'Content-Disposition', 'attachment', filename=f'reaction.png')
'Content-Disposition', 'attachment', filename='reaction.png')
return response
@routes_api.route("/gameProgress", methods=["GET", "POST"])
def gameProgress():
def game_progress():
if not flask.session:
return {"error": 1, "msg": "No session"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
username = flask.session["username"]
game.get_member(username).progress += 1
APP.socketio_app.emit("gameprogress", [flask.session["username"]], room="game."+game.game_id)
return {"error": 0}
@routes_api.route("/submitAnswers", methods=["GET", "POST"])
def checkAnwser():
def check_anwser():
if not flask.session:
return {"error": 1, "msg": "No session"}
game = game_logic.get_game(flask.session["game_id"])
if game == None:
if game is None:
return {"error": 1, "msg": "this game doesn't exist"}
member = game.get_member(flask.session["username"])
if member.results != None:
if member.results is not None:
return {"error": 1, "msg": "answers already submitted for this member"}
playerResponses = flask.request.values.get("responses")
player_responses = flask.request.values.get("responses")
if playerResponses == None:
if player_responses is None:
return {"error": 1, "msg": "no responses were sent"}
results = game.get_player_results(json.loads(playerResponses))
if results == False:
results = game.get_player_results(json.loads(player_responses))
if results is False:
return {"error": 1, "msg": "invalid npc sent"}
member.has_submitted = True
member.results = results
if game.has_finished():
jsonGameResults = game.generate_game_results()
APP.socketio_app.emit("gamefinshed",jsonGameResults,room="game."+game.game_id)
#TODO desctruct game
if game.has_finished():
json_game_results = game.generate_game_results()
APP.socketio_app.emit("gamefinshed", json_game_results, room="game."+game.game_id)
del game
response = {"error": 0}
return response

View File

@ -10,12 +10,10 @@ from truthseeker.logic import game_logic
def connect(auth):
if not (auth and "game_id" in auth):
raise socketio.exceptions.ConnectionRefusedError("Invalid connection data passed")
game = game_logic.get_game(auth["game_id"])
if not game:
raise socketio.exceptions.ConnectionRefusedError("No game with this ID")
room = join_room("game."+auth["game_id"])
join_room(room)

View File

@ -1,33 +1,39 @@
import flask
routes_ui = flask.Blueprint("ui", __name__)
@routes_ui.route("/")
def index():
return flask.render_template("index.html")
@routes_ui.route("/privacy")
def privacy():
return flask.render_template("privacy.html")
@routes_ui.route("/licenses")
def licenses():
return flask.render_template("licenses.html")
@routes_ui.route("/legal")
def legal():
return flask.render_template("legal.html")
@routes_ui.route("/lobby/<game_id>")
def lobby(game_id):
# rendered by the javascript client-side
return flask.render_template("lobby.html",gameid=game_id)
return flask.render_template("lobby.html", gameid=game_id)
@routes_ui.route("/solo")
def solo():
return flask.render_template("game.html")
@routes_ui.route("/multi")
def multi():
return flask.render_template("game.html")