Compare commits

..

No commits in common. "main" and "9dbc9fc89d2a77262fe60ee2ea3949288f8ce541" have entirely different histories.

5 changed files with 149680 additions and 204 deletions

View File

@ -1,17 +1,16 @@
# wgamesolv # wgamesolv
Words Games Solver. Words Games Solver.
Script d'aide à la résolution des jeux de mots style Wordle, SUTOM, mots-croisés, Scrabble... Script d'aide à la résolution des jeux de mots style wordle
On a fait ça pour s'amuser, pas spécialement pour tricher aux jeux de mots.
Auteurs : AntoineVe et Brunus.
Courageux testeur des 1ères versions et précieux apporteur d'idées: DarKou.
Licence : MIT
Utilisation : wgamesolv.py -d dictionnaire.json -nb 7 (autres options) Utilisation : wgamesolv.py -fl L -nb 7 (autres options)
-d, --dictionary : dictionnaire à utiliser -d, --dictionary : dictionnaire à utiliser
ex : -d fr_Fc.json ex : -d SutomList.json
Trois dictionnaires ont été fusionnés pour n'en faire qu'un : Wordle, SUTOM et l'officiel du Scrabble Les dictionnaires sont récupérables ici :
https://framagit.org/JonathanMM/sutom/-/blob/main/ts/mots/listeMotsProposables.ts
Et :
https://raw.githubusercontent.com/LouanBen/wordle-fr/main/mots.txt
-fl, --firstLetter : première lettre du mot -fl, --firstLetter : première lettre du mot
ex : -fl C ex : -fl C
@ -23,7 +22,7 @@ ex : -nb 7
-ft, --firstTry : optimise le premier essai en sortant les mots de -nb lettres, commençant par -fl lettre, ne contenant aucune lettre en plusieurs occurence et contenant -ft voyelles. -ft, --firstTry : optimise le premier essai en sortant les mots de -nb lettres, commençant par -fl lettre, ne contenant aucune lettre en plusieurs occurence et contenant -ft voyelles.
ex : -ft 4 ex : -ft 4
Cette option peut être utilisée pour le tout premier essai, pour optimiser les chances d'avoir des lettres validées. Cette option peut être utilisée pour le tout premier essai, pour optimiser les chances d'avoir des lettres validées.
Cette option est ensuite inutile ou contre-productive pour les essais suivants et ne peut pas être utilisée avec la pattern. Cette option est ensuite inutile ou contre-productive pour les essais suivants.
-nd, --noDoubleLetters : filtre les mots composé d'une seule occurence de chaque lettre. -nd, --noDoubleLetters : filtre les mots composé d'une seule occurence de chaque lettre.
@ -33,8 +32,7 @@ ex : -kl AEP
-bl, --badLetters : lettres déjà invalidées -bl, --badLetters : lettres déjà invalidées
ex : -bl ZTOR ex : -bl ZTOR
-p, --pattern : lettres validées et bien placées, lettres connues et mal placées, séparée par des '.' pour les lettres non validées -p, --pattern : lettres validées et bien placées, séparée par des '.' pour les lettres non validées
Les lettres en caps sont les lettres connues et bien placées, les lettres en minuscules sont les lettres connues mais mal placées ex : -p L..I... (le mots était LUCIOLE)
ex : -p L.uI... (le mots était LUCIOLE)
Exemple complet : wgamesolv.py -d fr_FR.json -nb 7 -fl L -p L.uI... -kl U -bl AMNR Exemple complet : wgamesolv.py -d SutomList.json -nb 7 -fl L -p L..I... -kl E -bl AMNR

149442
SutomList.json Normal file

File diff suppressed because it is too large Load Diff

