
Ce n'est pas une question, c'est une réponse.
Afin de ne pas maltraiter la pauvre souris, maintenez la touche "enter" enfoncée.
Soyez sympa avec elle...
Pour les explications, je vous recommande ce site qui est très bien conçu.
http://datagenetics.com/blog/november22015/
Il est en anglais mais Google traduira pour vous.Les explications sont clair et détaillés.
C'est là le point de départ de l'outil que je vous propose aujourd'hui.
Il nous faudra :
Un tableau de jeu dimensionné
Une fenêtre, pour afficher les gadgets.
Un graphisme des différents passages possibles 16 tuiles au total numéroté de 0 à 15
Les tuiles doivent être carré et au nombre de 16 et collés les unes aux autres sans séparation
La configuration des numéros de tuiles est binaire et un bit a 1 correspond a une cloison.
0000 = Pas de cloisons
0001 = Cloison au nord
0010 = Cloison a l'est
0100 = Cloison au sud
1000 = Cloison a l'est
1111 = Cloison de tous cotes
Avec pour les 16 tuiles :
00 = 0000 = Pas de Cloison
01 = 0001 = Cloison Nord
02 = 0010 = Cloison Est
03 = 0011 = Cloison Nord & Est
04 = 0100 = Cloison Sud
05 = 0101 = Cloison Sud & Nord
06 = 0110 = Cloison Sud & Est
07 = 0111 = Cloison Sud & Est & Nord
08 = 1000 = Cloison Ouest
09 = 1001 = Cloison Ouest & Nord
10 = 1010 = Cloison Ouest & Est
11 = 1011 = Cloison Ouest & Est & Nord
12 = 1100 = Cloison Ouest & Sud
13 = 1101 = Cloison Ouest & Sud & Nord
14 = 1110 = Cloison Ouest & Sud & Est
15 = 1111 = Cloison Ouest & Sud & Est & Nord
Ici, les tuiles sont générées automatiquement mais vous pouvez charger les votre avec
Code : Tout sélectionner
Tuiles .i = LoadImage( #PB_Any , Fichier$ , 0 )
Comme par exemple ceci :
Code : Tout sélectionner
; on cré un écran et son image si on souhaite visualiser la construction
; Si non, on met en commentaire les 3 lignes suivantes
ImageEcran .i = CreateImage ( #PB_Any , DimX * 8 , DimY * 8 , 24 , #White )
Ecran .i = ImageGadget ( #PB_Any , 10 , 10 , DimX * 8 , DimY * 8 , 0)
Maze2D::InitSurface ( Tuiles , ImageEcran , Ecran )
Code : Tout sélectionner
; Positionnez un obstacle aux coordonnée 10,5 de dimension 10 par 5
PosX = 1 : PosY = 10
Large = 10 : Haut = 5
For y = 0 To Haut-1
For x = 0 To Large-1
TableJeu( PosX + X, PosY + Y ) = -1
Next
Next
; Positionnez un obstacle aux coordonnée 15, 1 de dimension 5 par 10
PosX = 20 : PosY = 1
Large = 15 : Haut = 20
For y = 0 To Haut-1
For x = 0 To Large-1
TableJeu( PosX + X, PosY + Y ) = -1
Next
Next
C'est préférable sinon la première case (qui est choisie au hasard) pourrait se trouver au milieu d'un obstacle.
Code : Tout sélectionner
Maze2D::Create( TableJeu( ) , 44 , 15 )
sans les paramètres, le point de départ est choisi au hasard.
Code : Tout sélectionner
Maze2D::Create( TableJeu( ) )

Voici maintenant la démo avec son module Maze2D
Code : Tout sélectionner
; *********************************
; *** Module de gestion de pile ***
; * Empile des valeurs numériques *
; * *
; Entièrement autonome, il peut être utilisé dans toutes autres application.
DeclareModule Pile
; ******** Constantes et variables Publiques ***************
; Rien de public à déclarer
; ******** Declaration des procedures Publiques ***************
Declare .i GetIndex ( ) ; Retourne le nombre d'éléments dans la pile.
Declare Push ( Valeur.i ) ; Empile une valeur numérique.
Declare .i Pop ( ) ; Retourne l'élément précédemment empilé.
Declare .b IsEmpty ( ) ; Teste si la pile est vide retourne vrai / faux.
Declare .b IsFull ( ) ; Teste si la pile est pleine retourne vrai / faux.
Declare .i Last ( ) ; Retourne le dernier élément de la pile sans le dépiler ( ce n'est pas un "Pop()" ).
Declare Clr ( ) ; Vide la pile complétement.
EndDeclareModule
Module Pile
; ******** Constantes et variables privées ***************
Global NewList TableVal .i ( )
; ******** Procedures Privées ***************
; Il n'y en a pas.
; ******** Procedures Publiques ************
; Celles qui ont été déclarer plus haut
Procedure .i GetIndex( )
ProcedureReturn ListIndex( TableVal() )
EndProcedure
Procedure Push ( Valeur.i )
AddElement( TableVal() )
TableVal() = Valeur
EndProcedure
Procedure .i Pop ( )
Protected ValTmp.i
If LastElement(TableVal()) <> 0
ValTmp = TableVal()
DeleteElement( TableVal() )
ProcedureReturn ValTmp
Else
ProcedureReturn -1
EndIf
EndProcedure
Procedure .b IsEmpty ( )
ProcedureReturn Bool( LastElement( TableVal( ) ) = 0 )
EndProcedure
Procedure .b IsFull ( )
ProcedureReturn Bool( LastElement( TableVal( ) ) <> 0 )
EndProcedure
Procedure .i Last ( )
If LastElement( TableVal() ) <> 0
ProcedureReturn TableVal()
Else
ProcedureReturn -1
EndIf
EndProcedure
Procedure Clr ( )
ClearList(TableVal())
EndProcedure
; ******* Initialisation *******
; Rien à initialiiser
EndModule
; * *
; *** Fin du module pile ***
; *********************************
; ********************************
; *** Module de construction ***
; * d'un labyrinthe Maze2D *
; * *
; Entièrement autonome, il peut être utilisé dans toutes autres application.
DeclareModule Maze2D
; ******** Constantes et variables Publiques ***************
; ******** Declaration des procedures Publiques ***************
Declare Create ( Array Table.i( 2 ) , StartX.i = -1 , StartY.i = -1 ) ; Lance la création du labyrinthe
Declare InitSurface ( IdGraphe.i , IdSurface.i , IdGadget.i ) ; Initialise l'écran de visualisation
EndDeclareModule
Module Maze2D
; ******** Constantes et variables privées ***************
Global Xmax .i
Global Ymax .i
Global Xdim .i
Global Ydim .i
Global TuilesIdGraphe .i
Global TuileLargeure .i
Global TuileHauteur .i
Global DessinIdSurface .i
Global DessinIdGadget .i
;Global DessinTempo .i
Global PerceDessus .a = %1110
Global PerceDroite .a = %1101
Global PerceDessous .a = %1011
Global PerceGauche .a = %0111
Global Trace .a = #False
Global Dim TbDirectionsPossibles( 3 )
; ******** Procedures Privées ***************
Procedure .i GrilleGetPos ( ValX.i , ValY.i )
; Reccupération du numéro de case en fonction de ses coordonnées
ProcedureReturn ValY * Xdim + ValX
EndProcedure
Procedure .i GrilleGetX ( ValPos.i )
; Reccupération de la coordonnée X en fonction du numéro de case
ProcedureReturn ValPos % Xdim
EndProcedure
Procedure .i GrilleGetY ( ValPos.i )
; Reccupération de la coordonnée Y en fonction du numéro de case
ProcedureReturn Int( ValPos / Xdim )
EndProcedure
Procedure AfficheBloc ( PosX.i , PosY.i , Sp.i )
; Affiche la tuile Sp aux coordonnées PosX , PosY
If Sp = -1 : Sp = 15 : EndIf
If Trace
Protected IdBlockImageTmp .i
IdBlockImageTmp = GrabImage( TuilesIdGraphe , #PB_Any , Sp * TuileLargeure , 0 , TuileLargeure , TuileHauteur )
StartDrawing ( ImageOutput( DessinIdSurface ) )
DrawImage ( ImageID( IdBlockImageTmp ) , PosX * TuileLargeure , PosY * TuileHauteur )
StopDrawing ( )
SetGadgetState ( DessinIdGadget , ImageID( DessinIdSurface ) )
FreeImage( IdBlockImageTmp )
EndIf
EndProcedure
Procedure ConnectionCases ( Array Table.i( 2 ) , Case1.i , Case2.i )
; Raccordement des 2 cases
Protected Dx .w
Protected Dy .w
Protected Cx1 .i
Protected Cy1 .i
Protected Cx2 .i
Protected Cy2 .i
Protected Sp .a
Cx1 = GrilleGetX( Case1 )
Cy1 = GrilleGetY( Case1 )
Cx2 = GrilleGetX( Case2 )
Cy2 = GrilleGetY( Case2 )
Dx = Cx2 - Cx1 ; si Dx positif, case2 est à droite de case 1 sinon à gauche
Dy = Cy2 - Cy1 ; si Dy positif, case2 est dessous de case 1 sinon dessus
If Dx > 0 ; case2 est à droite de Case 1
Sp = Table( Cx1 ,Cy1 ) & PerceDroite
Table( Cx1 , Cy1 ) = Sp
AfficheBloc( Cx1 , Cy1 , Sp )
Sp = Table( Cx2 ,Cy2 ) & PerceGauche
Table( Cx2 , Cy2 ) = Sp
AfficheBloc( Cx2 , Cy2 , Sp )
Txt$ = "Je suis parti à droite."
EndIf
If Dx < 0 ; case2 est à gauche de Case 1
Sp = Table( Cx1 , Cy1 ) & PerceGauche
Table( Cx1 , Cy1 ) = Sp
AfficheBloc( Cx1 , Cy1 , Sp )
Sp = Table( Cx2 , Cy2 ) & PerceDroite
Table( Cx2 , Cy2 ) = Sp
AfficheBloc( Cx2 , Cy2 , Sp )
Txt$ = "Je suis parti à gauche."
EndIf
If Dy > 0 ; case2 est dessous de Case 1
Sp = Table( Cx1 ,Cy1 ) & PerceDessous
Table( Cx1 ,Cy1 ) = Sp
AfficheBloc( Cx1 , Cy1 , Sp )
Sp = Table( Cx2 , Cy2 ) & PerceDessus
Table( Cx2 , Cy2 ) = Sp
AfficheBloc( Cx2 , Cy2 , Sp )
Txt$ = "Je suis parti en bas."
EndIf
If Dy < 0 ; case2 est dessus de Case 1
Sp = Table( Cx1 , Cy1 ) & PerceDessus
Table( Cx1 , Cy1 ) = Sp
AfficheBloc( Cx1 , Cy1 , Sp )
Sp = Table( Cx2 , Cy2 ) & PerceDessous
Table( Cx2 , Cy2 ) = Sp
AfficheBloc( Cx2 , Cy2 , Sp )
Txt$ = "Je suis parti en haut."
EndIf
If Trace
;Txt$ = "Cx2 = " + Str( Cx2 ) + " / Cy2 = " + Str( Cy2 ) + " / Sp = " + Str( Sp )
If MessageRequester( "Pause" , Txt$ , #PB_MessageRequester_YesNo ) = #PB_MessageRequester_No : End : EndIf
EndIf
EndProcedure
Procedure RegardeAutour ( Array Table.i( 2 ) , NoCase.i )
Protected Cx .i
Protected Cy .i
Protected Choix .i
Protected Hasard .i
Protected NbDir .a
NbDir = 0 ; Pour le choix aleatoire de la direction a prendre
Cx = GrilleGetX( NoCase )
Cy = GrilleGetY( NoCase )
Choix = -1
If Cx > 0 ; Regarde à gauche
If Table( Cx - 1 , Cy ) = 15 ; Si = 15 alors Case pas visitée
TbDirectionsPossibles( NbDir ) = GrilleGetPos( Cx - 1 , Cy ); No de la case de gauche
NbDir + 1
EndIf
EndIf
If Cx < Xmax ; Regarde à droite
If Table( Cx + 1 , Cy ) = 15 ; Si = 15 alors Case pas visitée
TbDirectionsPossibles( NbDir ) = GrilleGetPos( Cx + 1 , Cy ); No de la case de droite
NbDir + 1
EndIf
EndIf
If Cy > 0 ; Regarde au dessus
If Table( Cx , Cy - 1 ) = 15 ; Si = 15 alors Case pas visitée
TbDirectionsPossibles( NbDir ) = GrilleGetPos( Cx ,Cy - 1 ); No de la case du dessus
NbDir + 1 ;
EndIf
EndIf
If Cy < Ymax ; Regarde au dessous
If Table( Cx , Cy + 1 ) = 15 ; Si = 15 alors Case pas visitée
TbDirectionsPossibles( NbDir ) = GrilleGetPos( Cx , Cy + 1 ); No de la case du dessous
NbDir + 1 ;
EndIf
EndIf
If NbDir > 0 ; Si on a trouvé au mois une case non visitée
Hasard.i = Random( NbDir , 1 )
Choix = TbDirectionsPossibles( Hasard -1 ) ; On choisi au hasard parmi les cases trouvées
Pile::Push( Choix ) ; Empile Numero de la case choisi
EndIf
If Choix > -1 ; si on a un choix valide, on connecte les deux cases
ConnectionCases( Table() , NoCase , Choix )
EndIf
ProcedureReturn Choix
EndProcedure
; ******** Procedures Publiques ************
Procedure Create ( Array Table.i( 2 ) , StartX.i = -1 , StartY.i = -1 )
; Construction du Labyrinthe
Xmax = ArraySize(Table() , 1 )
Ymax = ArraySize(Table() , 2 )
Xdim = Xmax + 1
Ydim = Ymax + 1
; Si j'ai un gadget avec une surface graphique, j'autorise le tracage
If DessinIdSurface And DessinIdGadget
Trace = #True
EndIf
; Initialise la grille à 15 ( Cases completement cloisonnee )
For y = 0 To Ymax ; Ligne
For x = 0 To Xmax ; Colonne
If Not Table( x, y ) < 0
Table( x, y ) = 15
EndIf
AfficheBloc( x , y , Table( x, y ) ) ; ( x , y , sp )
Next
Next
If StartX = -1 Or StartY = -1
CaseSelectionnee = Random( Xdim * Ydim -1 ); Numero d'une case de départ au hazard
Else
CaseSelectionnee = GrilleGetPos ( StartX , StartY )
EndIf
Pile::Push( CaseSelectionnee ) ; Empile le numero de la case choisi
While Pile::IsFull( ) ; Reboucle Tant que la Pile est pleine
CaseSelectionnee2 = RegardeAutour( Table() , CaseSelectionnee ) ; on choisi une case libre adjacente
If CaseSelectionnee2 = -1 ; Si pas de Case autour
CaseSelectionnee2 = Pile::Pop( ) ; Recupère la dernière case empilée
EndIf
CaseSelectionnee = CaseSelectionnee2 ; La case en cours devient la case choisie ou réccupéré
Wend
; Construction du Labyrinthe terminé
EndProcedure
Procedure InitSurface ( IdGraphe.i , IdSurface.i , IdGadget.i )
TuilesIdGraphe = IdGraphe
TuileLargeure = ImageHeight( IdGraphe )
TuileHauteur = TuileLargeure
DessinIdSurface = IdSurface
DessinIdGadget = IdGadget
EndProcedure
; ******* Initialisation *******
EndModule
; * *
; *** Fin du module Maze2D ***
; *********************************
; **************
; *** DEMO ***
; * *
; La configuration est binaire et un bit a 1 correspond a une cloison.
; %0000 = Pas de cloisons
; %0001 = Cloison au nord
; %0010 = Cloison a l'est
; %0100 = Cloison au sud
; %1000 = Cloison a l'est
; %1111 = Cloison de tous cotes
; Il nous faudra :
; Un tableau de jeu de la dimension suivante :
DimX = 50
DimY = 25
Dim TableJeu.i( DimX - 1 ,DimY - 1 )
; Une fenêtre, pour afficher les gadgets.
Window_0 = OpenWindow ( #PB_Any , 100 , 100 , 600 , 400 , "Maze" , #PB_Window_SystemMenu )
; Un graphisme des différents passages possibles 16 tuiles au total numéroté de 0 à 15 généré ici
Tuiles .i = CreateImage ( #PB_Any , 16 * 8 , 8 , 24 , 0 )
Dim Coul.i (2) ; couleurs des tuiles
Coul( 0 ) = #White
Coul( 1 ) = #Black
Coul( 2 ) = #White ;#Red #White ; On peut changer la couleur rouge ou blanc pour voir
Restore Sp0
; On dessine les tuiles
StartDrawing( ImageOutput( Tuiles ) )
For n=0 To 15
For y=0 To 7
Read.s a$
For x=1 To Len( a$ )
Plot( n*8 + (x-1) , y ,Coul ( Val( Mid( a$ , x , 1 ) ) ) )
Next
Next
Next
StopDrawing()
; on cré un écran et son image si on souhaite visualiser la construction
; Si non, on met en commentaire les 3 lignes suivantes
ImageEcran .i = CreateImage ( #PB_Any , DimX * 8 , DimY * 8 , 24 , #White )
Ecran .i = ImageGadget ( #PB_Any , 10 , 10 , DimX * 8 , DimY * 8 , 0)
Maze2D::InitSurface ( Tuiles , ImageEcran , Ecran )
; On peut placer un ou plusieurs obstacle au milieu du tableau en placant des valeurs négatives
; Positionnez un obstacle aux coordonnée 10,5 de dimension 10 par 5
PosX = 1 : PosY = 10
Large = 10 : Haut = 5
For y = 0 To Haut-1
For x = 0 To Large-1
TableJeu( PosX + X, PosY + Y ) = -1
Next
Next
; Positionnez un obstacle aux coordonnée 15, 1 de dimension 5 par 10
PosX = 20 : PosY = 1
Large = 15 : Haut = 20
For y = 0 To Haut-1
For x = 0 To Large-1
TableJeu( PosX + X, PosY + Y ) = -1
Next
Next
; Création du labyrinthe dans la table à 2 dimensions
; Comme on a placé un obstacle, on défini les coordonnées du point de départ du tracé.
; C'est préférable pour que la première case ne tombe pas au milieu d'un obstacle.
Maze2D::Create( TableJeu( ) , 44 , 15 )
; Mais sans obstacles, les paramétres sont facultatif,
; sans les paramètres, le point de départ est choisi au hasard.
; Maze2D::Create( TableJeu( ) )
; Sauvegarde du tableau dans un fichier texte ( en hexa ) pour une utilisation future
If CreateFile( 0 , "labyrinthe..txt" )
For Y = 0 To DimY - 1
TxtTmp$ = ""
For X = 0 To DimX - 1
If TableJeu( X, Y ) = -1 : TableJeu( X, Y ) = 15 : EndIf
TxtTmp$ + Hex( TableJeu( X, Y ) , #PB_Byte )
If X < DimX + 1 : TxtTmp$ + "," : EndIf
Next
WriteStringN( 0 , TxtTmp$ , #PB_Ascii )
Next
CloseFile( 0 )
EndIf
; La construction est terminée
MessageRequester( "Information." , "Opération Terminé." , #PB_MessageRequester_Ok | #PB_MessageRequester_Info )
Repeat
Until WaitWindowEvent() = #PB_Event_CloseWindow
; Les datas pour le graphique des tuiles
DataSection
Sp0: ; 0000 Pas de mur
Data.s "10022001"
Data.s "00022000"
Data.s "00022000"
Data.s "22222222"
Data.s "22222222"
Data.s "00022000"
Data.s "00022000"
Data.s "10022001"
; 0001 Mur Nord
Data.s "11111111"
Data.s "00000000"
Data.s "00000000"
Data.s "22222222"
Data.s "22222222"
Data.s "00022000"
Data.s "00022000"
Data.s "10022001"
; 0010 Mur Est
Data.s "10022001"
Data.s "00022001"
Data.s "00022001"
Data.s "22222001"
Data.s "22222001"
Data.s "00022001"
Data.s "00022001"
Data.s "10022001"
; 0011 Mur Nord & Est
Data.s "11111111"
Data.s "00000001"
Data.s "00000001"
Data.s "22222001"
Data.s "22222001"
Data.s "00022001"
Data.s "00022001"
Data.s "10022001"
; 0100 Mur Sud
Data.s "10022001"
Data.s "00022000"
Data.s "00022000"
Data.s "22222222"
Data.s "22222222"
Data.s "00000000"
Data.s "00000000"
Data.s "11111111"
; 0101 Mur Sud & Nord
Data.s "11111111"
Data.s "00000000"
Data.s "00000000"
Data.s "22222222"
Data.s "22222222"
Data.s "00000000"
Data.s "00000000"
Data.s "11111111"
; 0110 Mur Sud & Est
Data.s "10022001"
Data.s "00022001"
Data.s "00022001"
Data.s "22222001"
Data.s "22222001"
Data.s "00000001"
Data.s "00000001"
Data.s "11111111"
; 0111 Mur Sud & Est & Nord
Data.s "11111111"
Data.s "00000001"
Data.s "00000001"
Data.s "22222001"
Data.s "22222001"
Data.s "00000001"
Data.s "00000001"
Data.s "11111111"
; 1000 Mur Ouest
Data.s "10022001"
Data.s "10022000"
Data.s "10022000"
Data.s "10022222"
Data.s "10022222"
Data.s "10022000"
Data.s "10022000"
Data.s "10022001"
; 1001 Mur Ouest & Nord
Data.s "11111111"
Data.s "10000000"
Data.s "10000000"
Data.s "10022222"
Data.s "10022222"
Data.s "10022000"
Data.s "10022000"
Data.s "10022001"
; 1010 Mur Ouest & Est
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
; 1011 Mur Ouest & Est & Nord
Data.s "11111111"
Data.s "10000001"
Data.s "10000001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
; 1100 Mur Ouest & Sud
Data.s "10022001"
Data.s "10022000"
Data.s "10022000"
Data.s "10022222"
Data.s "10022222"
Data.s "10000000"
Data.s "10000000"
Data.s "11111111"
; 1101 Mur Ouest & Sud & Nord
Data.s "11111111"
Data.s "10000000"
Data.s "10000000"
Data.s "10022222"
Data.s "10022222"
Data.s "10000000"
Data.s "10000000"
Data.s "11111111"
; 1110 Mur Ouest & Sud & Est
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10022001"
Data.s "10000001"
Data.s "10000001"
Data.s "11111111"
; 1111 Mur Ouest & Sud & Est & Nord
Data.s "11111111"
Data.s "10000001"
Data.s "10000001"
Data.s "10022001"
Data.s "10022001"
Data.s "10000001"
Data.s "10000001"
Data.s "11111111"
EndDataSection