83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
import sys
|
|
import numpy as np
|
|
from gensim.models import KeyedVectors
|
|
import random
|
|
|
|
TOLERANCE = 1e-4 # tolérance sur la similarité cosinus
|
|
|
|
if len(sys.argv) < 3:
|
|
print("Usage: python cemantle.py <mot> <score>")
|
|
sys.exit(1)
|
|
|
|
first_word = sys.argv[1].lower()
|
|
first_score = float(sys.argv[2]) / 100
|
|
|
|
# Détection de la langue
|
|
lang = sys.argv[3] if len(sys.argv) > 3 else "en"
|
|
if lang == "fr":
|
|
TOLERANCE = 1e-2
|
|
with open("french_words.txt") as f:
|
|
valid_words = set(w.strip() for w in f)
|
|
print("Mode français : dictionnaire français chargé.")
|
|
model_path = "frWac_non_lem_no_postag_no_phrase_200_cbow_cut0.bin"
|
|
print("Chargement du modèle français (frWac cut100)...")
|
|
model = KeyedVectors.load_word2vec_format(model_path, binary=True)
|
|
else:
|
|
with open("english_words.txt") as f:
|
|
valid_words = set(w.strip() for w in f)
|
|
print("Mode anglais : dictionnaire anglais chargé.")
|
|
model_path = "GoogleNews-vectors-negative300.bin.gz"
|
|
print("Chargement du modèle anglais...")
|
|
model = KeyedVectors.load_word2vec_format(model_path, binary=True)
|
|
|
|
if first_word not in model:
|
|
print(f"Mot inconnu du modèle: {first_word}")
|
|
sys.exit(1)
|
|
|
|
# Calculer la similarité cosinus entre deux vecteurs
|
|
cos = lambda a, b: np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
|
|
|
|
def is_valid_word(word):
|
|
if lang == "fr":
|
|
return word.islower() and all(c.isalpha() for c in word) and word in valid_words and 3 <= len(word) <= 15
|
|
else:
|
|
return word.islower() and word.isalpha() and word in valid_words and 3 <= len(word) <= 15
|
|
|
|
# Filtrer les mots à la bonne distance du mot donné, et qui sont valides
|
|
vec1 = model[first_word]
|
|
words = []
|
|
for w in model.index_to_key:
|
|
if w == first_word:
|
|
continue
|
|
if not is_valid_word(w):
|
|
continue
|
|
sim = cos(vec1, model[w])
|
|
if abs(sim - first_score) < TOLERANCE:
|
|
words.append(w)
|
|
|
|
print(f"{len(words)} mots à la distance {first_score*100:.2f} de '{first_word}' (valides)")
|
|
|
|
while words:
|
|
guess = random.choice(words)
|
|
print(f"Try: {guess}")
|
|
s = input("Score: ")
|
|
if s == "n":
|
|
words.remove(guess)
|
|
print(f"Mot refusé, {len(words)} restants.")
|
|
continue
|
|
try:
|
|
score = float(s) / 100
|
|
except ValueError:
|
|
print("Entrée invalide, recommencez.")
|
|
continue
|
|
vec_guess = model[guess]
|
|
# Filtrer les mots à la bonne distance du guess
|
|
words = [w for w in words if abs(cos(vec_guess, model[w]) - score) < TOLERANCE]
|
|
print(f"{len(words)} mots restants à la distance {score*100:.2f} de '{guess}'")
|
|
|
|
if not words:
|
|
print("Plus aucun mot possible. Terminé.")
|
|
break
|
|
if len(words) == 1:
|
|
print(f"Plus qu'un seul mot possible: {words[0]}")
|
|
break
|