Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Tricher au scrabble...

36 views
Skip to first unread message

Dominique

unread,
Nov 28, 2023, 5:33:42 AM11/28/23
to
Bonjour,

Je m'amuse à faire un logiciel de triche au Scrabble. J'ai bien les
presque 350 000 mots en français au format txt.

Voici mes débuts :

-----------------------------------------
f=open('/home/USER/dico.txt')
scrabble=dict()
for i in f:
j=i[:-1]
mot=list(j)
mot.sort()
mot=''.join(mot)
scrabble[str(mot)]=j
del (mot)
del (i)
del(j)
del (f)
print('Création du dictionnaire terminée')

test='xx'
while test=='xx':
lettres=input('Lettres ')
lettres=list(lettres)
lettres.sort()
lettres=''.join(lettres)
if lettres!='xx':
if lettres in scrabble.keys():
print(scrabble[lettres])
else:
test=9
-----------------------------------------

Ce script fonctionne en deux blocs. Le premier, qui ne tourne qu'une
fois, charge le dico.text. Il parcourt chaque mot, le transforme en
liste, met les lettre par ordre alpha croissant, reconstitue un string
avec join. Il affecte comme values à cette keys le mot d'origine j.

Le deuxième bloc me demande mes lettres, les transforme en liste, les
classe par ordre alpha, reconstitue un string et voit si cette variable
existe en keys dans mon dictionnaire scrabble, ce à quoi il me donne la
values correspondant.

Il répond à la question, dès lors que les lettres que je lui soumets
existent à l'identique en clef. J'ai des limites. Par exemple, avec les
lettre aberv, il me proposera brave mais pas baver.

La vraie limite vient de ce que je ne vois pas trop comment faire pour
que l'application cherche un mot avec mes 7 lettres, en cas d'échec,
avec 6 lettres etc. Je pense que je pourrais utiliser les outils
d'itertools (combination ou permutations. mais j'ai peur que les temps
de traitements deviennent très longs...

Comment verriez-vous les choses ?

Merci et belle journée à vous tous,

--
Dominique
Esto quod es

Dominique

unread,
Nov 28, 2023, 10:39:45 AM11/28/23
to
Le 28/11/2023 à 12:30, Stefan Ram a écrit :
> Dominique <dominiqu...@orange.fr.invalid> writes:
>> del (mot)
>
> Tout d'abord, juste une remarque sur ce qui est cité ci-dessus :
>
> Au lieu de « del(x) », on peut souvent écrire simplement
> « del x », sans les parenthèses.
>
> Ensuite, on peut souvent remplacer
>
> x = 1
> print( x )
> del x
>
> par
>
> def ecris_1():
> x = 1
> print( x )
>
> ecris_1()
>
> . Cela comprend certes plus de lignes, mais correspond
> probablement plus au style habituel. La variable « x »
> n'existe plus non plus après cela.
>
>

Effectivement, par une fonction, les variables disparaissent après
exécution. Merci pour le rappel :)

Dominique

unread,
Nov 28, 2023, 10:43:52 AM11/28/23
to
Le 28/11/2023 à 13:22, Stefan Ram a écrit :

>
> Il y a encore une remarque à faire sur le style de programmation :
> si un script est composé de deux blocs, il sera plus clair
> pour le lecteur si chaque bloc est défini comme une fonction
> et nommé par sa tâche.

J'y ai bien pensé, mais le premier bloc n'est exécuté qu'une fois, lors
de la création du dictionnaire. Je n'ai pas jugé utile de faire une
fonction...

Je testerai le listing que tu me proposes dès que j'ai un peu de temps.
Merci pour cette approche :)

yves

unread,
Nov 28, 2023, 11:05:22 AM11/28/23
to
Le Tue, 28 Nov 2023 11:33:38 +0100, Dominique a écrit:

> Bonjour,
>
> Je m'amuse à faire un logiciel de triche au Scrabble. J'ai bien les
> presque 350 000 mots en français au format txt.
>
> Voici mes débuts :
>
> -----------------------------------------
> f=open('/home/USER/dico.txt')
> scrabble=dict()
> for i in f:
> j=i[:-1]
> mot=list(j)
> mot.sort() mot=''.join(mot) scrabble[str(mot)]=j
> del (mot)
> del (i)
> del(j)
> del (f)
> print('Création du dictionnaire terminée')