1
WordleList.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,204 +1,240 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys
import json import json
import argparse import argparse
from random import shuffle
parser = argparse.ArgumentParser(
def load_dict(dict_file):
try:
with open(dict_file, "r") as dico:
liste = json.load(dico)
return liste
except Exception as error:
print(f"Impossible d'ouvrir le fichier {dict_file} : {error}")
exit(2)
def noDouble(mots):
# Fonction d'élimination de mots contenant plusieurs occurences de lettres
ndList = []
for mot in mots:
if len(list(mot)) == len(set(list(mot))):
ndList.append(mot)
return ndList
def firstTryFilter(mots, max_mots, pattern):
'''
First Try : sélectionne des mots ayant des chances de valider ou invalider
l'une des lettres les plus utilisée en français.
'''
if pattern:
return mots # Inhibe le filtre si on utilise aussi un pattern
else:
bestLetters = ['E', 'A', 'I', 'R', 'S', 'N', 'T', 'O', 'L', 'U']
bestWords = []
shuffle(mots)
mots = mots[:100]
for mot in mots:
for bestLetter in bestLetters:
if bestLetter in mot:
bestWords.append(mot)
bestWords = list(set(bestWords))
bestWords_noDouble = noDouble(bestWords) # Autant maximiser les chances
if len(bestWords_noDouble) > 0:
bestWords = bestWords_noDouble
bestWords = bestWords[:max_mots]
return bestWords
def resolv_fl(liste, firstletter):
# On ne garde que les mots qui commence par FirstLetter
firstletter = firstletter.upper()
return [mot for mot in liste if mot[0] == firstletter]
def resolv_len(liste, lenght):
# On ne garde que les mots qui ont la bonne longueur
return [mot for mot in liste if len(mot) == lenght]
def resolv_pattern(liste, pattern):
# Pattern : élimination des mots ne satisfaisant pas la pattern
pattern_dict, not_pattern_dict = {}, {}
for lettre in pattern:
if lettre != "." and lettre.isupper():
pattern_dict.update({pattern.index(lettre): lettre})
if lettre != "." and lettre.islower():
not_pattern_dict.update({pattern.index(lettre): lettre.upper()})
MotsOK, MotsKO = [], []
for mot in liste:
for key in pattern_dict:
if mot[key] == pattern_dict[key]:
MotsOK.append(mot)
else:
MotsKO.append(mot)
for key in not_pattern_dict:
if mot[key] == not_pattern_dict[key]:
MotsKO.append(mot)
MotsKO = set(MotsKO)
liste = [mot for mot in MotsOK if mot not in MotsKO]
liste = list(set(liste))
return liste
def resolv_kl(liste, lettres):
'''
Known Letters : élimination des mots ne comprenant pas
les lettres validées (hors pattern)
'''
lettres = list(set(list(lettres.upper())))
MotsRestants = []
for mot in liste:
if len(set(lettres).intersection(mot)) == len(lettres):
MotsRestants.append(mot)
return MotsRestants
def resolv_bl(liste, lettres):
'''
Bad Letters : élimination des mots contenant
des lettres invalidées (hors pattern)
'''
lettres = list(set(list(lettres.upper())))
MotsSuppr = []
for mot in liste:
for lettre in lettres:
if lettre in mot:
MotsSuppr.append(mot)
return [mot for mot in liste if mot not in MotsSuppr]
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description='Cheating with SUTOM' description='Cheating with SUTOM'
) )
parser.add_argument( parser.add_argument(
'-d', '-d',
'--dictionary', '--dictionary',
help='Dictionnaire des mots du jeu', help='Dictionnaire des mots du jeu',
required=True required=True
) )
parser.add_argument( parser.add_argument(
'-fl', '-fl',
'--firstLetter', '--firstLetter',
help='Première lettre', help='Première lettre',
default=False required=True
) )
parser.add_argument( parser.add_argument(
'-nb', '-nb',
'--nbLetters', '--nbLetters',
type=int, type=int,
help='Nombre de lettres, un entier', help='Nombre de lettres, un entier',
default=False,
required=True required=True
) )
parser.add_argument( parser.add_argument(
'-kl', '-kl',
'--knownLetters', '--knownLetters',
default=False,
help='Lettres connues, hors première, sans espaces : -kl BE' help='Lettres connues, hors première, sans espaces : -kl BE'
) )
parser.add_argument( parser.add_argument(
'-bl', '-bl',
'--badLetters', '--badLetters',
default=False,
help='Lettres non valides, sans espaces : -bl AKL' help='Lettres non valides, sans espaces : -bl AKL'
) )
parser.add_argument( parser.add_argument(
'-p', '-p',
'--pattern', '--pattern',
default=False, help='Placement, avec des "." pour les inconnues : -p A...T.I.'
help='Placement : bien placée en majuscule, mal placée en minuscule et non existante par un \'.\'. E.g. : Ra..e.T' )
) parser.add_argument(
parser.add_argument(
'-nd', '-nd',
'--noDoubleLetters', '--noDoubleLetters',
help="Option pour ne chercher que des mots ne contenant qu'une occurence de chaque lettre", help="Option pour ne chercher que des mots ne contenant qu'une occurence de chaque lettre",
default=False,
action="store_true" action="store_true"
) )
parser.add_argument( parser.add_argument(
'-ft', '-ft',
'--firstTry', '--firstTry',
default=False,
type=int, type=int,
help="Sélectionne des mots commençants par firstLetter et composés de ft voyelles différentes: -ft 4", help="Sélectionne des mots commençants par firstLetter et composés de ft voyelles différentes: -ft 4",
) )
args = parser.parse_args() if not len(sys.argv) > 1:
print("-h or --help pour afficher l'aide")
exit(1)
if args.pattern and args.nbLetters and len(args.pattern) != args.nbLetters: args = parser.parse_args()
# Dictionary
if args.dictionary:
try :
with open(args.dictionary, "r") as dico:
liste = json.load(dico)
except:
print("Impossible d'ouvrir le fichier" + fp)
# First Letter
if args.firstLetter:
fl = args.firstLetter
else:
fl = False
# Nbr Letters
if args.firstLetter:
nb = args.nbLetters
else:
nbLetters = False
# Pattern
if args.pattern:
pattern = args.pattern
if args.nbLetters and len(pattern) != nb:
print("Tu as merdé ta pattern petit scarabé !") print("Tu as merdé ta pattern petit scarabé !")
exit(2) exit(2)
else:
pattern = False
liste = load_dict(args.dictionary) # Known Letters
liste = resolv_len(liste, args.nbLetters) if args.knownLetters:
if args.firstLetter: kl = args.knownLetters
liste = resolv_fl(liste, args.firstLetter) else:
if args.pattern: kl = False
liste = resolv_pattern(liste, args.pattern)
if args.noDoubleLetters: # Bad Letters
liste = noDouble(liste) if args.badLetters:
if args.knownLetters: bl = args.badLetters
liste = resolv_kl(liste, args.knownLetters) else:
if args.badLetters: bl = False
liste = resolv_bl(liste, args.badLetters)
if args.firstTry: # No Double
liste = firstTryFilter(liste, args.firstTry, args.pattern) if args.noDoubleLetters:
if len(liste) == 1: nd = True
print(f"Essaie : \"{liste[0]}\"") else: nd = False
elif len(liste) > 1:
print(f"Mots à tester : {liste}") # First Try
if args.firstTry:
ft = args.firstTry
else: ft = False
patternFilter = []
klFilter = []
blFilter = []
ftFilter = []
# Fonction d'élimination de mots contenant plusieurs occurences de lettres
def noDouble(mots):
ndList = []
for mot in mots:
llist = []
for l in mot:
if not l in llist:
llist.append(l)
if len(mot) == len(llist):
ndList.append(mot)
return(ndList)
# First Try : sélectionne des mots ayant des chances de valider ou invalider des voyelles
def firstTryFilter(mots, ft):
vLetters = ['A', 'E', 'I', 'O', 'U', 'Y']
bestWords = []
for mot in mots:
vCount = 0
for l in mot:
if l in vLetters:
vCount +=1
if vCount >= ft:
bestWords.append(mot)
return(bestWords)
# Fonction de comparaison des lettres d'un mot, avec celle de la pattern
# Plus nécessaire actuellement mais peut être dans une prochaine vie
'''
def patternCheck(pattern, mot, l):
goodPosCounter = 0
for pos in range(len(pattern)):
print("Checking : " + l + "against : " + pattern[pos] + " and " + mot[pos])
if pattern[pos] == l and mot[pos] == l:
goodPosCounter +=1
print("checked")
if goodPosCounter == pattern.count(l):
return(0)
else: else:
print("Hmmm... Je crois qu'on s'est perdu...") return(1)
exit(0) '''
if len(liste) > 1:
print(liste) # First Letter : élimination des mots ne commençant pas par FirstLetter
print(f"Il y a {len(liste)} mots dans la liste") if fl:
elif len(liste) == 1: goodFl = [mot for mot in liste if mot.startswith(fl)]
print(f"La solution est \"{liste[0]}\".")
# Nb Lettres : élimination des mots n'ayant pas le bon nombre de lettres
if fl:
goodLen = [mot for mot in goodFl if len(mot) == nb]
else:
goodLen = [mot for mot in liste if len(mot) == nb]
# First Try
if ft:
bestWords = noDouble(firstTryFilter(goodLen, ft))
# Pattern : élimination des mots ne satisfaisant pas la pattern
if pattern:
patternCount = len(pattern) - pattern.count(".")
for mot in goodLen:
patternEval = 0
for l in range(len(mot)):
if mot[l] == pattern[l]:
patternEval += 1
if patternEval == patternCount :
patternFilter.append(mot)
# Known Letters : élimination des mots ne comprenant pas les lettres validées (hors pattern)
if kl:
if patternFilter:
mots = patternFilter
else: else:
print("Hmmm... Je crois qu'on s'est perdu...") mots = goodLen
for mot in mots:
validate = 0
for l in kl:
if l in mot:
validate += 1
if validate == len(kl):
klFilter.append(mot)
# Bad Letters : élimination des mots contenant des lettres invalidées (hors pattern)
if bl:
if klFilter:
mots = klFilter
elif patternFilter:
mots = patternFilter
else:
mots = goodLen
for mot in mots:
invalidate = 0
for l in bl:
if l in mot and l in pattern:
if pattern.count(l) != mot.count(l):
invalidate += 1
elif l in mot:
invalidate += 1
if invalidate == 0:
blFilter.append(mot)
# Affiche du résultat
if pattern and kl and bl:
print(", ".join(blFilter))
print(str(len(blFilter)) + " mots dans la liste" )
elif pattern and kl:
print(", ".join(klFilter))
print(str(len(klFilter)) + " mots dans la liste" )
elif pattern:
print(", ".join(patternFilter))
print(str(len(patternFilter)) + " mots dans la liste" )
elif kl and bl:
print(", ".join(blFilter))
print(str(len(blFilter)) + " mots dans la liste" )
elif bl and pattern:
print(", ".join(blFilter))
print(str(len(blFilter)) + " mots dans la liste" )
elif ft:
print(", ".join(bestWords))
print(str(len(bestWords)) + " mots dans la liste" )
else:
print(", ".join(goodLen))
print(str(len(goodLen)) + " mots dans la liste" )