Bonjour à toutes et à tous !


Je travaille actuellement sur un projet de jeu vidéo, un petit chose assez simple, mais plutôt ambitieux pour mon niveau: Je ne code en python que depuis 6 mois, et dans le cadre d'un cours ne représentant que très peu d'heures sur mon emploi du temps chargé de S.

L'idée serait de créer un jeu d'infiltration en vue de dessus.
Je vous passe tous les détails, pour en venir directement au fait:
J'ai énormément de mal avec l'algorithme A*. Je planche dessus depuis maintenant plusieurs semaines, et je ne parviens pas à débloquer la situation.
J'ai vraiment besoin d'aide, et tout conseil serait le bienvenue.

Je joint à ce message le code actuel, et me tient disponible 24/24 en cas de réponse (et j'espère qu'il y en aura... )


Je code actuellement sous Tkinter, mais ici le GUI n'a que peu d'importance puisqu'il ne sert qu'à montrer sous forme graphique les calculs internes du programme.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# Créé par Elias, le 09/04/2016 en Python 3.2
# -*- coding: utf-8 -*-
"""
Éditeur de Spyder
 
Ce script temporaire est sauvegardé ici :
C:\Program Files (x86)\WinPython-32bit-3.3.2.1\settings\.spyder2\temp.py
"""
from tkinter import*
import sys
from math import*
from random import*
 
print(sys.getrecursionlimit())
sys.setrecursionlimit(5000)
 
listeetude=[]
listechoisi=[]
 
class pion:
    """Cette classe ne définit pour le moment que:
    - Les coordonnées X
    - Les coordonnées Y
    - La position relative aux colonnes
    - La position relative aux lignes """
 
    def __init__(self):
        self.coordsx = 0
        self.coordsy = 0
        self.colonnes= 0
        self.lignes= 0
 
class case: 
    """Cette classe définit, pour le moment:
        - La position relative aux colonnes et aux lignes.
        - La distance à l'arrivée en lignes et en colonnes.
        - La distance totale à l'arrivée
        - La distance au point de départ en lignes et en colonnes.
        - La distance totale au point de départ.
        - La qualité de cette case.
        - Dans quelle direction par rapport au noeud parent est placée cette case
        - Le type: Normal ou Bloqué.    """
    def __init__(self):
        self.colonnes=0
        self.lignes=0
        self.darcol=0
        self.darln=0
        self.dar = self.darcol+self.darln
        self.dgcol=0
        self.dgln=0
        self.dg= self.dgcol+self.dgln
        self.qual= self.dar + self.dg
        self.dir="direction"
        self.type=""
        self.parent=0
 
 
def lignes_colonnes(x):
    x.lignes=int((x.coordsy/50)-0.5)+1
 
    x.colonnes=int((x.coordsx/50)-0.5)+1
 
 
 
garde = pion()
joueur = pion()
 
p1=case()
p2=case()
p3=case()
p4=case()
 
 
compteur=0
 
 
xpointdepart=25
ypointdepart=25
 
garde.coordsx=xpointdepart
garde.coordsy=ypointdepart
 
xpointarrivee=225
ypointarrivee=225
 
lignes_colonnes(garde)
 
lignes_colonnes(garde)
casegarde=case()
casegarde.lignes=garde.lignes
casegarde.colonnes=garde.colonnes
 
joueur.coordsx=xpointarrivee
joueur.coordsy=ypointarrivee
lignes_colonnes(joueur)
casearrivee=case()
casearrivee.lignes=joueur.lignes
casearrivee.colonnes=joueur.colonnes
 
listechoisi.insert(0, casegarde)
listeetude.insert(0, casegarde)
listecaseobstacle=[]
#304, 305, 306, 404
xroot=0
yroot=0
 
 
OK=0
 
colonne=0
rang=0
 
largeurcanvas=500
hauteurcanvas=500
 
largeurfenetre=800
hauteurfenetre=500
 
fen=Tk()
fen.geometry(str(largeurfenetre)+"x"+str(hauteurfenetre))
drawzone=Canvas(height=500, width=500, bg="white")
drawzone.place(x=0,y=0)
 