> Comment verriez-vous les choses ?

J'aime bien cogiter sur du concret limpide.

Un petit exemple minimal pour la partie "création de dictionnaire" :

En entrée :
dico.txt :

pomme
fraise
orange

En sortie :
le dictionnaire scrabble :

{'emmop': 'pomme', 'aefirs': 'fraise', 'aegnor': 'orange'}

@+
--
Yves

yves

unread,
Nov 28, 2023, 11:17:32 AM11/28/23
to
Le 28 Nov 2023 16:05:20 GMT, yves a écrit:

> Un petit exemple minimal pour la partie "création de dictionnaire" :

Encore mieux:

En entrée :
dico.txt :

pomme
fraise
orange
brave
baver

En sortie :
le dictionnaire scrabble :

{'emmop': 'pomme', 'aefirs': 'fraise', 'aegnor': 'orange', 'aberv':
'baver'}

@+
--
Yves

Michel

unread,
Nov 28, 2023, 12:01:06 PM11/28/23
to
Le 28 novembre 2023 Dominique a écrit :

> if lettres in scrabble.keys():
> print(scrabble[lettres])

De passer par un dict ça impose que tu n'auras toujours qu'un seul mot
fourni pour un ensemble de lettres. Je ne pense pas que ce soit le mieux
pour jouer. Et de plus si tu as des lettres supplémentaires qui ne
rentrent pas dans un mot tu n'obtiendras aucun résultat.

Michel

unread,
Nov 28, 2023, 1:26:05 PM11/28/23
to
Le 28 novembre 2023 Stefan Ram a écrit :

> Voici une approche possible (sans essayer d'optimiser quoi que ce
> soit) :

J'ai optimisé ton algo en passant par un dictionnaire pour chaque
longueur de mot. Ca permet de limiter les parcours sur le sous-ensemble.
Ca accélère nettement quand on a plein de lettres qui ne collent pas, et
donc qu'on doit chercher plusieurs longueurs.


# apt install wfrench
fichier = '/usr/share/dict/french'

# on suppose que les mots font 27 caractères maxi
# (désinstitutionnalisassions)
MAX = 27

tests = [ 'emmop', 'aefirs', 'aegnor', 'aberv',
'axy', 'emmo', 'emmop', 'emmoepat', 'emoepat',
'aefirs', 'aegnor', 'aegnorer' ]

def possible( mot, mes_lettres ):
'''
les lettres de mes_lettres sont-elles suffisantes pour former le mot ?
'''
for lettre in mot:
if mot.count(lettre) > mes_lettres.count(lettre):
return False
return True

def mots_possibles( dictionnaire, mes_lettres ):
'''
Tous les mots du dictionnaire et qui
peuvent être formés avec les lettres du « mes_lettres ».
'''
résultat = []
for mot in dictionnaire:
if possible(mot, mes_lettres):
résultat.append(mot)
return résultat

def mots_de_longueur_maximale( dictionnaire, mes_lettres ):
'''
Trouve dans le dictionnaire des mots de longueur maximale qui
peuvent être formés avec les lettres indiquées.
'''
for longueur in range( len( mes_lettres ), 1, -1 ):
résultat = mots_possibles( dictionnaire[longueur], mes_lettres )
if résultat: return résultat
return []

def charge_dico():
'''
on passe par une array par longueur de mot
pour lors de la recherche ne parcourir que N mots
au lieu de N x longueurs recherchées
ça augmente le temps de chargement mais
ça divise le temps de recherche par 10
'''
dictionnaire = [[] for i in range(MAX + 1)]
with open(fichier, 'r') as fp:
while line := fp.readline().rstrip():
dictionnaire[len(line)].append(line)
return dictionnaire

dictionnaire = charge_dico()

for lettres in tests:
print(f'{lettres:8s}:', mots_de_longueur_maximale(dictionnaire, lettres))

yves

unread,
Nov 28, 2023, 3:16:51 PM11/28/23
to
Le 28 Nov 2023 16:19:20 GMT, Stefan Ram a écrit:

> dico = 'pomme', 'fraise', 'orange'
> scrd ={ ''.join( sorted( mot )) : mot for mot in dico }
> print( scrd )

ah oui, ça c'est du concis.

Sympathique :

