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

C Discussion :

redimensionnement d'un tableau dynamique


Sujet :

C

  1. #1
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut redimensionnement d'un tableau dynamique
    Bonjour à tous,
    Je vous écris ce message pour vous demander de l'aide au sujet d'un problème .

    Je programme un jeu de morpion de taille variable.
    J’ai une version qui fonctionne parfaitement.
    Je voulais apporter une modification pour simplifier un peu le code et maintenant, le programme ne fonctionne plus correctement.

    Voici l’idée générale :
    Je définis mes variables, définie 3 tableaux dynamiques
    Dans le main, si je clique sur ModifierLesDimensions, cela m’ouvre une nouvelle page dans laquelle je peux modifier les dimensions. Pour sortir de cette page, soit je clique Annuler, soit je clique Valider.
    Lorsque je veux valider, je reviens dans le main, vide mes tableaux avec leurs anciennes dimensions, redimensionne les tableaux aux nouvelles dimensions, vide les plateaux avec les nouvelles dimensions puis joue normalement.

    Voici mon code qui fonctionne

    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
     
    int main(int argc, char **argv)
    {
        SDL_Surface *ecran=NULL;
        int N=3;
        int M=3;
        int NbJetonsAAligner=3;
        int AncienN=N;
        int AncienM=M;
        int AncienNbJetonsAAligner=NbJetonsAAligner;//on aligne 3 jetons au depart
        Case *plateau;//les Case étant Vide, Crois, Rond
        int *HistoriqueJeton= FonctionAllocation1D(N*M);//Ce tableau doit etre dynamique, efectue le test de bonne attribution
        int *ListeCasesVides= FonctionAllocation1D(N*M);//Tableau qui contient les numeros de toutes les cases vides au debut puis -1 pour les cases occupées.
        int NbCasesJouees=0;
        ...
    ...
        videJeu(plateau, N, M, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu
     
        switch(...)
        {
           case CONFIGDIMENSION:
              joueurEnCours=ListeJoueurs[NbCasesJouees%2];
              AncienN=N;
              AncienM=M;
              AncienNbJetonsAAligner=NbJetonsAAligner;
              ConfigDimension(ecran, police,TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours, &Jeton, &N, &M, &NbJetonsAAligner, &ConfigModifiee);//on ouvre la configuration pour determiner le nombre de lignes et de colonnes du plateau de jeu et le nombre de jetons a aligner pour gagner
              if(ConfigModifiee==OUI)//si on modifie les dimensions du plateau de jeu
                   {
                         videJeu(plateau, AncienN, AncienM, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu APRES d'avoir modifier les dimensions, pour tout remettre a zero
                         free(plateau);
                         plateau=NULL;
                         plateau=malloc(N*M*sizeof(*plateau));//on realloue un plateau aux nouvelles dimensions
                         if(plateau==NULL)//si erreur d'allocation
                             {
                                   free(plateau);//liberation du plateau
                                   fprintf(stderr, "Erreur de creation du tableau plateau");
                                   exit(EXIT_FAILURE);//quitter le programme
                             }
     
                         free(HistoriqueJeton);//on libere HistoriqueJeu
                         HistoriqueJeton=NULL;
                         HistoriqueJeton= FonctionAllocation1D(N*M);//Ce tableau doit etre dynamique, efectue le test de bonne attribution
     
                         free(ListeCasesVides);//on libere HistoriqueJeu
                         ListeCasesVides=NULL;
                         ListeCasesVides= FonctionAllocation1D(N*M);//Tableau qui contient les numeros de toutes les cases vides au debut puis -1 pour les cases occupées.
     
                         videJeu(plateau, N, M, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu AVANT d'avoir modifier les dimensions, sinon, on ne vide pas tout le tableau
                         PlateauJeuLarg=PlateauLarg/maximumEntre(N, M)*N;//Dimension reelle de la zone de jeu quand on personnalise les dimensions
                         PlateauJeuHaut=PlateauHaut/maximumEntre(N, M)*M;
                         ConfigModifiee=NON;
                   }
    ...
        }
       ...
    }
    Avec
    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
     
    void videJeu(Case *plateau, int N, int M, Joueur ListeJoueurs[], Joueur *joueurEnCours, int *PartieFinie, int *NbCasesJouees, int *HistoriqueJeton, int *ListeCasesVides)//Fonction pour vider le plateau de jeu
    {
        int i;
     
        for(i=0; i<N*M; i++)//On vide le plateau
        {
            plateau[i] = Vide;//toutes les cases sont vides
            HistoriqueJeton[i] = -1;//on reinitialise le tableau a -1
            ListeCasesVides[i]=i;//on liste toutes les cases vides du tableau, c'est a dire toute les cases
        }
        *joueurEnCours=ListeJoueurs[0];
        *NbCasesJouees = 0;
        *PartieFinie = NON;//On commence une nouvelle partie
    }
    et
    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
     
    int *FonctionAllocation1D(int dimension)
    {
        int *tableau=malloc(dimension*sizeof(*tableau));//Ce tableau doit etre dynamique
        int i;
        if(tableau==NULL)//si erreur d'allocation
        {
            free(tableau);//liberation du tableau 
            fprintf(stderr, "Erreur de creation du tableau ");
            exit(EXIT_FAILURE);//quitter le programme
        }
     
        for (i=0; i<dimension; i++) //On initialise le tableau avec 0
        {
            tableau[i]=0;
        }
     
        return tableau;
    }
    J’ai voulu remplacer une partie entre les lignes 27 et 52 par une fonction qui gère tout cela (car j’aurai besoin de la réutiliser dans une autre fonction, donc je voulais simplifier plutôt que de réécrire la vingtaine de lignes)
    Le main que j’obtiens deviens …

    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
     
    case CONFIGDIMENSION:
                        joueurEnCours=ListeJoueurs[NbCasesJouees%2];
                        AncienN=N;
                        AncienM=M;
                        AncienNbJetonsAAligner=NbJetonsAAligner;
                        ConfigDimension(ecran, police,TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours, &Jeton, &N, &M, &NbJetonsAAligner, &ConfigModifiee);//on ouvre la configuration pour determiner le nombre de lignes et de colonnes du plateau de jeu et le nombre de jetons a aligner pour gagner
                        if(ConfigModifiee==OUI)//si on modifie les dimensions du plateau de jeu
                        {
                            ModificationConfigDimension(AncienN, AncienM, N,M, plateau, ListeJoueurs,&joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);
                            ConfigModifiee=NON;
                            PlateauJeuLarg=PlateauLarg/maximumEntre(N, M)*N;//Dimension reelle de la zone de jeu quand on personnalise les dimensions
                            PlateauJeuHaut=PlateauHaut/maximumEntre(N, M)*M;
     
                        }
    avec
    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
     
    void ModificationConfigDimension(int AncienN,int AncienM,int NouveauN,int NouveauM,Case *plateau, Joueur ListeJoueurs[], Joueur *joueurEnCours, int *PartieFinie, int *NbCasesJouees, int *HistoriqueJeton, int *ListeCasesVides)
    {
        //si seul le NbJetonAAligner a changé, alors on vide le plateau
    //si N ou M a changé, il faut tout vider et faire les realloc puis vider le jeu
     
        if((AncienN !=NouveauN)||(AncienM!=NouveauM))
        {
            videJeu(plateau, AncienN, AncienM, ListeJoueurs, joueurEnCours, PartieFinie, NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu AVANT d'avoir modifier les dimensions, pour tout remettre a zero
            free(plateau);
            plateau=NULL;
            plateau=malloc(NouveauN*NouveauM*sizeof(*plateau));//on realloue un plateau aux nouvelles dimensions
            if(plateau==NULL)//si erreur d'allocation
            {
                free(plateau);//liberation du plateau
                fprintf(stderr, "Erreur de creation du tableau plateau");
                exit(EXIT_FAILURE);//quitter le programme
            }
     
            free(HistoriqueJeton);//on libere HistoriqueJeu
            HistoriqueJeton=NULL;
            HistoriqueJeton= FonctionAllocation1D(NouveauN*NouveauM);//Ce tableau doit etre dynamique
     
            free(ListeCasesVides);//on libere ListeCasesVides
            ListeCasesVides=NULL;
            ListeCasesVides= FonctionAllocation1D(NouveauN*NouveauM);//Tableau qui contient les numeros de toutes les cases vides au debut puis -1 pour les cases occupées.
     
        }
        videJeu(plateau, NouveauN, NouveauM, ListeJoueurs, joueurEnCours, PartieFinie, NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu APRES d'avoir modifier les dimensions, sinon, on ne vide pas tout le tableau
     
    }


    Je n’ai pas d’alerte au moment de la compilation.
    Sauf que lorsque je redimensionne, j’ai parfois quelques jetons qui se placent sur le plateau et certaines cases ne sont pas accessibles.
    Mais surtout, lorsque je redimensionne encore une fois, ou lorsque je vide le jeu suite à une nouvelle partie, le programme plante.
    Il semblerait qu’il y ait des erreurs au niveau de free(HistoriqueJeton) et free(ListeCasesVides).
    Je pencherai au niveau d'un problème de passage de paramètres/pointeurs à la fonction videJeu ou au moment de la création des tableaux avec les nouvelles dimensions.

    Je vous remercie de l'aide que vous pourrez m'apporter.
    Cordialement
    Ludovic

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Bonjour

    Ton code me parait bien confus. Avec tes "et je vide avec l'ancienne dimension, et je vide avec les nouvelles dimensions" et autres.

    Il faut que tu sois clair dans tes idées. Est-ce que tu veux changer les dimensions en cours de partie ou bien (ce que je crois) proposer simplement le choix de la dimension au début de la partie. Dans ce cas, ce n'est pas un "redimensionnement" qu'il te faut mais simplement un "dimensionnement". Si par exemple tu veux que le programme boucle avec à chaque tour un choix de jeu aux dimensions N, alors il te faut le coder ainsi
    1. début de boucle
    2. proposition du choix des dimensions (avec éventuellement une valeur par défaut)
    3. allocation (et pour ça calloc() ou au pire malloc() + memset() seraient peut-être plus approprié que ton malloc() avec ensuite ta boucle =0)
    4. jeu
    5. libération (et il n'y a aucun souci avec le free())
    6. fin de boucle


    Le "redimensionnement" permet d'agrandir un tableau déjà utilisé sans perdre son contenu. Et pour ça il y a realloc() qui fait tout tout seul (soit agrandissement de ce qui existe déjà, soit allocation ailleurs et recopie de ce qui existe déjà puis libération du vieux). Mais parler de "redimensionnement" quand il s'agit juste de vider ce qui existe (ce qui déjà est un non-sens car une mémoire ne peut pas être "vide") puis allouer un tableau neuf et le mettre à 0 (on se demande alors pourquoi s'être cassé le luc à "vider" l'ancien)...

    Quelques remarques générales: on ne quitte pas un programme au beau milieu d'une fonction. Seul le main() a le droit de faire exit(). Si malloc() échoue, alors ta fonction qui l'utilise doit soit gérer le souci, soit le remonter à l'appelant qui devra lui-même soit gérer le souci, soit le remonter à son propre appelant et etc jusqu'au main. Parce que si tu alloues tableau1, que tu alloues tableau2 et que l'allocation de tableau3 échoue, ben tu quittes benoitement ton code et tu te laves les mains de ce qui peut arriver à tableau1 ou tableau2 (certes les OS modernes libèrent eux-mêmes mais ça reste dégueu).
    Ensuite si malloc() échoue alors c'est idiot de faire un free() (ligne 15 de ton nouveau code) qui montre donc que tu ne "ressens" pas réellement ce que tu écris. En plus ça ne marche que parce que free(NULL) a été codé pour être autorisé mais si tu appliques la même politique au fopen() (style si ça échoue alors je fais fclose()) alors c'est le crash assuré.
    Et enfin tu as beaucoup trop de paramètres 'listeJoueurs", "joueurEnCours", "partieFinie", etc. Tu ne connais pas les structures qui te permettent de regrouper plein de trucs ensembles et de les passer d'un coup aux fonctions qui en ont besoin ? D'autant plus que si tu as n tableaux liés (par exemple "liste des cases" lié à "liste des cases vides" et autre), tu regroupes ça dans une structure que tu peux allouer d'un coup => un seul malloc() au lieu de 3 ce qui aide grandement la gestion des échecs).

    Désolé, tu as peut-être fait un truc qui, comme tu dis, "fonctionne parfaitement" mais comme tu l'as mal bâti dès le départ, tu te retrouves coincé pour le faire évoluer. Et tu te retrouves maintenant à rajouter des verrues bancales qui peut-être finiront par fonctionner mais ça aura élevé sa complexité au carré pour le cas où tu voudrais encore le faire évoluer ensuite. Mieux vaudrait repartir sur des bases saines...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Bonjour Sve@r, merci de m'avoir répondu.

    Pour répondre à la 1ere partie de ton message, je te donne quelques précisions car je n'aiposté qu'une version condensée du min.

    - Je lance mon jeu de morpion de dimension 3*3, avec 3 jetons à aligner pour gagner avec le mode humain contre humain.
    - En aucun cas, le jeu demande les dimensions souhaitées
    - La partie de déroule "normalement", en cliquant dans les cases voulue.
    - J'ai défini plusieurs boutons que je peux activer en cliquant de dessus ou alors en saisissant au clavier une lettre : annuler le dernier coup, nouvelle partie, aide, modifier mode de jeu (humain-humain, ou humain-ordi, ou ordi-ordi), modification des dimensions (largeur, hauteur, nombre de jetons à aligner).
    - J'ai deux boucles : la principale pour quitter le jeu (si on a cliqué sur la croix, ou echap, ou bouton quitter), une secondaire pour recommencer une partie (partie finie, ou bouton nouvelle partie).
    - Lorsque je clique sur le bouton ModifierLesDimensions, cela m’ouvre une nouvelle page dans laquelle je peux modifier les dimensions. Pour sortir de cette page, soit je clique Annuler (je conserve les anciennes données), soit je clique Valider (et là, il faut que je recommence avec une nouvelle partie).
    Je t'avais écris que "Lorsque je veux valider, je reviens dans le main, vide mes tableaux avec leurs anciennes dimensions, redimensionne les tableaux aux nouvelles dimensions, vide les plateaux avec les nouvelles dimensions puis joue normalement."
    En fait je pensais que si je passais d'un "grand" tableau 5*6 à un "petit" tableau 3*4 par exemple (donc plus petit), les valeurs "en trop" n'étais pas libérées c'est pour cela que je vidais avec les anciennes dimensions (l29), puis je redéfinissais mon tableau et pour être sûr qu'il soit bien vide, je refaisais un vidage avec les nouvelles dimensions.
    - Comment me conseilles- tu de procéder ?


    Pour les erreurs de fichiers, je sais que ma méthode n'est pas correcte car il y a des exit à plusieurs endroits, mais je ne sais pas comment faire et je ne me sis aps vraiment penché sur la question :
    - Est-ce que je dois rajouter un pointeur Erreur et le passer à chaque fonction qui peut le modifier, et mettre un test du style "si erreur= non, alors ... sinon sortir de la fonction",
    - Faut-il que je je fasse une liste de code d'erreurs erreur_1 (erreur initialisation de cran), erreur_2(erreur initialisation de sdl), erreur_3(erreur initialisation de police),... et traiter les cas avec un switch : si erreur_1 alors libère écran, si erreur_2 alors libère écran+sdl, si erreur_3 alors libère écran+sdl+police,...
    Avec la 20aine d'images que j'ai plus les tableaux, cela me fais beaucoup de cas a envisager.
    - je suis entièrement d'accord avec mon étourderie de la ligne 15 (si malloc() échoue alors c'est idiot de faire un free())

    Merci beaucoup
    Ludovic

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chamludo Voir le message
    - En aucun cas, le jeu demande les dimensions souhaitées
    ...
    - Lorsque je clique sur le bouton ModifierLesDimensions, cela m’ouvre une nouvelle page dans laquelle je peux modifier les dimensions. Pour sortir de cette page, soit je clique Annuler (je conserve les anciennes données), soit je clique Valider (et là, il faut que je recommence avec une nouvelle partie).
    Ca me semble pas mal. Imagine alors une fonction qui a pour seul but d'allouer tout le jeu en n * n. Cette fonction pourrait être appelée en début de partie pour allouer en 3*3. Ensuite, si ton joueur clique sur "modifier les dimensions" ça alloue le jeu en n * n.
    Et quand la partie est finie, ça libère le jeu avant d'offir au joueur la possibilité de rejouer (donc d'allouer de nouveau en 3*3). Reste à savoir si le joueur peut modifier les dimensions en cours de partie (ce qui obligerait à libérer le jeu avant la fin naturelle) mais même ça ça peut se régler si par exemple tu préviens le joueur que le redimensionnement entrainera l'annulation de la partie en cours. Donc quand le jeu est redimensionné, ça le libère (puisque le redimensionnement en cours de partie suppose que le dimensionnement initial a été fait) puis ça appelle la fonction dont je te parle...

    Citation Envoyé par chamludo Voir le message
    Pour les erreurs de fichiers, je sais que ma méthode n'est pas correcte car il y a des exit à plusieurs endroits, mais je ne sais pas comment faire et je ne me sis pas vraiment penché sur la question :
    - Est-ce que je dois rajouter un pointeur Erreur et le passer à chaque fonction qui peut le modifier, et mettre un test du style "si erreur= non, alors ... sinon sortir de la fonction",
    - Faut-il que je je fasse une liste de code d'erreurs erreur_1 (erreur initialisation de cran), erreur_2(erreur initialisation de sdl), erreur_3(erreur initialisation de police),... et traiter les cas avec un switch : si erreur_1 alors libère écran, si erreur_2 alors libère écran+sdl, si erreur_3 alors libère écran+sdl+police,...
    Avec la 20aine d'images que j'ai plus les tableaux, cela me fais beaucoup de cas a envisager.
    Ouais, là je sais pas trop quoi dire; C'est vrai que la gestion d'erreurs en C n'est pas évidente. Pour l'instant on peut laisser ça de côté et présumer que tout marche ; et rajouter la gestion des erreurs plus tard...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Bonjour,
    je te poste la totalité de mon main afin que tu puisses bien voir la logique que j'avais : (aucune modification effectuée depuis le début de notre discussion)

    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
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
     
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>//pour les nombres aleatoires
    #include <SDL/SDL.h>// pour utiliser la sdl
    #include <SDL/SDL_image.h>// pour coller autre que des bmp
    #include <SDL/SDL_ttf.h>
     
    #include "Define.h"//Il est deja dans Main.h
    //#include "Main.h"
    #include "Jeu.h"
    #include "Affichage.h"//et pas #include "Jeu.h"
    #include "Init.h"
    #include "Aide.h"
    #include "ia.h"
     
    /*
    Reste a faire :
     
     
     
    3. créer code erreur : 10001 : pour chaque chargement. Puis boucle : si erreur = 00000 (pas erreur) alors jeu, sinon (chaque est une erreur)
    selon chiffre 1 ou 0 liberation de tel ou tel tableu ou autre
     
     
    5. Etudier les symetries et rotations pour limiter les recherches?
     
    4. bouton tournoi :
    a. afficher la ligne de titre
    b. afficher les lignes suivantes
    c. modification et zones de clic, definir des zones ?
     
     
    6. augmenter le nombre de joueurs?
     
    7. Integrer le son
     
    On peut remplacer tous les "ecran" par SDL_GetVideoSurface et éviter de passer "ecran" en parametre.
     
    */
     
     
    //on doit fournir "&Jeton" et modifier "*Jeton" pour modifier le pointeur dans la fonction
     
    int main(int argc, char **argv)
    {
        SDL_Event event;//pour gérer les évenements souris et clavier
        SDL_Surface *ecran=NULL;
        TTF_Font *police = NULL;//police d'ecriture
        int JeuFini = NON;//[NON : on continue][OUI : on arrête le jeu], pour la boucle de jeu
        int PartieFinie = NON;//[NON :on continue la partie][OUI : on vide le jeu et recommence une nouvelle partie]
        int N=3;
        int M=3;
        int NbJetonsAAligner=3;
        int AncienN=N;
        int AncienM=M;
        int AncienNbJetonsAAligner=NbJetonsAAligner;//on aligne 3 jetons au depart
        int PlateauJeuLarg=PlateauLarg;//Dimension reelle de la zone de jeu quand on personnalise les dimensions
        int PlateauJeuHaut=PlateauHaut;
        Case *plateau;
        Info InfoZoneDeRecherche= {0, N, M,0, N, M};
        int *HistoriqueJeton= FonctionAllocation1D(N*M);//Ce tableau doit etre dynamique, efectue le test de bonne attribution
        int *ListeCasesVides= FonctionAllocation1D(N*M);//Tableau qui contient les numeros de toutes les cases vides au debut puis -1 pour les cases occupées.
        int NbCasesJouees=0;
        Images Jeton = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; //On initialise toutes les images à NULL
        int ClicX=0;
        int ClicY=0;
        int posX=0;
        int posY=0;
        int SourisCachee=NON;//[NON : Souris visible][OUI : Souris cachée]
        int NbAlignements=0;//Compte le nombre d'alignements gagnants
     
        jeu TypeJeu=HH;//HH, HO, OH, OO; puis rajouter N si 3 jetons ou plus
        Joueur ListeJoueurs[2]= {{H, Rond}, {H, Croix}};//2 joueurs humains pur commencer puis on changera en appuyant sur le bouton Config
        Joueur joueurEnCours=ListeJoueurs[0];//il faut trouver un moyen de modifier la liste des joueur lorsque l'on modifie la config
        int ConfigModifiee=NON;//[NON : ne pas actualiser si echap lors de ConfigDim][OUI : actualiser les tableaux lors de ConfigDim]
    // int NumMatch=0;//indique le numero du match que l'on est en train de jouer
    //char numMatch[2]="";//pour afficher les numéros du texte en chaine de caracteres
        zone ZoneEvenement = MARGE;
     
        //  MancheTournoi MancheInitiale= {11,{H, Rond}, {H, Croix},3,3,3}; //tournoi de 10 manches au maximum
        MancheTournoi Tournoi[10];/*=
        {
            {1,{H, Rond}, {H, Croix},3,3,3},
            {2,{H, Rond}, {H, Croix},3,3,3},
            {3,{H, Rond}, {H, Croix},3,3,3},
            {4,{H, Rond}, {H, Croix},3,3,3},
            {5,{H, Rond}, {H, Croix},3,3,3},
            {6,{H, Rond}, {H, Croix},3,3,3},
            {7,{H, Rond}, {H, Croix},3,3,3},
            {8,{H, Rond}, {H, Croix},3,3,3},
            {9,{H, Rond}, {H, Croix},3,3,3},
            {10,{H,Rond}, {H, Croix},3,3,3}
        };*///tournoi de 10 manches au maximum
        int MaxMancheTournoi=10;
        InitTournoi(Tournoi,  &MaxMancheTournoi);
     
        /**********************/ //debut du programme
     
        initSDL(&ecran);
     
        SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE);//ignore tous les clics. A reactiver apres le titre avec SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
     
        police = TTF_OpenFont("times.ttf", 30);//chargement de la police d'ecriture et de la taille
        if(police==NULL)//si erreur d'allocation de police
        {
            fprintf(stderr, "Erreur de chargement de la police: %s\n", SDL_GetError());
            exit(EXIT_FAILURE);//quitter le programme
        }
     
        plateau=malloc(N*M*sizeof(*plateau));//Ce tableau doit etre dynamique
        if(plateau==NULL)//si erreur d'allocation
        {
            free(plateau);//liberation de la 1ere dimension
            fprintf(stderr, "Erreur de creation tableau plateau: %s\n", SDL_GetError());
            exit(EXIT_FAILURE);//quitter le programme
        }
     
        if(ChargementImages(&Jeton)==NON)//Si l'initialisation retourne faux
        {
            fprintf(stderr, "Problème pour charger les images : %s\n", SDL_GetError());//Si l'initialisation de la SDL a échoué, on retourne faux
            exit(EXIT_FAILURE);//quitter le programme
        }//alors, nous sortons de la fonction main et mettons fin au programme.
     
        SDL_ShowCursor(SDL_DISABLE);//on cache le pointeur de la souris
        SourisCachee=OUI;//la souris est cachée
     
        AfficheTitre(ecran);//Affiche le titre du jeu sur fond marron
        AfficheBoutons(ecran, police, &Jeton,  TypeJeu, EcranJeu);
     
        SDL_Delay(1000);//attend 1000ms = 1 seconde avant de passer a la suite
     
        srand(time(NULL)*1000); //
     
        PlateauJeuLarg=PlateauLarg/maximumEntre(N, M)*N;//Dimension reelle de la zone de jeu
        PlateauJeuHaut=PlateauHaut/maximumEntre(N, M)*M;
     
        while(JeuFini==NON)//Maintenant que l'initialisation est valide, on entre dans la boucle de jeu
        {
            videJeu(plateau, N, M, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu
            AfficheJeu(ecran, plateau, N, M, &Jeton);//affiche le jeu vide
            AfficheBoutons(ecran, police, &Jeton,  TypeJeu, EcranJeu);
     
            SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);//reactive les clics
     
            while(PartieFinie==NON)
            {
                if(joueurEnCours.joueur==O)//Si c'est a l'ordi de jouer
                {
                    DefinirZoneEtendue(&InfoZoneDeRecherche, N, M, &NbCasesJouees, NbJetonsAAligner, HistoriqueJeton);//determine la zone a etudier
                    DefinirListeCaseVide(&InfoZoneDeRecherche, N, M, &NbCasesJouees, HistoriqueJeton, /* HistoriqueJetonClasse, */ ListeCasesVides);//Détermine la TableauCaseVide
                    OrdiJoue(plateau, N, M,&InfoZoneDeRecherche, ListeJoueurs, &NbCasesJouees, &PartieFinie, NbJetonsAAligner, HistoriqueJeton, ListeCasesVides);
                    if(NbCasesJouees>=2*NbJetonsAAligner-1)//on verifie s'il y a alignement au bout du 5eme jeton rond posé, (Jouées = 3*o+2*x)
                    {
                        verifFini(plateau, N, M, HistoriqueJeton[NbCasesJouees-1], ListeJoueurs, &PartieFinie, &NbCasesJouees, NbJetonsAAligner, &NbAlignements); //Fonction pour vérifier si la partie est terminée
                    }
                    AfficheJeu(ecran, plateau, N, M, &Jeton);
                    joueurEnCours= ListeJoueurs[NbCasesJouees%2];//joueur suivant
                    SDL_Delay(500);
                }
     
                while(SDL_PollEvent(&event))//Traiter les évènements
                {
                    switch(event.type)
                    {
                    case SDL_QUIT://Si on a cliqué sur la croix
                        ZoneEvenement=QUITTER;
                        break;
                    case SDL_KEYUP://Si touche du clavier enfoncée
                        switch (event.key.keysym.sym)//selon la touche enfoncée
                        {
                        case SDLK_ESCAPE: // Appui sur la touche Echap, on va arrêter le jeu
                        case SDLK_a: // Appui sur la touche q (Attention a<->q avec les claviers qwerty-azerty), on va arrêter le jeu
                            ZoneEvenement=QUITTER;
                            break;
                        case SDLK_q: // Appui sur la touche a (Attention a<->q avec les claviers qwerty-azerty), on va annuler le dernier coup
                            ZoneEvenement=ANNULER;
                            break;
                        case SDLK_n: //si on presse le n de nouveau
                            ZoneEvenement=NOUVEAU;
                            break;
                        case SDLK_t: //si on presse le t de Tournoi
                            ZoneEvenement=TOURNOI;
                            break;
                        case SDLK_i: //si on presse le i de aIde
                            ZoneEvenement=AIDE;
                            break;
                        case SDLK_v: //si on presse le v de Valider
                            ZoneEvenement=VALIDER;
                            break;
                        case SDLK_d: //si on presse le d de configDim
                            ZoneEvenement=CONFIGDIMENSION;
                            break;
                        default ://sinon rien pour eviter message d'alerte lors de la compilation
                            break;
                        }
                        break;
                    case SDL_MOUSEMOTION://Si souris déplacée
                        posX=event.motion.x;
                        posY=event.motion.y;
                        GestionPointeur(posX, posY, &SourisCachee, ecran, plateau, PlateauJeuLarg, PlateauJeuHaut, N, M, &Jeton, ListeJoueurs, &joueurEnCours, &NbCasesJouees); //Fonction pour gerer l'affichage du pointeur
                        break;
                    case SDL_MOUSEBUTTONUP://Si clic souris
                        ClicX=event.button.x;
                        ClicY=event.button.y;
                        ZoneEvenement = QuelleZoneCliquee(ClicX, ClicY,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours);
                        break;
                    default: //Sinon on ne fait rien
                        break;
                    }
     
                    switch(ZoneEvenement)
                    {
                    case JEU :
                        HumainJoue(ClicX, ClicY, plateau, N, M, ListeJoueurs, &NbCasesJouees, HistoriqueJeton);//gestion du clic souris
                        if(NbCasesJouees>=2*NbJetonsAAligner-1)//on verifie s'il y a alignement au bout du 5eme jeton rond posé, (Jouées = 3*o+2*x)
                        {
                            verifFini(plateau, N, M, HistoriqueJeton[NbCasesJouees-1], ListeJoueurs, &PartieFinie, &NbCasesJouees, NbJetonsAAligner, &NbAlignements); //Fonction pour vérifier si la partie est terminée
                        }
                        AfficheJeu(ecran, plateau, N, M, &Jeton);
                        AffichePointeur(ecran, &Jeton, ListeJoueurs, &joueurEnCours, &NbCasesJouees, ClicX, ClicY);//pour afficher le pointeur quand on clique et que l'on ne bouge pas
                        ZoneEvenement=MARGE;
                        break;
                    case NOUVEAU:
                        videJeu(plateau, N, M, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);
                        PartieFinie=OUI;//On met PartieFinie a OUI pour quitter la boucle secondaire*/
                        ZoneEvenement=MARGE;
                        break;
                    case ANNULER:
                        if(ListeJoueurs[(NbCasesJouees-1)%2].joueur==O)//si le joueur precedent est l'ordi, alors il faut annuler 2 jetons
                        {
                            AnnulerCoup(plateau, ListeJoueurs, &joueurEnCours, &NbCasesJouees, HistoriqueJeton);//on annule le coup supplementaire
                        }
                        AnnulerCoup(plateau, ListeJoueurs, &joueurEnCours, &NbCasesJouees, HistoriqueJeton);//on annule le coup obligatoire et on actualise le joueurEnCours
                        AfficheJeu(ecran, plateau, N, M, &Jeton);//on affiche la modification
                        AffichePointeur(ecran, &Jeton, ListeJoueurs, &joueurEnCours, &NbCasesJouees, posX, posY);//pour afficher le pointeur quand on clique et que l'on ne bouge pas
                        AfficheBoutons(ecran, police, &Jeton,  TypeJeu, EcranJeu);
                        ZoneEvenement=MARGE;//pour eviter de boucler et de renouveller ANNULER
                        break;
                    case CONFIGTYPE:
                        TypeJeu=ConfigType(ecran, TypeJeu, &Jeton, ClicX-BoutonX, ClicY-BoutonYConfigType, ListeJoueurs/*, 2*/);//Les coordonnéees envoyées sont relatives au coin superieur gauche du bouton Config
                        joueurEnCours=ListeJoueurs[NbCasesJouees%2];//il faut actualiser le joueurEnCours
                        ZoneEvenement=MARGE;
                        break;
                    case CONFIGDIMENSION:
                        joueurEnCours=ListeJoueurs[NbCasesJouees%2];
                        AncienN=N;
                        AncienM=M;
                        AncienNbJetonsAAligner=NbJetonsAAligner;
                        ConfigDimension(ecran, police,TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours, &Jeton, &N, &M, &NbJetonsAAligner, &ConfigModifiee);//on ouvre la configuration pour determiner le nombre de lignes et de colonnes du plateau de jeu et le nombre de jetons a aligner pour gagner
                        if(ConfigModifiee==OUI)//si on modifie les dimensions du plateau de jeu
                        {
     
     
                           /*   videJeu(plateau, AncienN, AncienM, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu AVANT d'avoir modifier les dimensions, pour tout remettre a zero
                              free(plateau);
                              plateau=NULL;
                              plateau=malloc(N*M*sizeof(*plateau));//on realloue un plateau aux nouvelles dimensions
                              if(plateau==NULL)//si erreur d'allocation
                              {
                                  free(plateau);//liberation du plateau
                                  fprintf(stderr, "Erreur de creation du tableau plateau");
                                  exit(EXIT_FAILURE);//quitter le programme
                              }
     
                              free(HistoriqueJeton);//on libere HistoriqueJeu
                              HistoriqueJeton=NULL;
                              HistoriqueJeton= FonctionAllocation1D(N*M);//Ce tableau doit etre dynamique, efectue le test de bonne attribution
     
                              free(ListeCasesVides);//on libere HistoriqueJeu
                              ListeCasesVides=NULL;
                              ListeCasesVides= FonctionAllocation1D(N*M);//Tableau qui contient les numeros de toutes les cases vides au debut puis -1 pour les cases occupées.
     
                              videJeu(plateau, N, M, ListeJoueurs, &joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);//Vide le plateau de jeu APRES d'avoir modifier les dimensions, sinon, on ne vide pas tout le tableau
                              PlateauJeuLarg=PlateauLarg/maximumEntre(N, M)*N;//Dimension reelle de la zone de jeu quand on personnalise les dimensions
                              PlateauJeuHaut=PlateauHaut/maximumEntre(N, M)*M;
                              ConfigModifiee=NON;*/
     
                            ModificationConfigDimension(AncienN, AncienM, N,M, plateau, ListeJoueurs,&joueurEnCours, &PartieFinie, &NbCasesJouees, HistoriqueJeton, ListeCasesVides);
                            ConfigModifiee=NON;
                            PlateauJeuLarg=PlateauLarg/maximumEntre(N, M)*N;//Dimension reelle de la zone de jeu quand on personnalise les dimensions
                            PlateauJeuHaut=PlateauHaut/maximumEntre(N, M)*M;
     
                        }
                        AfficheJeu(ecran, plateau, N, M, &Jeton);
                        AfficheBoutons(ecran, police, &Jeton,  TypeJeu, EcranJeu);
                        ZoneEvenement=MARGE;
                        break;
                    case TOURNOI:
                        DetermineTournoi(ecran, police, &Jeton, TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours, Tournoi,10, &MaxMancheTournoi);//determine els composante du tournoi
                        AfficheJeu(ecran, plateau, N, M, &Jeton);
                        AfficheBoutons(ecran, police, &Jeton,  TypeJeu, EcranJeu);
                        ZoneEvenement=MARGE;
                        break;
                    case AIDE:
                        Aide(ecran, police, &Jeton,TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours);//on ouvre le menu d'aide
                        AfficheJeu(ecran, plateau, N, M, &Jeton);
                        ZoneEvenement=MARGE;//pour eviter de boucler su le menu AIDE
                        break;
                    case QUITTER:
                        JeuFini=OUI; //On met JeuFini a OUI pour quitter la 1ere boucle principale
                        PartieFinie=OUI;//On met PartieFinie a OUI pour quitter la 2eme boucle principale
                        ZoneEvenement=MARGE;
                        break;
                    case MARGE:
                        break;
                    default: //Sinon on ne fait rien
                        break;
                    }
                }
                SDL_Flip(ecran);//Rafraichissement de l'écran. Il faut le sortir du while car sinon il attend de bouger la souris pour faire jouer le joueur suivant
            }
            SDL_Delay(1000);//Attendre avant de fermer ou de commencer une nouvelle partie : 1000 ms = 1 s
        }
     
        free(ecran);//liberation de lecran
        free(plateau);//liberation du plateau de jeu
        plateau=NULL;
        free(HistoriqueJeton);
        HistoriqueJeton=NULL;
        free(ListeCasesVides);
        ListeCasesVides=NULL;
     
        LiberationImages(&Jeton);
        TTF_CloseFont(police); // Fermeture de la police, doit être fermée avant TTF_Quit()
        TTF_Quit();
        SDL_Quit();
     
        return EXIT_SUCCESS;//on quitte le jeu avec succes
    }
    Nom : aa-01.png
Affichages : 1744
Taille : 28,6 Ko
    Nom : aa-02.png
Affichages : 1684
Taille : 32,9 Ko
    Ainsi que 2 images pour illustrer.
    Mon but étais de remplacer la partie entre les lignes 250 à 278 par la ligne 279. Au départ je les avais incluses dans ma fonction ConfigDimension, mais cela ne fonctionnait pas. Surtout lorsque je n'enregistre pas les modifications pas de problème, mais si je valide les modification, alors de dois ajouter plein de variables (ecran, police, &Jeton, TypeJeu,PlateauJeuLarg, PlateauJeuHaut, joueurEnCours, Tournoi,10, &MaxMancheTournoi).
    C'est pour cela que je voulais faire une fonction qui valide les modification : fonction ModificationConfigDimension.
    C'est cette fonction qui beugue dont j'ai parlé dans mon 1er message.

    De plus, le bouton Tournoi n'est pas encore opérationnel car lorsque je clique dessus, cela m'ouvre un nouvel écran.
    Mon but est de pouvoir choisir au maximum 10 parties avec le mode que je veux (humain-humain, humain-ordi,...) avec les dimensions que je souhaite (3*3 puis 5*12,... avec le nombre de jetons à aligner variable, parfois 3 , parfois 5).

    Lorsque du me dis : "Imagine alors une fonction qui a pour seul but d'allouer tout le jeu en n * n. Cette fonction pourrait être appelée en début de partie pour allouer en 3*3. Ensuite, si ton joueur clique sur "modifier les dimensions" ça alloue le jeu en n * n."
    Est-ce que tu me conseilles d'inclure les lignes 110-116 dans ma fonction videJeu (ligne 139) ? N'est-ce pas gênant de réallouer à chaque nouvelle partie même lorsque cela est inutile ? Moi je ne pensais le faire que lorsque les dimensions étaient modifiées.

    Dans ton 1er message tu me parlais de structures. Est-ce que tu me conseilles de passer largeur N, hauteur M et peut-être NbjetonsAAligner comme une seule structure ? J'y avais pensé car N et M sont toujours ensemble, et parfois NbJetonsAAligner, donc autant les séparer. Cela me fait juste un peu peur de changer tous mes N et M par une structure car j'en ai énormément.
    Ensuite je pourrais regrouper HistoriqueJeton et ListeCasesVides car l'un est le complément de l'autre.



    Pour la gestion des erreurs, je pensais rajouter un else aux lignes 109-119-123, sachant que dans la fonction ChargementImages, j'ai 23 images à charger. Et à rajouter les free correspondant
    Dans la fonction initSDL (ligne 99), j'initialise SDL_INIT_VIDEO, ecran et TTF_Init.
    Si je gère toutes erreurs de chargements, je vais avoir une indentation de fou. C'est pour cela que je voulais le faire à la fin du jeu.

    Ou alors j'initalise une variable Erreur à 0.
    Remplacer la ligne 107 par Erreur =1.
    Remplacrer la ligne 107 par Erreur = 2 ou Erreur=Erreur+10
    Remplacrer la ligne 107 par Erreur =3 ou Erreur=Erreur+100. car ces initialisations sont indépendantes les unes des autres.
    Avant de lancer le jeu ligne 137 , Erreur vaut 0 ou 10 ou 11 ou 100 ou 110 ou 101 ou 111 selon les erreurs rencontrées.
    Puis un petit si Erreur ==0 alors lancer le jeu sinon (si chiffre des unités =0 alors bonne initialisation de la line103 et free(), si chiffre des dizaines, ...si chiffres des centaines, ...)
    Sauf que si j'ai trop d'initialisation, mon Erreur sera trop long.

    Ou créer un tableau listant toutes les erreurs possibles et cocher celle qui ont eu lieu. Puis faire free() selon les erreurs rencontrées



    Toujours est-il que je n'arrive pas à remplacer les lignes 250 à 278 par la ligne 279 et c'est cela mon problème principal.
    Merci
    Ludovic

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chamludo Voir le message
    je te poste la totalité de mon main afin que tu puisses bien voir la logique que j'avais : (aucune modification effectuée depuis le début de notre discussion)
    Oui, je l'ai lu. J'ai même tenté de le compiler (j'ai installé SDL pour ça, sisi je t'assure, mais t'inquiète pas, je l'ai fait sur une machine virtuelle dont le disque système est immuable => au prochain reboot ma machine sera comme neuve) mais il manque les "Define.h" et autres. Donc je ne peux que faire une analyse succinte. Et le souci c'est que ta logique me parait correcte(nettoyage du jeu avant modification, même si c'est inutile ça doit fonctionner ; puis allocation de nouvelles dimensions là aussi ça doit fonctionner, puis nettoyage du jeu après modification là aussi ça doit fonctionner).
    Peut-être me montrer ConfigDimension et videJeu (ou carrément tout le projet complet)...

    Citation Envoyé par chamludo Voir le message
    Lorsque du me dis : "Imagine alors une fonction qui a pour seul but d'allouer tout le jeu en n * n. Cette fonction pourrait être appelée en début de partie pour allouer en 3*3. Ensuite, si ton joueur clique sur "modifier les dimensions" ça alloue le jeu en n * n."
    Est-ce que tu me conseilles d'inclure les lignes 110-116 dans ma fonction videJeu (ligne 139) ?
    Maintenant que je vois ton source non. Tu alloues au début du projet, tu libères à la fin la logique est bonne. Et même si au milieu tu fais un free+malloc la logique reste bonne. Ce que je proposais était une autre façon de voir qui me correspond plus et qui était plus du style "je rapproche le plus possible les ouvertures/fermetures du travail qui en dépend"

    Citation Envoyé par chamludo Voir le message
    N'est-ce pas gênant de réallouer à chaque nouvelle partie même lorsque cela est inutile ? Moi je ne pensais le faire que lorsque les dimensions étaient modifiées.
    Perso j'essaye toujours de penser "petites fonctions toutes simples utilisables de partout", un peu comme un atome qu'on peut combiner à un autre pour former une molécule ou du "diviser pour régner".
    C'est vrai que si ton truc tournait 100000 fois par secondes, alors mettre dans le bouzin "allocation+travail+libération" effectivement ça ne serait pas optimisé. Mais pour une partie dont la durée se compte en secondes (minutes ?), ce n'est pas une allocation (même inutile) au début de la partie puis une libération à la fin qui va vraiment se faire sentir.
    Et puis plus tard, dans un second temps, rien n'interdit de modifier ta fonction qui alloue en n * n pour qu'elle teste si la nouvelle dimension est différente de l'ancienne et dans ce cas ne rien faire (ou même ne pas l'appeler)...

    Citation Envoyé par chamludo Voir le message
    Dans ton 1er message tu me parlais de structures. Est-ce que tu me conseilles de passer largeur N, hauteur M et peut-être NbjetonsAAligner comme une seule structure ? J'y avais pensé car N et M sont toujours ensemble, et parfois NbJetonsAAligner, donc autant les séparer. Cela me fait juste un peu peur de changer tous mes N et M par une structure car j'en ai énormément.
    Ensuite je pourrais regrouper HistoriqueJeton et ListeCasesVides car l'un est le complément de l'autre.
    Hé oui. Principe des fondations. C'est vrai que tu as énormément de variables (joueuEnCours, partieFinie, typeJeu, EcranJeu, etc etc etc) et que ça n'aide pas à faire évoluer. Est-ce que par exemple certaines variables ne pourraient pas être calculées ? Oui ça va peut-être à contresens où justement on mémorise un résultat dans une variable pour ne pas avoir à le recalculer justement mais parfois il faut essayer de "sentir" quand une variable est nécessaire et quand el;e ne l'est pas. Si par exemple je devais faire une boucle et traiter strlen(s) dans la boucle, il est certain que j'utiliserais une variable pour mémoriser strlen(s) pour ne pas avoir à la recalculer dans la boucle. Mais mettre une variable pour mémoriser un truc calculable dont tu va te servir une fois de temps en temps ça a l'effet inverse: ça complexifie sans aider vraiment. Je sais plus qui sur ce forum a une signature qui dit "une variable en moins c'est un bug en moins".

    Bon, on va continuer. de tenter de t'aider Il me faudrait maintenant voir videJeu()...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Il est vrai qu'avec mes 30 fonctions annexes et plus 2200 lignes pour le programme, il t'en manque une bonne partie.
    Comment faire pour te fournir le projet avec 5 MO de d'images?

  8. #8
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Les images sont-elles vraiment nécessaires ?
    Tu peux faire un tar de ton dossier et le déposer sur https://www.grosfichiers.com/. Tu remplis les champs, te mets toi-même en destinataire. Tu recevras alors un mail avec le lien pour administrer le fichier (créateur) et le lien pour télécharger le fichier (destinataire)
    Tu conserves précieusement le lien d'admin et tu déposes le lien de téléchargement sur le fofo...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  9. #9
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Voici le lien
    www.grosfichiers.com/biHb6pTYqkE

    Pour voir le problème, il faut décommentariser le passage du main ligne 254->276 et mettre en commentaire les lignes 278-279.

    Puis lancer le jeu;
    Appuyer sur D (pour dimension) ou cliquer sur le 4eme bouton.
    Mettre l'abscisse à 20 puis valider.
    Recliquer sur le 4eme bouton.
    Mettre l'abscisse à 30.

    Si on commente le passage du main lign e254->276 et exécute les lignes 278-279.

    Puis lancer le jeu;
    Appuyer sur D (pour dimension) ou cliquer sur le 4eme bouton.
    Mettre l'abscisse à 20 puis valider. Pourquoi des jetons apparaissent ???
    Recliquer sur le 4eme bouton.
    Mettre l'abscisse à 30. Pourquoi le jeu plante ???

    Mon debogger me dit qu'il y a une erreur l 548 et 552 lors des free(HistoriqueJeton); et free(ListeCasesVides);
    C'est pour cela que je pensais a une erreur de reallocation

  10. #10
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Zut, je croyais avoir trouvé mais non. Je continue à chercher...

    Si tu veux j'ai créé le Makefile pour compiler sous Linux
    Code Makefile : 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
    #
    # Makefile de compilation du projet Morpion de chamludo
    #
     
    CC=gcc
    CFLAGS=-Wall -Werror
    CFLAGS=
    # Oui, j'ai annulé CFLAGS car avec les Wall activés, il y a trop de warnings => il faudra aussi s'y atteler et les supprimer tous
    LDFLAGS=-lSDL -lSDL_ttf
     
    SOURCEFILES=Affichage.c Aide.c ia.c Init.c Jeu.c main.c
    OBJECTFILES=$(SOURCEFILES:.c=.o)
    EXEC=Morpion
     
    all:
    	@make $(EXEC)
     
    clean:
    	rm -f $(EXEC)
    	rm -f $(OBJECTFILES)
     
    object:
    	@make $(OBJECTFILES)
     
    Affichage.o: Affichage.c Affichage.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    Aide.o: Aide.c Aide.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    ia.o: ia.c ia.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    Init.o: Init.c Init.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    Jeu.o: Jeu.c Jeu.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    Main.o: Main.c Main.h Define.h
    	$(CC) $(CFLAGS) -c $<
     
    Morpion: $(OBJECTFILES)
    	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@

    Petite question concernant la SDL (que je ne connais pas): quand tu initialises ton écran avec initSDL(&ecran), est-ce que "ecran" est alloué vu que tu y fais un free() en fin de main ? Je dis ça car chez-moi j'ai un segfault mais si j'enlève le free(), plus de segfault.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    J'ai trouvé !!!! La vache j'y ai mis du temps (j'ai même failli abandonner et c'est en écrivant ce post que j'ai compris)

    Déjà voici ce que j'ai fait
    1. dans Define.h, j'ai rajouté cette ligne: #define FREE(x) {printf("%s, %d - free=%x\n", __FILE__, __LINE__, x); free(x); printf("free ok\n");}.
    2. j'ai remplacé tous les free(...) par FREE(...).
    3. partout où il y avait truc=malloc(N*M) j'ai rajouté printf("%s, %d - malloc(%d * %d)\n", __FILE__, __LINE__, N, M) avant le malloc et printf("%s, %d - truc=%x\n", __FILE__, __LINE__, truc) après le malloc


    Ce que je remarque, c'est que tu peux agrandir la taille sans souci. C'est au moment où tu la réduis que le souci se produit

    Voici une trace de jeu. Je lance le jeu, j'agrandis en 20x10 puis je réduis en 10x10
    main.c, 61 - malloc(3 * 3)
    main.c, 63 - HistoriqueJeton=be0996a0
    main.c, 65 - malloc(3 * 3)
    main.c, 67 - ListeCasesVides=be0996d0
    main.c, 105 - ecran=be0dc960
    main.c, 258 - free=be0df5c0
    free ok
    main.c, 261 - plateau=be3c3860
    main.c, 268 - free=be0996a0
    free ok
    main.c, 270 - malloc(20 * 10)
    main.c, 272 - HistoriqueJeton=be3c3b90
    main.c, 274 - free=be0996d0
    free ok
    main.c, 276 - malloc(20 * 10)
    main.c, 278 - ListeCasesVides=be3c3ec0
    Jeu.c, 538 - free=be3c3860
    free ok
    Jeu.c, 540 - malloc(20 * 10)
    Jeu.c, 542 - plateau=be3c3860
    Jeu.c, 549 - free=be3c3b90
    free ok
    Jeu.c, 551 - malloc(20 * 10)
    Jeu.c, 553 - HistoriqueJeton=be3c3b90
    Jeu.c, 555 - free=be3c3ec0
    free ok
    Jeu.c, 557 - malloc(20 * 10)
    Jeu.c, 559 - ListeCasesVides=be3c3ec0
    main.c, 258 - free=be3c3860
    free ok
    main.c, 261 - plateau=be50c530
    main.c, 268 - free=be3c3b90
    free ok
    main.c, 270 - malloc(10 * 10)
    main.c, 272 - HistoriqueJeton=be50c6d0
    main.c, 274 - free=be3c3ec0
    free ok
    main.c, 276 - malloc(10 * 10)
    main.c, 278 - ListeCasesVides=be50c870
    Jeu.c, 538 - free=be50c530
    free ok
    Jeu.c, 540 - malloc(10 * 10)
    Jeu.c, 542 - plateau=be50c530
    Jeu.c, 549 - free=be50c6d0
    free(): invalid pointer
    Abandon

    Donc le truc que je remarque, c'est que la fonction ModificationConfigDimension (source Jeu.c ligne 540) fait sa sauce avec les pointeurs, mais que la partie CONFIGDIMENSION de main.c fait la même sauce (lignes 278 etc de main.c). Déjà c'est double job mais admettons.

    Mais si je regarde ModificationConfigDimension, voici ce que je vois (je simplifie juste pour montrer l'erreur)
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void ModificationConfigDimension(int *ListeCasesVides) {
    	...
    	...
    	free(ListeCasesVides);
    	ListeCasesVides=malloc(...);
    }
     
    int main() {
    	int *ListeCasesVides;
    	ModificationConfigDimensions(ListeCasesVides);

    Tu la sens venir là l'erreur ? Tu libères la zone allouée puis tu alloues dans une variable locale à la fonction. Et que cette variable soit un pointeur ne change rien vu que tu te contentes de travailler la variable elle-même et non le pointé. Exactement comme si tu avais écrit
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void ModificationConfigDimension(int pt) {
    	...
    	...
    	pt=456;
    }
     
    int main() {
    	int xxx=123;
    	ModificationConfigDimension(xxx);
    }
    Donc quand la fonction se termine, la zone est libérée et la nouvelle allocation est perdue. Et au free() suivant de la même zone, évidemment ça plante.

    Quand on veut que ça marche avec des int, il faut écrire la fonction comme ceci...
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void ModificationConfigDimension(int *pt) {
    	...
    	...
    	*pt=456;
    }
     
    int main() {
    	int xxx=123;
    	ModificationConfigDimension(&xxx);
    }

    Donc si on veut que ça marche avec le pointeur ListeCasesVides, il faut écrire la fonction comme cela:
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void ModificationConfigDimension(int **ListeCasesVides) {
    	...
    	...
    	free(*ListeCasesVides);
    	*ListeCasesVides=malloc(...);
    }
     
    int main() {
    	int *ListeCasesVides;
    	ModificationConfigDimensions(&ListeCasesVides);

    Et bien évidemment faire de même avec plateau et HistoriqueJetons. Et peut-être essayer de voir si tu as vraiment besoin de faire ces free+malloc toutes les 15 lignes de ton code...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  12. #12
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Merci beaucoup, tout fonctionne.

    Le truc qui me genait était d'écrire " videJeu(*plateau, NouveauN, NouveauM, ListeJoueurs, joueurEnCours, PartieFinie, NbCasesJouees, *HistoriqueJeton, *ListeCasesVides);" avec les étoiles dans la fonction ModificationConfigDimension.
    J'ai du mal avec les pointeurs définis dans une fonction, utilisés dans une 2eme imbriquée pour être finalement modifiée dans une 3eme imbriquée.

    quand tu initialises ton écran avec initSDL(&ecran), est-ce que "ecran" est alloué vu que tu y fais un free() en fin de main ? Je dis ça car chez-moi j'ai un segfault mais si j'enlève le free(), plus de segfault.
    .
    J'avais du le voir un jour sur une page. Finalement, il d'après certaines sources il semblerait qu'il faudrait utiliser SDL_FreeSurface, d'aprés d'autre que ce soit pas nécessaire (ça dépend de la gestion des erreurs et du moment où l'on quitte le programme).

    J'ai retiré les free en cas d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if(tableau==NULL)//si erreur d'allocation
        {
      //      free(tableau);//liberation du tableau
            fprintf(stderr, "Erreur de creation du tableau ");
            exit(EXIT_FAILURE);//quitter le programme
        }
    Par contre ma fonction int *FonctionAllocation1D(int dimension) est utilisable pour les tableaux ListeCasesVides et HistoriqueJetons car ils sont de type entier, mais pas pour mon tableau plateau qui est de type case. Est-ce que tu penses que je laisse le prog comme ça, ou je creée une fonction FonctionAllocation1DtypeCase(), ou j'utilise les unions (il me semble que c'est comme ca ) pour pour voir utiliser FonctionAllocation1D quel que soit le type du tableau (9a, je n'ai jamais fait).

    Y a-t-il un moyen de définir la "police" dans le define.h, histoire que je ne sois pas obligé de le fournir à chaque fonction l'utilisant ? J'ai déjà posé la question et on m'a dit que ce n'était pas possible.

  13. #13
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chamludo Voir le message
    Le truc qui me genait était d'écrire " videJeu(*plateau, NouveauN, NouveauM, ListeJoueurs, joueurEnCours, PartieFinie, NbCasesJouees, *HistoriqueJeton, *ListeCasesVides);" avec les étoiles dans la fonction ModificationConfigDimension.
    J'ai du mal avec les pointeurs définis dans une fonction, utilisés dans une 2eme imbriquée pour être finalement modifiée dans une 3eme imbriquée.
    Oui, c'est pas évident. C'est dû au fait que l'étoile dans une définition indique un pointeur, et l'étoile dans une instruction indique le pointé.

    Voici une exemple illustratif que tu pourras réutiliser quand tu voudras faire la même chose

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int main() {
    	int var=123;
    	modif1(&var);				// & "adresse de" donc la fonction reçoit l'adresse d'un int donc un "int étoile"
    	printf("var=%d\n", var);
    }
     
    void modif1(int *pt) {				// La fonction reçoit bien un int étoile qui se nomme "pt" => "pt" est un int étoile => c'est un pointeur
    	(*pt)=(*pt) * 2;			// Je mets des parenthèses pour que tu voies bien qu'on travaille sur le pointé => ici "*pt" c'est le pointé !!!
    	modif2(pt);				// La fonction reçoit "pt" qui est un int étoile  => elle reçoit un pointeur
    }
     
    void modif2(int *xxx) {				// La fonction reçoit bien un int étoile qui se nomme "xxx" => "xxx" est un int étoile  => c'est un pointeur
    	(*xxx)=(*xxx) * 3;
    }

    Citation Envoyé par chamludo Voir le message
    Par contre ma fonction int *FonctionAllocation1D(int dimension) est utilisable pour les tableaux ListeCasesVides et HistoriqueJetons car ils sont de type entier, mais pas pour mon tableau plateau qui est de type case. Est-ce que tu penses que je laisse le prog comme ça, ou je creée une fonction FonctionAllocation1DtypeCase(), ou j'utilise les unions (il me semble que c'est comme ca ) pour pour voir utiliser FonctionAllocation1D quel que soit le type du tableau (ça, je n'ai jamais fait).
    Tu as voulu trop déléguer et le trop est l'ennemi du bien. Parce que fondamentalement, qu'y a-t-il de différent entre "FonctionAllocation1D" et "malloc" ??? Essaye de remplacer partout où tu l'utilises par malloc et tu verras que finalement le gain était négligeable.
    Et concernant FonctionAllocation2D je l'ai beaucoup aimée car tu as tenté de faire ça propre et ça c'est une super mentalité.
    Toutefois je vais d'abord te proposer une autre façon de faire
    Code c : 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
    int **FonctionAllocation2D(int dimension1, int dimension2)//alloue dynamiquement un tableau a deux dimensions
    {
    	size_t i;
    	int **tableau;
     
    	tableau=calloc(dimension1, sizeof(*tableau));	// on alloue N pointeurs tous mis à 0
    	if (tableau == NULL) goto liberation;		// oui oui, un vrai "goto" comme en Basic !!!
    	for(i=0; i < dimension1; i++) {
    		tableau[i]=malloc(dimension2 * sizeof(**tableau));	//on alloue des tableaux de taille M
    		if (tableau[i] == NULL) goto liberation;
    	}
     
    	return tableau;
     
    	liberation:
    	// Partie qui gère une erreur d'allocation
    	// On est bien d'accord ici que si le tableau est alloué, alors sur l'ensemble des pointeurs du tableau,
    	// ceux qui ne sont pas à 0 sont ceux qui ont été alloués. Ne reste donc qu'à les débusquer et les libérer.
    	if (tableau) {
    		for(i=0; i < dimension1; i++) {
    			if (tableau[i]) free(tableau[i]);
    			// Et encore, comme free(NULL) est autorisé, le "if" n'est même pas nécessaire...
    		}
    		free(tableau);
    	}
    	fprintf(stderr, "Erreur de creation du tableau - %s", strerror(errno));
    	return NULL;
    }
    Oui, un "goto", le truc indiqué dans tous les tutos comme l'abomination des programmeurs. Perso je suis plus modéré. Pour moi, un "goto" est un outil comme un autre, avec ses avantages et ses inconvénients. Celui qui utilise le "goto" parce qu'il n'a pas envie de réfléchir à une façon plus élégante de faire alors oui c'est un porc. Mais celui qui l'utilise justement parce que sa solution donne un truc plus simple à coder et à appréhender là alors je dis "ok". Les bons programmeurs respectent les règles, les programmeurs brillants les transgressent parfois...
    Accessoirement tu remarqueras l'emploi de "size_t" qui est le type adéquat pour les dimensions d'un tableau et un peu d'aération dans les opérations de comparaison (ça aide à la lecture d'aérer un code)...

    Ca c'était la méthode pour gérer l'allocation 2D. Toutefois as-tu réfléchi à l'avantage que tu aurais si tu convertissais tes tableaux 2D en tableau 1D ? Parce qu'après tout en mémoire c'est comme ça que c'est codé: une longue et interminable suite de cases. Déjà un seul malloc à gérer et rien que ça...
    Alors certes il te faudrait ensuite convertir tous tes accès indices 2D (style tab[i][j]) en index 1D (style tab[idx]) mais ça c'est pas super compliqué car idx=i * nb_col + j et dans l'utre sens, i=idx / nb_col et j=idx % nb_col.

    Voilà, c'était la pensée du jour concernant la gestion de la mémoire.

    Citation Envoyé par chamludo Voir le message
    Y a-t-il un moyen de définir la "police" dans le define.h, histoire que je ne sois pas obligé de le fournir à chaque fonction l'utilisant ? J'ai déjà posé la question et on m'a dit que ce n'était pas possible.
    Tu parles de TTF_Font *police ? Oui tu peux le mettre en global. Dans ce cas, tu écris TTF_Font *police dans le source qui contient le main() (et tu écris cette ligne en dehors de toute fonction) et tu écris extern TTF_Font *police dans define.h. Mais ça reste pas conseillé (ça fait partie des façons de faire pas propre pour "éviter de se fatiguer").
    D'autant plus qu'il existe une autre façon de faire : tu définis une structure qui englobe tout ce dont tu as besoin y compris ce fameux "TTF_Font *police". Ainsi au lieu de passer 50 paramètres à tes fonctions tu ne passes que la structure (enfin son adresse car c'est plus rapide de transférer une adresse de 8 octets qu'une structure de 8000). D'autant plus que tu l'as fait. Pourquoi par exemple tu n'intègres pas ce "TTF_Font *police" dans ton "struct Images" ???
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  14. #14
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    Merci beaucoup, je vais regarder tout cela lorsque j'en aurais plus le temps.

    Pour l'allocation2D, je ne m'en sers qu'à un seul endroit et je trouve plus simple dans mon esprit de le conserver tel quel plutôt qu'en 1D.

    Qu'y a-t-il de différent entre "FonctionAllocation1D" et "malloc"
    Je sais que c'est presque pareil, c'est juste que j'aimais bien l'idée de faire int *HistoriqueJeton= FonctionAllocation1D(N*M);plutot que int *HistoriqueJeton, puis plus loin malloc puis test. Je vais y repenser.
    Je vais aussi repenser à regrouper certaines variables.
    Merci pour tout, je pense pouvoir mettre le sujet en résolu.

  15. #15
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 851
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 851
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par chamludo Voir le message
    Je sais que c'est presque pareil, c'est juste que j'aimais bien l'idée de faire int *HistoriqueJeton= FonctionAllocation1D(N*M);plutot que int *HistoriqueJeton, puis plus loin malloc puis test.
    T'as le droit de faire int *HistoriqueJeton=malloc(N*M*sizeof(*HistoriqueJeton))
    Et comme de toute façon (enfin dans ma façon de faire) le test tu étais quand-même obligé de le faire. Parce que moi, quand une fonction échoue, je ne quitte pas le programme mais je remonte à l'appelant. Donc dans mon esprit d'un côté c'était int *HistoriqueJeton= FonctionAllocation1D(N*M) puis if (HistoriqueJeton == NULL) ... et de l'autre c'était int *HistoriqueJeton=malloc(N*M*sizeof(*HistoriqueJeton)) puis if (HistoriqueJeton == NULL) ....

    Donc je comprends chez-toi son utilité. Alors si maintenant tu veux la garder telle quelle (avec sortie via exit) et que tu veux la rendre plus "universelle", alors te suffit de rajouter la taille d'un élément en paramètre (comme calloc). Et pour avoir un pointeur universel t'as le "void *"

    Exemple
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void *FonctionAllocation1D(unsigned short dimension, size_t size) {
    	void *tableau=calloc(dimension, size);//Ce tableau doit etre dynamique et initialisé à 0
    	if (tableau != NULL) return tableau;
     
    	fprintf(stderr, "Erreur d'allocation du tableau %hu - %s", dimension * size, strerror(errno));
    	exit(EXIT_FAILURE);//quitter le programme
    }

    Ensuite, pour un tableau de 10 ints => int *t=FoncTionAllocation1D(10, sizeof(*t)). Et pour un tableau de 15 Case => Case *t=FonctionAllocation1D(15, sizeof(*t)).

    PS: tu remarqueras aussi le travail de recherche sur la finesse à apporter aux paramètres. Une dimension étant toujours positive, et étant probablement toujours inférieure à 65536, le ushort suffit...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  16. #16
    Membre averti
    Homme Profil pro
    Enseignant
    Inscrit en
    Juillet 2019
    Messages
    72
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Juillet 2019
    Messages : 72
    Par défaut
    J'aime bien cette version de la fonction void *FonctionAllocation1D(unsigned short dimension, size_t size).
    Cela fonctionne parfaitement pour mes tableaux de int comme ceux de type case.

    Je viens de passer une heure à me prendre la tête pour un truc bête
    Comme la fonction calloc alloue un bloc de mémoire en initialisant tous ces octets à la valeur 0, je comprenais parfaitement pour les tableaux d'entiers (tous à 0).
    Mais pour le type enum Case, que j'écrive enum Case {Vide, Rond, ... } ou enum Case { Rond, Vide,... }, mon tableau est toujours vide à l'exécution alors que je m'attendais à avoir un tableau de Rond dans le 2eme cas.

    En fait j'avais juste oublié que la fonction videJeu remplissez le plateau de Vide avant de l'afficher, donc je ne voyais jamais l'étape avec les Ronds.

    Je vais réfléchir aux conseils que tu m'as donné pour améliorer mon programme lorsque j'en aurais le temps.
    Encore merci

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

Discussions similaires

  1. [XL-2010] Redimensionnement d'un tableau dynamique et perte de données VBA
    Par awa123 dans le forum Macros et VBA Excel
    Réponses: 5
    Dernier message: 11/08/2014, 22h54
  2. [Free Pascal] Redimensionner un tableau dynamique en un tableau statique
    Par tekthoninks dans le forum Free Pascal
    Réponses: 5
    Dernier message: 22/03/2009, 22h38
  3. Réponses: 1
    Dernier message: 03/05/2007, 08h15
  4. Redimensionner un tableau dynamique
    Par WebPac dans le forum Delphi
    Réponses: 6
    Dernier message: 18/01/2007, 16h23
  5. Comment redimensionner un tableau dynamique ?
    Par Mickey.jet dans le forum Langage
    Réponses: 13
    Dernier message: 07/09/2006, 18h16

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