housetile=PhotoImage(file="rooftile.gif")
pavestile=PhotoImage(file="paves.gif")
 
 
mapfile1=open("maptest.txt")
 
for ligne in mapfile1 : #On utilise le fichier texte joint pour créer le décor.
    for i in range(0,len (ligne)) :
        case = ligne[i]
        if case=='B':
            maison=drawzone.create_image(xroot,yroot, image=housetile, anchor="nw")
        if case=='P'   :
            rue=drawzone.create_image(xroot, yroot, image=pavestile, anchor="nw")
        xroot= xroot+50
    xroot=0
    yroot=yroot+50
 
#zonebloquee=drawzone.create_polygon((100, 150), (150,150), (150,200), (100,200))
#zonebloquee=drawzone.create_polygon((100, 200), (150,200), (150,250), (100,250))
#zonebloquee=drawzone.create_polygon((100, 250), (150,250), (150,300), (100,300))
#zonebloquee=drawzone.create_polygon((150, 150), (150,200), (200,200), (200,150))
 
 
 
xroot=0
yroot=0
 
pointdepart=drawzone.create_oval(xpointdepart-10, ypointdepart-10, xpointdepart+10, ypointdepart+10, fill="green")
pointarrivee=drawzone.create_oval(xpointarrivee-10, ypointarrivee-10, xpointarrivee+10, ypointarrivee+10, fill="blue")
 
def qualitépoint(x): #Cette partie sert à déterminer la qualité de la case, en fonction de son statut et de sa position relative à celle du point d'arrivée.
    if ((x.lignes*100+x.colonnes) in listecaseobstacle) or (x in listechoisi): #Si la case est dans la liste des obstacles, ou a déjà été choisie par l'algorithme, on élimine la solution, en plaçant une valeur impossible à atteindre autrement.
        x.qual=999
    else: #On calcule ensuite la qualité du point grâce à la distance de Manhattan, à savoir :
        listeetude.append(x)
        x.darcol= fabs(casearrivee.colonnes-x.colonnes)  #Valeur absolue de la distance entre case d'arrivée et case de départ, sur x.
        x.darln= fabs(casearrivee.lignes-x.lignes) #Valeur absolue de la distance entre case d'arrivée et case de départ, sur y.
        x.dar= x.darcol + x.darln #Somme de ces deux valeurs
        x.qual=x.dar #Et qui donne la qualité du point.
 
 
def pathfinding():
    chemin()
 
def chemin(): #Cette partie du programme sert à vérifier la qualité des toutes les cases adjacentes à la dernière case étudiée.
    global compteur
 
    p1.colonnes=listechoisi[compteur].colonnes
    p1.lignes=(listechoisi[compteur].lignes)+1
    p1.direction="bas"
    p1.parent=listechoisi[compteur]
    qualitépoint(p1)
 
    p2.colonnes=(listechoisi[compteur].colonnes)
    p2.lignes=(listechoisi[compteur].lignes)-1
    p2.parent=listechoisi[compteur]
    p2.direction="haut"
    qualitépoint(p2)
 
    p3.colonnes=(listechoisi[compteur].colonnes)+1
    p3.lignes=(listechoisi[compteur].lignes)
    p3.direction="droite"
    p3.parent=listechoisi[compteur]
    qualitépoint(p3)
 
    p4.colonnes=(listechoisi[compteur].colonnes)-1
    p4.lignes=(listechoisi[compteur].lignes)
    p4.direction="gauche"
    p4.parent=listechoisi[compteur]
    qualitépoint(p4)
 
    if min(p1.qual, p2.qual, p3.qual, p4.qual) == p1.qual: #Cette partie sert à choisir la case ayant la qualité la plus basse, c'est à dire celle qui se rapproche le plus du point d'arrivée.
        listechoisi.append(p1)
        print("bas")
    elif min(p1.qual, p2.qual, p3.qual, p4.qual) == p2.qual:
        listechoisi.append(p2)
        print("haut")
    elif min(p1.qual, p2.qual, p3.qual, p4.qual) == p3.qual:
        listechoisi.append(p3)
        print("droite")
    elif min(p1.qual, p2.qual, p3.qual, p4.qual) == p4.qual:
        listechoisi.append(p4)
        print("gauche")
 
 
    compteur=compteur+1
 
    print(listechoisi[compteur].qual)
    print(listechoisi[compteur].colonnes, listechoisi[compteur].lignes)
    print(casearrivee.colonnes, casearrivee.lignes)
 
 
    drawzone.create_polygon((((listechoisi[compteur].colonnes-1)*50), ((listechoisi[compteur].lignes-1)*50)),(((listechoisi[compteur].colonnes)*50), ((listechoisi[compteur].lignes-1)*50)),(((listechoisi[compteur].colonnes)*50), ((listechoisi[compteur].lignes)*50)),(((listechoisi[compteur].colonnes-1)*50), ((listechoisi[compteur].lignes)*50)), fill="red" ) #Cette partie fait passer en rouge la case choisie par le programme.
 
 
 
 
 
 
 
def deplacementpoint(evt): #Sert à déplacer le point de départ et le point d'arrivée: Touche fléchées pour le point de départ, et [zqsd] pour le point d'arrivée.
    global pointdepart
    global pointarrivee
    global xpointarrivee
    global ypointarrivee
    global xpointdepart
    global ypointdepart
    drawzone.delete(pointdepart, pointarrivee)
    if evt.keycode==38: #haut
        ypointdepart=ypointdepart-50
    elif evt.keycode==40: #bas
        ypointdepart=ypointdepart+50
    elif evt.keycode==37: #gauche
        xpointdepart=xpointdepart-50
    elif evt.keycode==39: #droite
        xpointdepart=xpointdepart+50
    elif evt.keycode==90: #"z"
        ypointarrivee=ypointarrivee-50
    elif evt.keycode==81: #"q"
        xpointarrivee=xpointarrivee-50
    elif evt.keycode==68: #"d"
        xpointarrivee=xpointarrivee+50
    elif evt.keycode==83: #"s"
        ypointarrivee=ypointarrivee+50
    garde.coordsx=xpointdepart
    garde.coordsy=ypointdepart
    lignes_colonnes(garde)
    joueur.coordsx=xpointarrivee
    joueur.coordsy=ypointarrivee
    lignes_colonnes(joueur)
    casegarde.lignes=garde.lignes
    casegarde.colonnes=garde.colonnes
    casearrivee.lignes=joueur.lignes
    casearrivee.colonnes=joueur.colonnes
    casearrivee.lignes=joueur.lignes
    casearrivee.colonnes=joueur.colonnes
    pointdepart=drawzone.create_oval(xpointdepart-10, ypointdepart-10, xpointdepart+10, ypointdepart+10, fill="green")
    pointarrivee=drawzone.create_oval(xpointarrivee-10, ypointarrivee-10, xpointarrivee+10, ypointarrivee+10, fill="blue")
 
 
 
 
pathfindingbt=Button(text="Lancer procedure Pathfinding", command=pathfinding)
pathfindingbt.place(x=550, y=100)
 
 
fen.bind("<Key>", deplacementpoint)
 
 
fen.mainloop()
Ci-joint, les ressources nécessaires pour faire fonctionner le programme.maptest.txtNom : paves.gif
Affichages : 510
Taille : 1,6 KoNom : housetile.gif
Affichages : 516
Taille : 105 octets

Je vous laisse le tester... Je ne saurais pas exactement dire quels bugs je rencontre, mais j'en ai repéré quelques uns:
Tout d'abord, le fait que, d'une manière assez étrange, le programme choisira parfois une case en diagonale, ce qui n'est pas, en soi, un mauvais choix, mais rentre en contradiction nette avec ce qui est indiqué dans la fonction (chemin), puisque celle-ci ne permet de choisir que des cases situées à gauche, à droite, en bas ou en haut.

Ensuite... Le fait que, passé les deux premières occurrences de la fonction (chemin), le programme fait... N'importe quoi, je ne saurais vraiment pas le décrire.


J'ai vraiment besoin d'aide, pour le coup, c'est assez urgent, et je dois finir cela si je veux pouvoir passer à la suite...

Merci beaucoup de votre attention, et merci d'avance si vous décidez de m'aider.

A la prochaine !

Saad