print(sorted('citron')

Résultat :
['c', 'i', 'n', 'o', 'r', 't']

Mais pas facile à décrypter avant d'avoir bien étudié cette syntaxe.

avec la version étendue, on constate aussi la limite de l'approche par ce
dictionnaire :

dico = 'pomme', 'fraise', 'orange', 'baver', 'brave'
scrd ={ ''.join( sorted( mot )) : mot for mot in dico }
print( scrd )


{'emmop': 'pomme', 'aefirs': 'fraise', 'aegnor': 'orange', 'aberv':
'brave'}

Comme ça :
srcd1 = {mot : ''.join( sorted( mot )) for mot in dico}
print(srcd1)

Résultat:

{'pomme': 'emmop', 'fraise': 'aefirs', 'orange': 'aegnor', 'baver':
'aberv', 'brave': 'aberv'}

Ensuite, il reste à écrire le code pour faire une inversion key/value qui
traite le cas des anagrammes.

@+
--
Yves

Dominique

unread,
Nov 28, 2023, 11:55:08 PM11/28/23
to
C'est exactement ce que j'ai fait:)

Dominique

unread,
Nov 28, 2023, 11:57:20 PM11/28/23
to
Je sais, et c'est bien là ma limite :)

yves

unread,
Dec 1, 2023, 12:39:09 PM12/1/23
to
Le Tue, 28 Nov 2023 16:43:50 +0100, Dominique a écrit:

>> Il y a encore une remarque à faire sur le style de programmation :
>> si un script est composé de deux blocs, il sera plus clair pour le
>> lecteur si chaque bloc est défini comme une fonction et nommé par sa
>> tâche.
>
> J'y ai bien pensé, mais le premier bloc n'est exécuté qu'une fois, lors
> de la création du dictionnaire. Je n'ai pas jugé utile de faire une
> fonction...
>
> Je testerai le listing que tu me proposes dès que j'ai un peu de temps.
> Merci pour cette approche

J'ai séché aujourd'hui sur un problème wordle qui s'apparentait pour le
coup à un problème de scrabble.

Du coup, j'ai réimplémenté quelques idées de ce fil de façon très brute,
et j'ai été surpris par la rapidité de traitement.

Voici un exemple, avec une séquence de lettres qui a de nombreux
anagrammes :


dictionnaire = "/usr/share/dict/french"
with open(dictionnaire) as f:
b= [mot.rstrip() for mot in f.readlines()]
c= [mot for mot in b if sorted(mot) == sorted("acenrt")]

print(len(b))
print(len(c))
print(c)
print('terminé')


#+RESULTS:
: 346200
: 9
: ['canter', 'cantre', 'carnet', 'centra', 'crante', 'encart', 'nectar',
'tancer', 'tanrec']
: terminé



@+
--
Yves

yves

unread,
Dec 1, 2023, 12:56:42 PM12/1/23
to
Le 01 Dec 2023 17:39:07 GMT, yves a écrit:

> Voici un exemple, avec une séquence de lettres qui a de nombreux
> anagrammes :

Encore plus concis, la ligne va sans doute être coupé par les lecteurs de
news:

dictionnaire = "/usr/share/dict/french"
with open(dictionnaire) as f:
resultat = [mot.rstrip() for mot in f.readlines() if
sorted(mot.rstrip()) == sorted("acenrt")]

print(resultat)
print('terminé')


#+RESULTS:
: ['canter', 'cantre', 'carnet', 'centra', 'crante', 'encart', 'nectar',
'tancer', 'tanrec']
: terminé


0.4 secondes sur mon ordi, quand même.


@+
--
Yves

Michel

unread,
Dec 1, 2023, 9:51:04 PM12/1/23
to
Le 1 décembre 2023 yves a écrit :

> dictionnaire = "/usr/share/dict/french"
> with open(dictionnaire) as f:
> resultat = [mot.rstrip() for mot in f.readlines() if
> sorted(mot.rstrip()) == sorted("acenrt")]

Pour les anagrammes c'est bon mais pour le scrabble on peut avoir des
lettres qui ne seraient pas utilisées et donc cet algo ne marcherait pas.

> 0.4 secondes sur mon ordi, quand même.

Sur le mien 0.280. Mais en reprenant le même principe que pour le
scrabble, en chargeant le fichier dans une array par longueur de mot,
j'obtiens 0.170.

fichier = "/usr/share/dict/french"

# on suppose que les mots font 27 caractères maxi
# (désinstitutionnalisassions)
MAX = 27

def charge_dico():
dictionnaire = [[] for i in range(MAX + 1)]
with open(fichier, 'r') as fp:
while line := fp.readline().rstrip():
dictionnaire[len(line)].append(line)
return dictionnaire

def recherche(lettres, dictionnaire):
resultat = [mot for mot in dictionnaire[len(lettres)]
if sorted(mot) == sorted(lettres)]
return resultat

tests = ['acenrt']

dictionnaire = charge_dico()

for lettres in tests:
print(lettres, ':', recherche(lettres, dictionnaire))

yves

unread,
Dec 6, 2023, 5:22:14 PM12/6/23
to
Le Sat, 02 Dec 2023 03:48:09 +0100, Michel a écrit:

>> 0.4 secondes sur mon ordi, quand même.
>
> Sur le mien 0.280. Mais en reprenant le même principe que pour le
> scrabble, en chargeant le fichier dans une array par longueur de mot,
> j'obtiens 0.170.

Oui, c'est clair que c'est mieux.

> while line := fp.readline().rstrip():

Tiens, je ne connaissais pas cet opérateur ( := ) ni cette syntaxe.

En espérant qu'il ne va pas se transformer en émoji.

@+
--
Yves

Michel

unread,
Dec 7, 2023, 4:32:12 AM12/7/23
to
Le 6 décembre 2023 yves a écrit :

>> while line := fp.readline().rstrip():
>
> Tiens, je ne connaissais pas cet opérateur ( := ) ni cette syntaxe.

Je viens du Perl où il est dit qu'il y a plusieurs façons de faire un
truc :) Mais en python je ne suis pas sûr d'utiliser une syntaxe
mainstream...

Thierry Pinelli

unread,
Dec 7, 2023, 10:35:22 AM12/7/23
to
Le 06/12/2023 à 23:22, yves a écrit :
> Le Sat, 02 Dec 2023 03:48:09 +0100, Michel a écrit:
>
>>> 0.4 secondes sur mon ordi, quand même.
>>
>> Sur le mien 0.280. Mais en reprenant le même principe que pour le
>> scrabble, en chargeant le fichier dans une array par longueur de mot,
>> j'obtiens 0.170.
>
> Oui, c'est clair que c'est mieux.
>
>> while line := fp.readline().rstrip():

> Tiens, je ne connaissais pas cet opérateur ( := ) ni cette syntaxe.

du bon vieux Pascal

PPP Perl Python Pascal



Thierry Pinelli

unread,
Dec 7, 2023, 11:53:09 AM12/7/23
to
Le 07/12/2023 à 16:57, Stefan Ram a écrit :

> Il y a aussi un exemple :
>
> |while chunk := file.read(9000):
> | process(chunk)
>
> ("The Python Language Reference", Release 3.13.0a0).

oui, 6.12. Assignment expressions

yves

unread,
Dec 7, 2023, 1:00:33 PM12/7/23
to
Le 7 Dec 2023 15:57:34 GMT, Stefan Ram a écrit:

> ("The Python Language Reference", Release 3.13.0a0).

Oui, j'en profite pour rappeler l'aide intégrée au prompt python :


Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.

>>> help("while")
The "while" statement
*********************

The "while" statement is used for repeated execution as long as an
expression is true:

while_stmt ::= "while" assignment_expression ":" suite
["else" ":" suite]

This repeatedly tests the expression and, if it is true, executes the
first suite; if the expression is false (which may be the first time
it is tested) the suite of the "else" clause, if present, is executed
and the loop terminates.

A "break" statement executed in the first suite terminates the loop
without executing the "else" clause’s suite. A "continue" statement
executed in the first suite skips the rest of the suite and goes back
to testing the expression.

Related help topics: break, continue, if, TRUTHVALUE

@+
--
Yves

yves

unread,
Dec 7, 2023, 1:07:51 PM12/7/23
to
Le 7 Dec 2023 15:57:34 GMT, Stefan Ram a écrit:

> |while_stmt ::= "while" assignment_expression ":" suite

On peut noter que cette syntaxe, (:=, également appelé "opérateur
d'affectation de l'expression") a été introduite dans la version 3.8
de python, sortie fin 2019*.

* juste un peu avant l'épidémie de Covid. Coïncidence ? JE POSE LA
QUESTION.

@+
--
Yves
0 new messages