Problèmes programme python

honey -  
heyquem Messages postés 808 Statut Membre -
Bonjour, je fais un programme pour résoudre des grilles de sudoku en python (sous windows vista) mais je suis confrontée à 2 problèmes:
la fonction est bonne mais je n'arrive pas à lire un fichier texte :

def lire ('../grille1.txt'):
lgrille=[]
fp=open ('../grille1.txt','r')
ligne=fp.readline()
while ligne:
l=ligne.split()
lgrille.append([])
for e in l:
lgrille [-1].append(int(e))
ligne=fp.readline
fp.close()
return lgrille


print lire()



Puis j'ai une autre fonction pour afficher la grille mais ça ne m'affiche pas les lignes, tous les éléments sont les uns en dessous des autres (sauf pour afficheSeparateur):

def afficheSeparateur ():
print ("-"*25)


def afficheLigne(l):
for e in range (9):
if e%3==0:
print ("|")
if l[e]==0:
print (".")
else:
print (l[e])
print ("|")


def afficher (l):
for e in range (9):
if e%3==0:
afficheSeparateur()
afficheLigne (l[e])
afficheSeparateur()


l=[[0,0,9,0,0,0,0,0,0],[0,1,0,0,0,0,4,8,0],[0,4,0,3,8,5,0,0,0],[5,0,0,0,0,2,0,3,0],[0,0,0,0,5,0,7,9,1],[0,0,1,7,0,9,0,2,4],[0,0,0,0,4,3,0,0,5],[0,0,2,0,9,7,0,1,8],[0,0,0,0,0,0,0,0,0]]
afficher(l)


J'ai vraiment besoin d'aide c'est un devoir à rendre. Merci beaucoup d'avance !
A voir également:

4 réponses

heyquem Messages postés 808 Statut Membre 131
 
je ne comprend pas pourquoi je dois mettre les parenthèses pour les print sinon ça ne fonctionne pas.
C'est certainement parce que tu es sous Python 3, alors que je suis toujours sous Python 2.6
https://www.local-guru.net/blog/2009/02/09/whats-new-in-python-3-0
http://docs.python.org/dev/3.0/whatsnew/3.0.html

-------------------------------------------

Tu ne veux pas remplacer
        l=ligne.split()
        lgrille.append([]) 
        for e in l: 
            lgrille [-1].append(int(e))

par
        l=ligne.split()
        sous-liste = [ int(u) for u in l ]
        lgrille.append(sous-liste)

?

On peut même condenser en
        l=ligne.split()
        lgrille.append([ int(u) for u in l ])

et on peut même aller jusqu'à

def lire (fic): 
    lgrille=[] 
    fp=open (fic,'r') 
    ligne=fp.readline()
    while ligne: 
        lgrille.append([int(u) for u in ligne.split()]) 
        ligne=fp.readline()
    fp.close() 
    return lgrille 

C'est clean , non ?






Si ça ne te plait pas, on peut aussi procéder autrement.
Est-ce que tu connais la fonction map() ?
Regarde ce qui se passe par exemple avec
li = ['23','4','123','890','45']
print li
li = map(int,li)
print li


map(f,li) applique la fonction f sur chaque élément de li et renvoie la liste li transformée

Donc dans ton cas, on peut s'en servir pour écrire

def lire1 (fic): 
    lgrille=[] 
    fp=open (fic,'r') 
    ligne=fp.readline()
    while ligne: 
        l=map(int,ligne.split())
        lgrille.append(l) 
        ligne=fp.readline()
    fp.close() 
    return lgrille


et en condensant:

def lire1 (fic): 
    lgrille=[] 
    fp=open (fic,'r') 
    ligne=fp.readline()
    while ligne: 
        lgrille.append(map(int,ligne.split())) 
        ligne=fp.readline()
    fp.close() 
    return lgrille 



Comme ça , il n'y a même pas de création de l, ses valeurs sont immédiatement traitées par map().

--------------

Pour l'affichage, y a de l'idée, mais ça cafouille un peu.

D'abord, si tu fais renvoyer lgrille par la fonction lire(), et l'imprimer par print lire(...), certes tu as l'écriture de lgrille à l'écran. Mais une fois ceci fait, lgrille ne se trouve plus accessible parce que c'était une variable locale, c'est à dire interne a lire().

Donc il faut l'enregistrer à l'extérieur:
Faire
lgrille = lire(...)
print lgrille




Ensuite je ferais comme ça:
- afficher "-"*25
- pour chaque sous-liste de lgrille (c'est à dire une ligne), afficher la succession de chiffres et de '|' c'est à dire la ligne de chiffres proprement dite bien formatée
puis en dessous afficher "-"*25

Il faut savoir que sous Python 2.6 en tous cas, print fait revenir à la ligne donc
            print (l[e]) 
            print ("|") 

va malheureusement faire afficher
l[e] sur une ligne
puis '|' à la ligne suivante
Pour contrecarrer ça, il faut faire
            print (l[e]),("|") 

La virgule empêche le retour à la ligne. Ça marche aussi si on écrit
            print (l[e]),
            print ("|") 


Mais il reste un ennui: print a,b fait affichér a et b avec touours un blanc entre les deux.
Pour éviter ceci il faut alors écrire print a+b, mais cela n'est possible que si a et b sont des chaînes. Si b est un entier par exemple, il suffit d'écrire print a+str(b).

Et hop.


Ceci dit, Python 3 a vu une augmentation notable des possibilités de la fonction print, et les pratiques sont sans doute différentes et plus simples à mettre en place. À toi de regarder tout ça et de te débrouiller avec mes indications pour arriver à écrire ta fonction d'affichage.



Pense aussi au fait que Python permet de jouer très facilement avec des indices.
Par exemple
l = [0,0,1,4,0,3,0,3,8]
for i in (0,3,6):
    print l[i:i+3],


Allez, j'arrête là, on peut dire des tonnes de choses encore.

------------------------

pour garder l'indentation des lignes qui sont du code, dans le message ue tu postes, il faut sélectionner les lignes en question et appuyer sur le bouton à icône de page blanche qui se trouve juste après les icônes G I S
1
heyquem Messages postés 808 Statut Membre 131
 
Salut,

Il faut lire les messages d'erreur !
Comment faire autrement quand on veut débugger ?


Si ton fichier se trouve bien à portée de lecture de Python (je pars de l'hypothèse que c'est le cas), tu as dû obtenir le message d'erreur suivant:
Ther's an error in your programm: invalid syntax.
et sous IDLE, une marque rouge sur la deuxième apostrophe dans def lire ('../grille1.txt'): (juste après txt)
Donc il y a un problême avec ce que tu indiques comme paramètres de la fonction.

En fait, il ne peut y avoir une chaîne comme argument de paramètre entre les parenthèses que si elle est précédée de var = , pour signaler que l'argument chaîne qui est là est un argument par défaut pour le paramètre var.

Ou alors il faut que la chaîne qui est le nom du fichier soit mise dans l'appel de la fonction. C'est ce que j'ai fait.



Je me suis créé un fichier
0 0 9 0 0 0 0 0 0
0 1 0 0 0 0 4 8 0
0 4 0 3 8 5 0 0 0
5 0 0 0 0 2 0 3 0
0 0 0 0 5 0 7 9 1
0 0 1 7 0 9 0 2 4
0 0 0 0 4 3 0 0 5
0 0 2 0 9 7 0 1 8
0 0 0 0 0 0 0 0 0
à partir de tes données
et j'ai pris ton code pour le tester.

J'ai alors obtenu le message d'erreur suivant:
AttributeError: 'builtin_function_or_method' object has no attribute 'split'

Comme je ne comprenais pas, j'ai ajouté des instructions print pour suivre l'évolution de l'exécution au sein de la fonction:
def lire(nomfich): 
    lgrille=[] 
    fp=open (nomfich,'r') 
    ligne=fp.readline()
    print 'AAA',ligne,type(ligne)
    while ligne: 
        l=ligne.split()
        print 'BBB',l
        lgrille.append([])
        print 'lgrille avant =',lgrille
        for e in l: 
            lgrille[-1].append(int(e))
        print 'lgrille apres =',lgrille
        ligne=fp.readline
        print 'ligne lue =',ligne
    fp.close() 
    return lgrille 

print lire('sudoku.txt')


Et voici ce qui sort à l'exécution:
AAA 0 0 9 0 0 0 0 0 0
<type 'str'>
BBB ['0', '0', '9', '0', '0', '0', '0', '0', '0']
lgrille avant = [[]]
lgrille apres = 0, 0, 9, 0, 0, 0, 0, 0, 0
ligne lue = <built-in method readline of file object at 0x013A9480>
Traceback (most recent call last):
  File "E:\Python\Essais Python\zzzzzzzzzzz ccm.py", line 19, in <module>
    print lire('sudoku.txt')
  File "E:\Python\Essais Python\zzzzzzzzzzz ccm.py", line 7, in lire
    l=ligne.split()
AttributeError: 'builtin_function_or_method' object has no attribute 'split'


Donc l'erreur se produit quand le programme revient à l'instruction l=ligne.split() après avoir réussi à faire ligne=fp.readline et qu'il essaye de faire un split() sur ligne.

Le message d'erreur dit que ligne est une 'builtin_function_or_method'.
Or ce devrait être une chaîne.
Regarde bien l'instruction ligne=fp.readline , le problème est là.
Je te laisse trouver



------------------



Il y a aussi plus simple à faire que d'ajouter une sous-liste vide à lgrille puis de la remplir progressivement avec les éléments de l prélevés progressivement et transformés en entiers avant d'être placés dans la sous-liste lgrille[-1].

Il faut d'abord créer la sous-liste remplie puis l'ajouter dans lgrille.

l est déjà une liste, de caractères.
Il suffit de transformer ces caractères en entiers.
Une list comprehension permet de faire cette transformation en une seule ligne:
sous-liste = [ int(u) for u in l ]
Ce qui donne:
def lire(nomfich): 
    lgrille=[] 
    fp=open (nomfich,'r') 
    ligne=fp.readline()
    while ligne: 
        l=ligne.split()
        sous-liste = [ int(u) for u in l ]
        lgrille.append(sous-liste)
        ligne=fp.readline
    fp.close() 
    return lgrille 

print lire('sudoku.txt')


Dans ce code, la ligne ligne=fp.readline n'est toujours pas corrigée, c'est à toi de le faire.



Maintenant, tu peux remplacer dans [ int(u) for u in l ] la variable l par son expression ligne.split()
Cela donne un code plus condensé.

Il y a d'autres condensations et meilleures pratiques à apporter pour améliorer ton code.

Pour l'affichage, il y a d'autres façons de faire que celles que tu envisages.

Je ne sais pas quelles sortes de choses tu peux te permettre de mettre dans ton devoir. Il ne faudrait pas que cela paraisse trop astucieux. Je n'ai pas l'intention de te faire ton devoir à ta place, mais même sans tout faire, rien qu'en étant guidé, tu obtiendras un code peut être trop bien fait pour le niveau que tu es censé avoir.



J'attends de voir si tu reviens lire cette réponse.
0
honey
 
Merci beaucoup mon programme fonctionne maintenant (et correctement ^^)

def lire (fic):
lgrille=[]
fp=open (fic,'r')
ligne=fp.readline()
while ligne:
l=ligne.split()
lgrille.append([])
for e in l:
lgrille [-1].append(int(e))
ligne=fp.readline()
fp.close()
return lgrille


print (lire('grille1.txt'))

Voilà ! Par contre je ne comprend pas pourquoi je dois mettre les parenthèses pour les print sinon ça ne fonctionne pas.

En tout cas merci de m'avoir aidée, c'est très gentil.
0
heyquem Messages postés 808 Statut Membre 131
 
Je viens aussi de penser que généralement , c'est assez lourdingue de lire des fichiers en réitérant des readline()

Il vaut mieux
- soit lire le fichier d'un coup avec read() et traiter ensuite la chaîne obtenue
- soit lire le fichier d'un coup avec readlines() qui met tout de suite le fichier en liste de lignes.

Mais le fait que readlines() conserve les retours de ligne '\n' en bout de chaque ligne est souvent un inconvénient.
Dans ce cas il faut tirer les données du fichier en faisant un traitement de la chaîne fp.read() avec splitlines() et ça peut être fait d'un seul coup:
fp.read().splitlines()


À partir de là, ça devient plus amusant:

def lire (nomfich): 
    lgrille=[] 
    fp=open (nomfich,'r') 
    lignes=fp.read().splitlines()
    for l in lignes:
        lgrille.append( map(int,l.split())) 
    return lgrille


et même

def lire (nomfich): 
    fp=open (nomfich,'r') 
    lignes=fp.read().splitlines()
    lgrille = [ map(int,l.split()) for l in lignes ] 
    return lgrille


et tant qu'on y est:

def lire (nomfich):
    fp=open (nomfich,'r') 
    lgrille = [ map(int,l.split()) for l in fp.read().splitlines() ] 
    return lgrille




puis enfin, tenant compte du fait qu'existe le très intéressant with statement depuis 2.6
with open ('sudoku.txt','r') as fp:
    lgrille = [ map(int,l.split()) for l in fp.read().splitlines() ] 


2 lignes. J'adore Python
0
honey
 
Bon la fonction lire je peux condenser (sans utiliser map()) mais j'ai déja essayé de mettre des virgules pour éviter le saut à la ligne mais ça le fait toujours, je vais essayer d'écrire la fonction d'une autre façon.
Merci pour ton aide et tes conseils
0
heyquem Messages postés 808 Statut Membre 131
 
Je me suis escrimé à trouver une manière concise de faire afficher un tableau de sudoku, c'est à dire un tableau de 9 X 9 découpé en 9 tableaux de 3 X 3.
Je ne m'étais jamais intéressé à ce problème, j'ai eu un peu de mal.

Mais je suis finalement parvenu à un code en 7 lignes.
Cependant, il est peut être trop sophistiqué pour ce que tu es sensé savoir, bien que je ne fasse qu'utiliser split(), le formatage de chaîne, l'insertion dans une liste et join().
Je me demande si ça sert à quelque chose que je le mette sur ce forum.
Donne plutôt le code auquel tu es parvenu, si tu es intéressé d'avoir mon avis.

Parallèlement, je ne peux que t'encourager à regarder le formatage de chaîne
http://www.python.org/doc/2.5.4/lib/typesseq-strings.html
et la fonction très utile join() qui concatène une liste en insérnt un séparateur entre les éléments de la liste. Vraiment très utile pourla présentation de liste sans prendre plusieurs lignes de code.




Par ailleurs, Python ne dispose pas de structure de données qui puisse représenter simplement un tableau par tab(2;4) ; il faut utiliser une liste de listes et ce n'est pas tout à fait intuitif de manipuler des li[2][4]
De plus , une liste de liste donne un programme certainement plus lent.
C'est pourquoi je suis partisan d'une solution dans laquelle on n'a qu'une liste, dans laquelle l'élément de la ligne i et de la colonne j se trouve à l'index i * 9 + j. L'écriture des calculs s'en trouvera certainement grandement simplifiée, et le programme plus rapide.



Le module numpy est spécialisé dans la représentation de tableaux utilisables. Mais je suppose que tu n'as pas latitude pour t'en servir.
0
honey > heyquem Messages postés 808 Statut Membre
 
Tu as un code pour résoudre un sudoku?

Je t'explique le devoir:

-je lis un fichier avec ma fonction lire (je transforme en une liste de listes)
-j'affiche la grille non résolue avec les séparateurs donc avec ma fonction afficher
-j'affiche la grille résolue mais sans séparateurs, juste les chiffres
-j'affiche le temps qu'a pris le programme pour résoudre le sudoku

Maintenant je problème que j'ai c'est que mon programme ne résout que des grilles faciles mais n'arrive pas à résoudre des grilles difficiles et renvoie une solution avec encore plein de zéros.

Je pense qu'il faut changer carrément ma fonction résolution...
0
heyquem Messages postés 808 Statut Membre 131
 
Non, je n'ai pas de code pour résoudre les sudokus.
Le code de 7 lignes dont je parle fait ce que tu as expliqué vouloir faire dans ton premier post: lire une grille dans un fichier, afficher la grille.

Ce qui m'intéresse , c'est d'aider quelqu'un en lui montrant des meilleures pratiques pour progresser plus vite dans la résolution d'un problème, et de chercher moi-même des solutions pour des problèmes que je ne connais pas. Je ne suis pas trop intéressé de fournir des codes tout faits.

Pour ce qui est des sudokus, je ne m'y étais jamais intéressé. Comme sujet de programmation, c'est intéressant. Mais c'est le genre de jeu qui en lui-même m'énerve un peu: ça pompe du temps et ça n'apporte pas grand chose. Pour dire: je viens seulement de me renseigner sur les règles des sudokus, je n'étais même pas au courant.

J'ai lu des trucs sur les sudokus; sous l'apparence de simplicité, la résolution semble parfois très difficile pour certaines grilles. Je n'ai pas tellement envie de me lancer à réfléchir sur un algorithme de sudoku, je n'ai pas le temps. Tu dois être en fac ou quelque école après le bac pour avoir ainsi un devoir sur un sujet aussi ardu.

Mais je veux bien continuer à te donner des indications, des corrections et des tuyaux relativement à Python, et aussi un peu pour l'algorithme, mais je ne peux pas m'y plonger.
Pour l'algorithme, il y a ces sites qui ont l'air bien:
http://mosa.ique.free.fr/sudoku/index.php?url=/sudoku/sudoku.php¶m=
https://www.mots-croises.ch/Sudoku/grille.htm?g=G114839328609-48176&t=N2
et sans doute plein d'autres, en cherchant sur google.

Voici mon adresse sur gmail si tu veux m'adresser quelque chose sans que ce soit visible sur un forum
heyquem@gmail.com
Par exemple, tu devrais me montrer les codes que tu as déjà écrits. Sans ça on va faire du blabla.
0