IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Classe, pile, pointeurs et casse-tête!


Sujet :

Langage Delphi

  1. #1
    Expert confirmé
    Avatar de zazaraignée
    Profil pro
    Étudiant
    Inscrit en
    Février 2004
    Messages
    3 174
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2004
    Messages : 3 174
    Points : 4 085
    Points
    4 085
    Par défaut Classe, pile, pointeurs et casse-tête!
    Bonjour

    Avant de m'arracher les cheveux, je demande un peu de votre aide.
    J'ai défini, dans un fichier d'unité (.pas), une classe qui gère une pile d'adresses en mémoire vive. Cette classe possède, entre autres, une procédure (méthode) d'empilement et une procédure (autre méthode) de dépilement.

    Empilement:
    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
    procedure ClPileDeCellules.EmpilerElement (piLigne   : integer;
                                               piColonne : integer);
    var
        lpCourant : TpPointeurPile;
    begin
    // Ajout à la pile vide;
    new (lpCourant);
        lpCourant^.Ligne := piLigne;
        lpCourant^.Colonne :=piColonne;
    if (gpDessus = nil) then
        begin
        lpCourant^.Suivant := nil
        end
      // Ajout au dessus de la pile
      else
        begin
        lpCourant^.Suivant := gpDessus
        end;
    gpDessus := lpCourant;
    inc (NbrElements)
    end;
    Dépilement:
    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
    procedure ClPileDeCellules.DepilerElement(var piLigne      : integer;
                                              var piColonne    : integer;
                                              var piCodeErreur : integer);
    var
        lpCourant : TpPointeurPile;
    begin
    piCodeErreur := 0; // j'usqu'à maintenant, aucune erreur... pas commencé!
    if (gpDessus = nil) then
        begin
        piCodeErreur := 1; // aucun élément dans la pile
        end
      else
        begin
        lpCourant := gpDessus;
        gpDessus  := lpCourant^.Suivant;
        dispose   (lpCourant);
        piLigne   := gpDessus^.Ligne;
        piColonne := gpDessus^.Colonne;
        dec (NbrElements)
        end
    end;
    Dans mon unité appelante (une Form), j'ai un 'rat' qui cherche la sortie d'un labyrinthe (un StringGrid avec des cases noires, les murs, et des cases blanches, les chemins) pour en trouver la sortie.

    La première fois, le rat parcourt par essai et erreur pour trouver la sortie. à force d'empiler et de dépiler son chemin, à la fin, le contenu de la pile correspond à son meilleur parcours. Vous me suivez? Je dois emmagasiner dans une deuxième pile le bon chemin contenu dans la première. Pour ce faire, je dois emplier la deuxième avec le dépilement de la première. Parce que tel quel, il est à l'envers, le chemin de la deuxième pile. Vous me suivez toujours?

    À l'initialisation de la form, la pile emmagasine l'adresse actuelle du rat. Donc la pile a une longueur de 1 élément.

    Ma procédure:
    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
    procedure TFrmTP1CI.BtbParcourirLabyrintheClick(Sender: TObject);
    var
        lbFin        : boolean;
        liDirection  : integer;
        liLigne      : integer;
        liColonne    : integer;
        liCodeErreur : integer;
    begin
    lbFin := false;
    giNbrMouvements := 0;
    // si l'utilisateur recommence, initialiser l'application
    if gaPileParcours.NbrElements > 1 then
        begin
        MemoriserParcours;
        InitialiserLabyrinthe;
        // forcer à redessiner toute la grille
        StgLabyrinthe.Repaint;
        StbMessages.Panels[0].Text := 'Le rat recommence le parcours.';
        while gaMeilleurParcours.NbrElements > 0 do
            begin
            application.ProcessMessages;
            gaMeilleurParcours.DepilerElement(liLigne, liColonne, liCodeErreur);
            if liCodeErreur = 0 then
                begin
                gaMarqueurs[StgLabyrinthe.Row, StgLabyrinthe.Col] := 'P';
                gaMarqueurs[liLigne, liColonne] := 'R';
                StgLabyrinthe.Row := liLigne;
                StgLabyrinthe.Col := liColonne;
                StbMessages.Panels[2].Text :=
                                      IntToStr (gaMeilleurParcours.NbrElements);
                inc (giNbrMouvements);
                StbMessages.Panels[4].Text := IntToStr (giNbrMouvements)
                end
            end
        end
      else
        begin
        StbMessages.Panels[0].Text := 'Le rat cherche la sortie.';
        lbFin                      := false;  // variable de test
        while not lbFin do
            begin
            application.ProcessMessages;
            inc (giNbrMouvements);
            StbMessages.Panels[2].Text := IntToStr (gaPileParcours.NbrElements);
            StbMessages.Panels[4].Text := IntToStr (giNbrMouvements);
            liDirection := Direction (StgLabyrinthe.Row, StgLabyrinthe.Col);
            if liDirection = 0 then
                begin
                // Reculer
                Reculer (liLigne, liColonne);
                if (liLigne = 0) and (liColonne = 0) then
                    begin
                    lbFin                      := true;
                    StbMessages.Panels[0].Text := 'Aucune sortie possible.'
                    end
                end
              else
                begin
                // Avancer
                Avancer (liDirection, liLigne, liColonne);
                if (liLigne = ciRowMax) and (liColonne = ciColMax) then
                    begin
                    lbFin                      := true;
                    StbMessages.Panels[0].Text := 'Bon appétit, le rat!'
                    end
                end;
            sleep (giVitesse)
            end
        end
    end;
    Tout va bien quand je clique une première fois. C'est lorsque je veux que mon rat parcoure à nouveau le labyrinthe que ça se gate. J'ai un message d'erreur
    Le projet PTP1CI.exe a provoqué une classe d'exception EAccessViolation avec le message "Violation d'accès à l'adresse .... dans le module..." Processus stoppé. Utilisez Pas-à-pas...
    Vous avez une idée?

  2. #2
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 561
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 561
    Points : 3 951
    Points
    3 951
    Par défaut
    Salut

    Pour commencer, évite de rappeler les extensions des fichiers d'unité, c'est absolument inutile en ce lieu, les personnes susceptibles de t'apporter de l'aide ont quelques connaissances sur Delphi. D'où ton message je suppose.

    Le fait de préciser qu'une variable est locale par un préfixe n'est pas très pertinent, il vaut mieux si tu veux qualifier la portée, préciser qu'elle est globale car ce sont surtout les variables globales qui doivent être mises en évidence.

    Pour définir ta pile, pourquoi ne t'es-tu pas servi d'un objet TList, quitte à "l'habiller" avec une interface de pile ?

    Enfin, la gestion des erreurs par code de retour est "scandaleuse" avec Delphi qui propose une gestion par exception beaucoup plus pertinente en terme de qualité et de robustesse (il faut prendre de bonnes habitudes).

    En outre, l'interface de ta pile et son utilisation :
    - laissse à penser que tu as l'intention d'avoir une erreur (c'est le genre d'événement dont on se passe),
    - conduit à se mettre d'accord sur les codes d'erreur (difficile dans un grand projet),
    - que veut dire 1 (dans le cas de ton code c'est simple mais sur un gros programme, tu souffres vite même avec ton propre code), définis au moins des constantes

    En quoi le fait qu'une pile soit vide constitue une erreur ? Une méthode PileVide (par exemple) retournant True si la pile est vide aurait augmenté la clarté de ton code qui se documenterait de lui-même, en plus tu fais appel à une routine Depiler dans un contexte illégitime puisqu'elle est vide, c'est pas vraiment chouette.

    Je te dis tout cela car un programme a aussi un aspect de communication et doit donc le plus facilement interprétable par d'éventuels lecteurs (nous par exemple, sur le forum).

    Pour tenter de répondre à ta question :
    J'ai l'impression que tu ne nous as pas transmis tout les éléments (où se trouve le transfert des éléments de la première vers l'autre? que fait MemoriserParcours ?...) .

    >>>>>>>>>>>>>>>>>Donnes des précisions.

    cdlt

    e-ric

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  3. #3
    Expert confirmé
    Avatar de zazaraignée
    Profil pro
    Étudiant
    Inscrit en
    Février 2004
    Messages
    3 174
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2004
    Messages : 3 174
    Points : 4 085
    Points
    4 085
    Par défaut
    Merci pour ta réponse
    Citation Envoyé par e-ric
    Le fait de préciser qu'une variable est locale par un préfixe n'est pas très pertinent, il vaut mieux si tu veux qualifier la portée, préciser qu'elle est globale car ce sont surtout les variables globales qui doivent être mises en évidence.
    Je n'aipas le choix, c'est une norme définie par le collège et qui est à respecter faute de perdre des points. Dans le coins, il y a quelques grandes entreprise qui définissent aussi de telles normes. Autant s'habituer tout de suite.
    Citation Envoyé par e-ric
    Pour définir ta pile, pourquoi ne t'es-tu pas servi d'un objet TList, quitte à "l'habiller" avec une interface de pile ?
    Parce qu'on n'y est pas encore! Mais ça viendra dans les semaines à venir.

    Je passe par dessus la phylosophie de gestion des erreurs... Je n'ai pas envie de partir un débat sur le sujet. Sache que je ne suis pas en désacord avec ce que tu dis. On a juste suivi les instructions du prof.

    Citation Envoyé par e-ric
    Pour tenter de répondre à ta question :
    J'ai l'impression que tu ne nous as pas transmis tout les éléments (où se trouve le transfert des éléments de la première vers l'autre? que fait MemoriserParcours ?...) .
    En effet il manquait le principal: la procédure MémoriserParcours. En ce moment je la modifie.

    J'essayais bêtement d'utiliser deux fois la même classe (avec le même pointeur de dessus de pile)... avec l'erreur que l'on connaît.

    Je voulais 'transvider' ma pile dans une autre pile pour mettre le dessus en dessous et inversement. En de détruisant pas ma première pile, même si je déclarais une autre variable de cette classe, au niveau de la classe le pointeur gpDessus servait aux deux piles... Problème!

    Actuellement, Je crée un petit tableau en local qui conserve les données de la pile (en la dépilant) et les retourne (en la réempilant).

    Je vous donne des nouvelles si ça marche ou non.

    Merci encore.

  4. #4
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 561
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 561
    Points : 3 951
    Points
    3 951
    Par défaut
    Citation Envoyé par zazaraignée
    Merci pour ta réponse
    Citation Envoyé par e-ric
    Le fait de préciser qu'une variable est locale par un préfixe n'est pas très pertinent, il vaut mieux si tu veux qualifier la portée, préciser qu'elle est globale car ce sont surtout les variables globales qui doivent être mises en évidence.
    Je n'aipas le choix, c'est une norme définie par le collège et qui est à respecter faute de perdre des points. Dans le coins, il y a quelques grandes entreprise qui définissent aussi de telles normes. Autant s'habituer tout de suite.
    Citation Envoyé par e-ric
    Pour définir ta pile, pourquoi ne t'es-tu pas servi d'un objet TList, quitte à "l'habiller" avec une interface de pile ?
    Parce qu'on n'y est pas encore! Mais ça viendra dans les semaines à venir.

    Je passe par dessus la phylosophie de gestion des erreurs... Je n'ai pas envie de partir un débat sur le sujet. Sache que je ne suis pas en désacord avec ce que tu dis. On a juste suivi les instructions du prof.

    Citation Envoyé par e-ric
    Pour tenter de répondre à ta question :
    J'ai l'impression que tu ne nous as pas transmis tout les éléments (où se trouve le transfert des éléments de la première vers l'autre? que fait MemoriserParcours ?...) .
    En effet il manquait le principal: la procédure MémoriserParcours. En ce moment je la modifie.

    J'essayais bêtement d'utiliser deux fois la même classe (avec le même pointeur de dessus de pile)... avec l'erreur que l'on connaît.

    Je voulais 'transvider' ma pile dans une autre pile pour mettre le dessus en dessous et inversement. En de détruisant pas ma première pile, même si je déclarais une autre variable de cette classe, au niveau de la classe le pointeur gpDessus servait aux deux piles... Problème!

    Actuellement, Je crée un petit tableau en local qui conserve les données de la pile (en la dépilant) et les retourne (en la réempilant).

    Je vous donne des nouvelles si ça marche ou non.

    Merci encore.
    C'est pas grave, c'était juste des avis, tes profs ont fait du pascal, on reconnaît des choses.

    C'est quoi le malaise sur la gestion des erreurs ?

    Vous faites de la programmation Delphi au Collège ? C'est luxe !

    En dehors du code sur le labyrinthe, pourrais-tu poster le code de gestion de ta pile (méthodes, variable, référence ...), tout ce qui permet d'en expliquer le fonctionnement. Si ton problème est localisé à cette gestion, je pourrais peut-être t'aider à le résoudre.

    cdlt

    e-ric

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  5. #5
    Modérateur
    Avatar de tourlourou
    Homme Profil pro
    Biologiste ; Progr(amateur)
    Inscrit en
    Mars 2005
    Messages
    3 862
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Biologiste ; Progr(amateur)

    Informations forums :
    Inscription : Mars 2005
    Messages : 3 862
    Points : 11 330
    Points
    11 330
    Billets dans le blog
    6
    Par défaut
    il y a mieux que le TList pour les piles : TStack (FIFO) ( et il existe le TQueue (LIFO) )
    Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
    . Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !

  6. #6
    Expert confirmé
    Avatar de zazaraignée
    Profil pro
    Étudiant
    Inscrit en
    Février 2004
    Messages
    3 174
    Détails du profil
    Informations personnelles :
    Localisation : Canada

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2004
    Messages : 3 174
    Points : 4 085
    Points
    4 085
    Par défaut
    Bonjour

    Bon! Aujourd'hui, le travail est remis. J'ai donc décidé de ne plus me casser la tête avec les extras. Car en fin de compte, et effectivement, le parcours optimal se gère mieux dans une liste que dans une pile.

    Le but de l'exercice était juste de nous faire manipuler des piles (files et listes) avant de passer au composant TList.

    Je crois que ces notions nous serons très utiles lorsque nous passerons à la programmation en Java et en C.

    Pour le reste Je suis d'accord avec vous, les listes sont certainement plus faciles à gérer avec les composants que vous m'avez suggéré.

    Ça me fera quelque sujets de discussion avec le prof!

    Merci bien à vous tous!

  7. #7
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 561
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 561
    Points : 3 951
    Points
    3 951
    Par défaut
    Salut

    Disons que c'est un apprentissage académique, cela permet aux étudiants de bien comprendre les structures fondamentales, c'est déjà bien.

    Mais la mise en oeuvre dans un langage particulier s'éloigne souvent de cette manière de faire, ce qui n'est pas forcément condamnable (exemple : Delphi où il existe une bonne cohésion dans les classes de base)

    TStack n'est pas disponible dans toutes les versions de Delphi à ma connaissance (les dernières seulement).

    Il faut dire que ce n'est pas très dur à coder d'une façon assez générique (il suffit de s'inspirer de l'implémentation de TList en définissant une interface et un comportement de pile) même si les mécanisme les plus adapté pour ce genre de programmation n'existe pas (grande absence durement ressentie :-()

    Rappelle quand tu veux et même envoie ton prof sur le forum, on pourra discuter!

    cdlt

    e-ric

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Les classes! un casse tête
    Par georgeslb dans le forum Débuter avec Java
    Réponses: 9
    Dernier message: 18/11/2010, 22h48
  2. Conception d'une classe : casse-tête
    Par Tomaka17 dans le forum C++
    Réponses: 9
    Dernier message: 22/03/2009, 17h09
  3. casse-tête sur les adresses (classe C et A)
    Par HuZimA dans le forum Protocoles
    Réponses: 7
    Dernier message: 27/07/2006, 13h05
  4. [Tableaux] Casse têtes de boucles
    Par Anduriel dans le forum Langage
    Réponses: 5
    Dernier message: 28/06/2006, 00h24
  5. casse-tête excel
    Par gregius dans le forum Access
    Réponses: 2
    Dernier message: 21/09/2005, 16h38

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo