Recherche le plus court chemin entre deux point dans un labyrinthe

Programmation avancée de jeux en PureBasic
Avatar de l’utilisateur
plabouro472
Messages : 49
Inscription : sam. 23/juil./2022 10:17

Recherche le plus court chemin entre deux point dans un labyrinthe

Message par plabouro472 »

Bonjour à tous.

J'en avais besoin alors j'ai fais des recherches.
Recherche le plus court chemin entre deux point dans un labyrinthe.
Voici le résultat de mon travail et c'est avec plaisir que je vous en fais profité.

Cette méthode est basée sur l’algorithme de E.W. Dijkstra.

PB : 6.30
Os : Windows 11

La procedure PlusCourtChemin
Pcc ( DepartX , DepartY , ArriveeX , ArriveeY , 0 , @Tables )

et la procedure
ChargeResultat ( ArriveeX , ArriveeY , @Tables , Resultat() )

sont autonome, il sufit de passer les tables en paramètre et
elle seront traitées.

Les résultats s'affiche dans la fenêtre de débogage.

Je pense avoir suffisamment commenté le code pour le rendre le plus clair possible.

Bien à vous.

Code : Tout sélectionner

 

; Recherche le plus court chemin
; entre deux point dans un labyrinthe
;
; Cette méthode est basée sur l’algorithme de E.W. Dijkstra.
;
; PB : 6.30
; Os : Windows 11
; 

Structure Pt
 x .w
 y .w
 Dist .w
EndStructure

Structure Tb
 Array Laby .w ( 1 , 1 )
 Array Chemin.Pt ( 1 )
 V2 .w
 L .b
 H .b
EndStructure

Define .Tb Tables

; ***************
; Les procédures
Procedure AfficheResultat ( _x , _y , _v , *Tbs.Tb )
 Protected a$
 Debug "x = " + Str( _x ) + " : y = " + Str( _y ) + " : valeur = " + Str( _v )
 For y = 0 To *Tbs\H
 a$ = ""
 For x = 0 To *Tbs\L
 If *Tbs\Laby( x , y ) = -1
 a$ + "XXX:"
 Else
 a$ + RSet( Str( *Tbs\Laby( x , y ) ) , 3 , " ") + ":" 
 EndIf
 Next 
 Debug a$
 Next
 Debug""
EndProcedure
Procedure Pcc ( _x1 , _y1 , _x2 , _y2 , _v , *Tbs.Tb )
 Protected ValTmp .w
 v = _v + 1
 *Tbs\Laby ( _x1 , _y1 ) = v
 *Tbs\V2 + 1
 *Tbs\Chemin ( *Tbs\V2 )\x = _x1
 *Tbs\Chemin ( *Tbs\V2 )\y = _y1
 *Tbs\Chemin ( *Tbs\V2 )\Dist = v
 ; ; Pour un affichage pas à pas, retirez le point-virgule de la ligne suivante
 ; AfficheResultat( _x1 , _y1 , v , *Tbs )
 
 If _x1 = _x2 And _y1 = _y2 : ProcedureReturn : EndIf
 
 ; Pour chaque directions possibles :
 ValTmp = *Tbs\Laby( _x1 + 1 , _y1 ) ; à droite
 If v < ValTmp Or ValTmp = 0 
 Pcc( _x1 + 1 , _y1 , _x2 , _y2 , v , *Tbs )
 EndIf
 
 ValTmp = *Tbs\Laby( _x1 - 1 , _y1 ) ; à gauche
 If v < ValTmp Or ValTmp = 0 
 Pcc( _x1 - 1 , _y1 , _x2 , _y2 , v , *Tbs )
 EndIf
 
 ValTmp = *Tbs\Laby( _x1 , _y1 + 1 ) ; en bas
 If v < ValTmp Or ValTmp = 0 
 Pcc( _x1 , _y1 + 1 , _x2 , _y2 , v , *Tbs )
 EndIf
 
 ValTmp = *Tbs\Laby( _x1 , _y1 - 1 ) ; en haut
 If v < ValTmp Or ValTmp = 0 
 Pcc( _x1 , _y1 - 1 , _x2 , _y2 , v , *Tbs )
 EndIf
EndProcedure
Procedure ChargeResultat ( _x2 , _y2 , *Tabs.Tb , Array Res.Pt( 1 ) )
; Charge dans la table Resultat() le chemin le plus court
 Protected .w Distance
 Protected .w n
 Protected .a Trouve
 
Distance = *Tabs\Laby ( _x2 , _y2 )
Res( Distance )\Dist = Distance
Res( Distance )\x = _x2
Res( Distance )\y = _y2
Trouve.a = #False
For n = *Tabs\V2 To 1 Step -1
 If Not Trouve
 ; Recherche le point d'arrivée en partant de la fin 
 If *Tabs\Chemin( n )\Dist = Res( Distance )\Dist And 
 *Tabs\Chemin( n )\x = _x2 And 
 *Tabs\Chemin( n )\y = _y2
 Trouve = #True
 EndIf
 Else
 ; Trace le chemin en remontant jusqu'au point de départ
 If *Tabs\Chemin( n )\Dist < Distance
 Distance - 1
 Res( Distance )\Dist = *Tabs\Chemin( n )\Dist
 Res( Distance )\x = *Tabs\Chemin( n )\x
 Res( Distance )\y = *Tabs\Chemin( n )\y
 EndIf
 EndIf
Next
EndProcedure


