Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > fr.comp.lang.python > #4113 > unrolled thread

Tricher au scrabble...

Started byDominique <dominique.sextant@orange.fr.invalid>
First post2023-11-28 11:33 +0100
Last post2023-11-28 19:23 +0100
Articles 19 — 4 participants

Back to article view | Back to fr.comp.lang.python


Contents

  Tricher au scrabble... Dominique <dominique.sextant@orange.fr.invalid> - 2023-11-28 11:33 +0100
    Re: Tricher au scrabble... Dominique <dominique.sextant@orange.fr.invalid> - 2023-11-28 16:39 +0100
    Re: Tricher au scrabble... Dominique <dominique.sextant@orange.fr.invalid> - 2023-11-28 16:43 +0100
      Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-12-01 17:39 +0000
        Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-12-01 17:56 +0000
          Re: Tricher au scrabble... Michel <michel@domain.invalid> - 2023-12-02 03:48 +0100
            Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-12-06 22:22 +0000
              Re: Tricher au scrabble... Michel <michel@domain.invalid> - 2023-12-07 10:28 +0100
              Re: Tricher au scrabble... Thierry Pinelli <olmia2b+news@gmail.com> - 2023-12-07 16:35 +0100
              Re: Tricher au scrabble... Thierry Pinelli <olmia2b+news@gmail.com> - 2023-12-07 17:52 +0100
              Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-12-07 18:00 +0000
              Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-12-07 18:07 +0000
    Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-11-28 16:05 +0000
      Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-11-28 16:17 +0000
        Re: Tricher au scrabble... Dominique <dominique.sextant@orange.fr.invalid> - 2023-11-29 05:55 +0100
      Re: Tricher au scrabble... yves <yves@free.invalid> - 2023-11-28 20:16 +0000
    Re: Tricher au scrabble... Michel <michel@domain.invalid> - 2023-11-28 17:52 +0100
      Re: Tricher au scrabble... Dominique <dominique.sextant@orange.fr.invalid> - 2023-11-29 05:57 +0100
    Re: Tricher au scrabble... Michel <michel@domain.invalid> - 2023-11-28 19:23 +0100

#4113 — Tricher au scrabble...

FromDominique <dominique.sextant@orange.fr.invalid>
Date2023-11-28 11:33 +0100
SubjectTricher au scrabble...
Message-ID<uk4fm4$852n$1@dont-email.me>
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

[toc] | [next] | [standalone]


#4118

FromDominique <dominique.sextant@orange.fr.invalid>
Date2023-11-28 16:39 +0100
Message-ID<uk51jt$auel$1@dont-email.me>
In reply to#4113
Le 28/11/2023 à 12:30, Stefan Ram a écrit :
> Dominique <dominique.sextant@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
Esto quod es

[toc] | [prev] | [next] | [standalone]


#4119

FromDominique <dominique.sextant@orange.fr.invalid>
Date2023-11-28 16:43 +0100
Message-ID<uk51rm$auel$2@dont-email.me>
In reply to#4113
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 :)


-- 
Dominique
Esto quod es

[toc] | [prev] | [next] | [standalone]


#4138

Fromyves <yves@free.invalid>
Date2023-12-01 17:39 +0000
Message-ID<656a1a3b$0$10088$426a74cc@news.free.fr>
In reply to#4119
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

[toc] | [prev] | [next] | [standalone]


#4139

Fromyves <yves@free.invalid>
Date2023-12-01 17:56 +0000
Message-ID<656a1e57$0$10088$426a74cc@news.free.fr>
In reply to#4138
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

[toc] | [prev] | [next] | [standalone]


#4140

FromMichel <michel@domain.invalid>
Date2023-12-02 03:48 +0100
Message-ID<874jh1tlp1.fsf@gnus.org>
In reply to#4139
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))

[toc] | [prev] | [next] | [standalone]


#4148

Fromyves <yves@free.invalid>
Date2023-12-06 22:22 +0000
Message-ID<6570f414$0$27068$426a74cc@news.free.fr>
In reply to#4140
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

[toc] | [prev] | [next] | [standalone]


#4150

FromMichel <michel@domain.invalid>
Date2023-12-07 10:28 +0100
Message-ID<87o7f2pdo8.fsf@gnus.org>
In reply to#4148
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...

[toc] | [prev] | [next] | [standalone]


#4152

FromThierry Pinelli <olmia2b+news@gmail.com>
Date2023-12-07 16:35 +0100
Message-ID<uksonl$1ae09$1@dont-email.me>
In reply to#4148
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


[toc] | [prev] | [next] | [standalone]


#4154

FromThierry Pinelli <olmia2b+news@gmail.com>
Date2023-12-07 17:52 +0100
Message-ID<ukst92$1b7cb$1@dont-email.me>
In reply to#4148
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

[toc] | [prev] | [next] | [standalone]


#4155

Fromyves <yves@free.invalid>
Date2023-12-07 18:00 +0000
Message-ID<6572083e$0$10105$426a74cc@news.free.fr>
In reply to#4148
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

[toc] | [prev] | [next] | [standalone]


#4156

Fromyves <yves@free.invalid>
Date2023-12-07 18:07 +0000
Message-ID<657209f5$0$10105$426a74cc@news.free.fr>
In reply to#4148
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

[toc] | [prev] | [next] | [standalone]


#4121

Fromyves <yves@free.invalid>
Date2023-11-28 16:05 +0000
Message-ID<65660fc0$0$6447$426a34cc@news.free.fr>
In reply to#4113
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

[toc] | [prev] | [next] | [standalone]


#4122

Fromyves <yves@free.invalid>
Date2023-11-28 16:17 +0000
Message-ID<6566129a$0$6447$426a34cc@news.free.fr>
In reply to#4121
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

[toc] | [prev] | [next] | [standalone]


#4127

FromDominique <dominique.sextant@orange.fr.invalid>
Date2023-11-29 05:55 +0100
Message-ID<uk6g75$ltg0$1@dont-email.me>
In reply to#4122
Le 28/11/2023 à 17:17, yves a écrit :
> 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'}
> 
> @+

C'est exactement ce que j'ai fait:)

-- 
Dominique
Esto quod es

[toc] | [prev] | [next] | [standalone]


#4126

Fromyves <yves@free.invalid>
Date2023-11-28 20:16 +0000
Message-ID<65664ab1$0$8256$426a34cc@news.free.fr>
In reply to#4121
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

[toc] | [prev] | [next] | [standalone]


#4124

FromMichel <michel@domain.invalid>
Date2023-11-28 17:52 +0100
Message-ID<87y1eh4ydw.fsf@gnus.org>
In reply to#4113
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.

[toc] | [prev] | [next] | [standalone]


#4128

FromDominique <dominique.sextant@orange.fr.invalid>
Date2023-11-29 05:57 +0100
Message-ID<uk6gbd$lu0d$1@dont-email.me>
In reply to#4124
Le 28/11/2023 à 17:52, Michel a écrit :
> 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.

Je sais, et c'est bien là ma limite :)

-- 
Dominique
Esto quod es

[toc] | [prev] | [next] | [standalone]


#4125

FromMichel <michel@domain.invalid>
Date2023-11-28 19:23 +0100
Message-ID<87sf4p4uek.fsf@gnus.org>
In reply to#4113
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))

[toc] | [prev] | [standalone]


Back to top | Article view | fr.comp.lang.python


csiph-web