|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import json |
|
import random |
|
from datetime import datetime |
|
import numpy as np |
|
from gensim.models import KeyedVectors |
|
from hints import curiosity, hint |
|
from tracking import ( |
|
calculate_moving_average, |
|
calculate_tendency_slope, |
|
) |
|
from sentence_transformers import SentenceTransformer |
|
import warnings |
|
|
|
warnings.filterwarnings(action="ignore", category=UserWarning, module="gensim") |
|
|
|
|
|
|
|
class Semantrix: |
|
|
|
|
|
config_file_path = "config/lang.json" |
|
secret_file_path = "config/secret.json" |
|
data_path = "data/" |
|
|
|
|
|
class DictWrapper: |
|
def __init__(self, data_dict): |
|
self.__dict__.update(data_dict) |
|
|
|
|
|
def __init__(self, lang=0, model_type="SentenceTransformer"): |
|
|
|
|
|
with open(self.config_file_path, "r") as file: |
|
self.Config_full = json.load(file) |
|
|
|
|
|
with open(self.secret_file_path, "r") as file: |
|
self.secret = json.load(file) |
|
|
|
|
|
self.lang = lang |
|
|
|
|
|
self.model_type = model_type |
|
|
|
if self.lang == 1: |
|
self.model = KeyedVectors.load("config/w2v_models/eng_w2v_model", mmap="r") |
|
self.Config = self.DictWrapper(self.Config_full["ENG"]["Game"]) |
|
self.secret_dict = self.secret["ENG"] |
|
else: |
|
self.model = KeyedVectors.load("config/w2v_models/esp_w2v_model", mmap="r") |
|
self.Config = self.DictWrapper(self.Config_full["SPA"]["Game"]) |
|
self.secret_dict = self.secret["SPA"] |
|
|
|
|
|
if self.model_type == "SentenceTransformer": |
|
self.model_trans = KeyedVectors(768) |
|
|
|
self.model_st = SentenceTransformer( |
|
"sentence-transformers/paraphrase-multilingual-mpnet-base-v2" |
|
) |
|
|
|
|
|
with open(self.data_path + "ranking.txt", "w+") as file: |
|
file.write("---------------------------") |
|
|
|
|
|
def prepare_game(self, difficulty): |
|
|
|
|
|
self.secret_list = ( |
|
self.secret_dict["basic"] |
|
if difficulty <= 2 |
|
else self.secret_dict["advanced"] |
|
) |
|
|
|
|
|
self.secret = self.secret_list.pop(random.randint(0, len(self.secret_list) - 1)) |
|
self.secret = self.secret.lower() |
|
|
|
|
|
self.words = [self.Config.secret_word] |
|
|
|
|
|
self.scores = [10] |
|
|
|
|
|
if self.model_type == "SentenceTransformer": |
|
|
|
|
|
if self.secret not in self.model_trans.key_to_index.keys(): |
|
self.model_trans.add_vector( |
|
self.secret, |
|
self.model_st.encode(self.secret, convert_to_tensor=True).tolist(), |
|
) |
|
|
|
|
|
self.win = False |
|
self.n = 0 |
|
self.recent_hint = 0 |
|
self.f_dev_avg = 0 |
|
self.last_hint = -1 |
|
self.difficulty = difficulty |
|
|
|
|
|
if self.difficulty == 1: |
|
self.n = 3 |
|
|
|
|
|
def gen_rank(self, repeated): |
|
ascending_indices = np.argsort(self.scores) |
|
descending_indices = list(ascending_indices[::-1]) |
|
ranking_data = [] |
|
k = len(self.words) - 1 |
|
if repeated != -1: |
|
k = repeated |
|
|
|
ranking_data.append(["#" + str(k), self.words[k], self.scores[k]]) |
|
|
|
ranking_data.append("---------------------------") |
|
for i in descending_indices: |
|
if i == 0: |
|
continue |
|
ranking_data.append(["#" + str(i), self.words[i], self.scores[i]]) |
|
|
|
with open(self.data_path + "ranking.txt", "w+") as file: |
|
for item in ranking_data: |
|
file.write("%s\n" % item) |
|
|
|
|
|
def play_game(self, word): |
|
|
|
|
|
word = word.lower() |
|
|
|
|
|
if word == "give_up": |
|
text = ( |
|
"[lose]" |
|
+ self.Config.Feedback_9 |
|
+ self.secret |
|
+ "\n\n" |
|
+ self.Config.Feedback_10 |
|
) |
|
return text |
|
|
|
|
|
if word in self.words: |
|
repeated = self.words.index(word) |
|
else: |
|
repeated = -1 |
|
self.words.append(word) |
|
|
|
|
|
if word not in self.model.key_to_index.keys(): |
|
|
|
self.words.pop(len(self.words) - 1) |
|
feedback = ( |
|
"I don't know that word. Try again." |
|
if self.lang == 1 |
|
else "No conozco esa palabra. Inténtalo de nuevo." |
|
) |
|
feedback += ( |
|
"[rank]" + open(self.data_path + "ranking.txt", "r").read() |
|
if len(self.words) > 1 |
|
else "\n\n" |
|
) |
|
return feedback |
|
|
|
|
|
if ( |
|
self.model_type == "SentenceTransformer" |
|
and word not in self.model_trans.key_to_index.keys() |
|
): |
|
self.model_trans.add_vector( |
|
word, self.model_st.encode(word, convert_to_tensor=True).tolist() |
|
) |
|
|
|
|
|
if self.model_type == "word2vec": |
|
similarity = self.model.similarity(self.secret, word) |
|
else: |
|
similarity = self.model_trans.similarity(self.secret, word) |
|
|
|
log_similarity = np.log10((similarity if similarity > 0 else 0) * 10) |
|
score = round( |
|
np.interp( |
|
log_similarity, |
|
[0, np.log10(10)], |
|
[0, 10], |
|
), |
|
2, |
|
) |
|
|
|
|
|
if repeated == -1: |
|
self.scores.append(score) |
|
|
|
|
|
if score <= 2.5: |
|
feedback = self.Config.Feedback_0 + str(score) |
|
elif score > 2.5 and score <= 4.0: |
|
feedback = self.Config.Feedback_1 + str(score) |
|
elif score > 4.0 and score <= 6.0: |
|
feedback = self.Config.Feedback_2 + str(score) |
|
elif score > 6.0 and score <= 7.5: |
|
feedback = self.Config.Feedback_3 + str(score) |
|
elif score > 7.5 and score <= 8.0: |
|
feedback = self.Config.Feedback_4 + str(score) |
|
elif score > 8.0 and score < 10.0: |
|
feedback = self.Config.Feedback_5 + str(score) |
|
|
|
else: |
|
self.win = True |
|
feedback = "[win]" + self.Config.Feedback_8 |
|
self.words[0] = self.secret |
|
self.words.pop(len(self.words) - 1) |
|
self.scores.pop(len(self.scores) - 1) |
|
|
|
|
|
if score > self.scores[len(self.scores) - 2] and self.win == False: |
|
feedback += "\n" + self.Config.Feedback_6 |
|
elif score < self.scores[len(self.scores) - 2] and self.win == False: |
|
feedback += "\n" + self.Config.Feedback_7 |
|
|
|
|
|
|
|
if self.difficulty != 4: |
|
mov_avg = calculate_moving_average(self.scores[1:], 5) |
|
|
|
|
|
if len(mov_avg) > 1 and self.win == False: |
|
f_dev = calculate_tendency_slope(mov_avg) |
|
f_dev_avg = calculate_moving_average(f_dev, 3) |
|
|
|
|
|
if f_dev_avg[len(f_dev_avg) - 1] < 0 and self.recent_hint == 0: |
|
|
|
|
|
i = random.randint(0, len(self.Config.hint_intro) - 1) |
|
feedback += "\n\n[hint]" + self.Config.hint_intro[i] |
|
|
|
|
|
hint_text, self.n, self.last_hint = hint( |
|
self.secret, |
|
self.n, |
|
self.model_st, |
|
self.last_hint, |
|
self.lang, |
|
( |
|
self.DictWrapper(self.Config_full["ENG"]["Hint"]) |
|
if self.lang == 1 |
|
else self.DictWrapper(self.Config_full["SPA"]["Hint"]) |
|
), |
|
) |
|
feedback += "\n" + hint_text |
|
self.recent_hint = 3 |
|
|
|
if self.recent_hint != 0: |
|
self.recent_hint -= 1 |
|
|
|
|
|
self.gen_rank(repeated) |
|
|
|
|
|
feedback += "[rank]" + open(self.data_path + "ranking.txt", "r").read() |
|
|
|
|
|
if self.win: |
|
|
|
with open(self.data_path + "ranking.txt", "r") as original_file: |
|
file_content = original_file.readlines() |
|
|
|
new_file_name = self.secret + "_" + str(datetime.now()) + ".txt" |
|
|
|
with open(self.data_path + "plays/" + new_file_name, "w+") as new_file: |
|
new_file.writelines(file_content[2:]) |
|
|
|
|
|
return feedback |
|
|
|
|
|
def curiosity(self): |
|
|
|
|
|
feedback = curiosity( |
|
self.secret, |
|
( |
|
self.DictWrapper(self.Config_full["ENG"]["Hint"]) |
|
if self.lang == 1 |
|
else self.DictWrapper(self.Config_full["SPA"]["Hint"]) |
|
), |
|
) |
|
|
|
|
|
return feedback |
|
|