; *************************
; Les données du labyrinthe
DataSection
 DataLaby:
 Data.b 14 , 14 ; Large , Haut
 ;       0  1  2  3  4  5  6  7  8  9  A  B  C  D  E 
 Data.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ; 0
 Data.b -1, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1 ; 1
 Data.b -1,-1,-1,-1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1,-1 ; 2
 Data.b -1, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1 ; 3
 Data.b -1, 0,-1,-1,-1, 0,-1, 0,-1,-1,-1,-1, 0,-1,-1 ; 4
 Data.b -1, 0,-1, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0,-1 ; 5
 Data.b -1, 0,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1 ; 6
 Data.b -1, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0,-1, 0,-1 ; 7
 Data.b -1, 0,-1, 0,-1,-1,-1,-1,-1,-1,-1, 0,-1, 0,-1 ; 8
 Data.b -1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1 ; 9
 Data.b -1,-1,-1, 0,-1,-1,-1,-1, 0,-1,-1,-1,-1, 0,-1 ; A
 Data.b -1, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1, 0,-1 ; B
 Data.b -1,-1,-1, 0,-1,-1,-1, 0,-1,-1,-1,-1,-1, 0,-1 ; C
 Data.b -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1 ; D
 Data.b -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 ; E
 
EndDataSection

Restore DataLaby
Read.b Tables\L
Read.b Tables\H
; Initialise les tables avec les bonnes valeurs
FreeArray( Tables\Laby () ) : Dim Tables\Laby.w ( Tables\L , Tables\H )
FreeArray( Tables\Chemin() ) : Dim Tables\Chemin.Pt( Tables\L * Tables\H )

Dim LabyStr.s ( Tables\L , Tables\H )
; Chargement des tables
For y = 0 To Tables\H
 For x = 0 To Tables\L
 Read.b Val1
 Tables\Laby( x , y ) = Val1
 If Val1 < 0 : LabyStr ( x , y ) = "#"
 Else : LabyStr ( x , y ) = " "
 EndIf
 Next 
Next


; ************************************************
; Les coordonnées du points de départ et d'arrivée
; peuvent être modifier ici.
; Les valeurs vont de 1 à 13 en x et en y.
DepartX = 9 : DepartY = 1
ArriveeX = 7 : ArriveeY = 13


; ********************************
; Controle la validité des valeurs
If LabyStr (  DepartX , DepartY ) <> " " : Debug "Invalide Depart." : End : EndIf
If LabyStr (  ArriveeX , ArriveeY ) <> " " : Debug "Invalide Arrivee." : End : EndIf
If DepartX < 1 Or DepartX > Tables\L : Debug "Invalide DepartX." : End : EndIf
If DepartY < 1 Or DepartY > Tables\H : Debug "Invalide DepartY." : End : EndIf
If ArriveeX < 1 Or ArriveeX > Tables\L : Debug "Invalide ArriveeX." : End : EndIf
If ArriveeY < 1 Or ArriveeY > Tables\H : Debug "Invalide ArriveeY." : End : EndIf


; *************************************************
; La recherche du chemin le plus court, c'est ici.
; avec les coordonnées de départ, d'arrivée, valeur initialisée à 0 et
; la variable structurée contenant les tables nécessaire au traitement.
Pcc ( DepartX , DepartY , ArriveeX , ArriveeY , 0 , @Tables )
; Dimensionne le tableau de résultat puis remplit celui-ci en partant du point d'arrivé.
; Tables\Laby ( ArriveeX , ArriveeY ) contient la distance minimale entre les deux points.
; C'est le nombre d'éléments du tableau
Dim Resultat.Pt ( Tables\Laby ( ArriveeX , ArriveeY ) )
ChargeResultat ( ArriveeX , ArriveeY , @Tables , Resultat() )



; **********************
; Affiche les résultats
Debug ""
Debug "*************************"
Debug "Affichage des résultats :"
Debug "Départ : x = " + Str( DepartX ) + " : y = " + Str( DepartY )
Debug "Arrivée : x = " + Str( ArriveeX ) + " : y = " + Str( ArriveeY )

Debug "Contenu du tableau Laby( x , y ) :"
For y = 0 To Tables\H
 a$ = ""
 For x = 0 To Tables\L
 If Tables\Laby( x , y ) = -1
 a$ + "XXX:"
 Else
 a$ + RSet( Str( Tables\Laby( x , y ) ) , 3 , " ") + ":" 
 EndIf
 Next 
 Debug a$
 Next
 Debug ""

Debug "Chemin à suivre :"
For n = 1 To Tables\Laby ( ArriveeX , ArriveeY )
 Debug Str( n ) + " : x = " + Str( Resultat ( n )\x ) + " : y = " + Str( Resultat ( n )\y )
 LabyStr ( Resultat ( n )\x , Resultat ( n )\y ) = "o"
Next
Debug ""

Debug "le tracé :"
LabyStr ( DepartX , DepartY ) = "D"
LabyStr ( ArriveeX , ArriveeY ) = "A"
For y = 0 To Tables\H
 a$ = ""
 For x = 0 To Tables\L
 a$ + LabyStr ( x , y ) + " "
 Next 
 Debug a$
Next
Debug ""

Dernière modification par plabouro472 le dim. 08/mars/2026 15:26, modifié 1 fois.
Avatar de l’utilisateur
SPH
Messages : 5088
Inscription : mer. 09/nov./2005 9:53

Re: Recherche le plus court chemin entre deux point dans un labyrinthe

Message par SPH »

Merci bien.

Je ne l'ai pas testé car je n'en ai pas l'utilité actuellement. Mais je crois me souvenir que je me suis penché sur ce thème il y a longtemps sans y arriver.

:idea:

!i!i!i!i!i!i!i!i!i!
!i!i!i!i!i!i!
!i!i!i!
//// Informations ////
Intel Core i7 4770 64 bits - GTX 650 Ti
Version de PB : 6.12LTS- 64 bits
Répondre