"Changer taille tableau de chaine de caractère en C"

Fermé
loki9678 - 4 janv. 2022 à 16:56
 loki9678 - 5 janv. 2022 à 19:21
Bonjour,
je souhaite réaliser une pioche aléatoire de 16 cartes.
Cependant étant donné que il ne faut pas tirer deux fois la même carte j'ai procédé ainsi.
je crée donc deux tableau de chaine de caractère de "16 ligne et 10 colonnes".
Je crée une boucle while dans laquelle :
Je tire un nombre aléatoire compris entre 0 et 31 et j'associe le nombre à une case du tableau 1.
J'affiche la carte tirée a l'écran pour informer l'utilisateur.
Ensuite je copie la carte tirée avec strcpy dans le tableau 2.
Puis je supprime la carte avec memmove.
Le problème étant que lors du premier tirage la carte se copie bien dans le tableau 2. Cependant dans le tableau 1 il y'a une carte qui se duplique. Cette carte étant à chaque fois la carte tirée+3.
Voici un exemple de ce qui est affiché:

Pour piocher entrez 0:
0
La carte choisi est : carte 10
///--------------------------------------------Tableau1--------------------------------------//
carte 1
carte 2
carte 3
carte 4
carte 5
carte 6
carte 7
carte 8
carte 9
carte 11
carte 12
carte 13 ///Ici le 13 se duplique
carte 13
carte 14
carte 15
carte 16
carte 17
carte 18
carte 19
carte 20
carte 21
carte 22
carte 23
carte 24
carte 25
carte 26
carte 27
carte 28
carte 29
carte 30
carte 31
carte 32
//-------------------------------------------tableau2--------------------------------------//








carte 10










Le second tableau me permet de changer de pioche quand la première est vide pour ne pas tirer plusieurs fois la même carte.
Pour remédier à ce problème je souhaitait baisser la taille du tableau à chaque tirage pour empêcher une duplication.

Sauriez vous comment remédier à ce problème soit en redimensionnant le tableau soit d'une autre manière?
Merci d'avance.
A voir également:

4 réponses

yg_be Messages postés 22726 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024 1 476
4 janv. 2022 à 19:42
bonjour,
peux-tu partager la source de ton programme?
merci d'utiliser les balises de code: https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code

Pour empêcher une duplication, ne suffit-il pas de réduire le choix au moment de tirer un nombre aléatoire?

Je suis surpris que la carte tirée ne se mette pas au début du tableau 2: est-ce intentionnel?
0
Merci de votre réponse.
Voici mon code:
int main()
{
    int nombre,i,entree;
    char pioche1[16][10] = {"carte 1","carte 2","carte 3","carte 4","carte 5","carte 6","carte 7","carte 8",
                            "carte 9","carte 10","carte 11","carte 12","carte 13","carte 14","carte 15","carte 16"
                           };
    char pioche2[16][10]= {};
    //char piocheVide[1][10]={"VIDE"};
    srand(time(NULL));


    while(pioche1[0]!='\0') 
    {
        printf("Pour piocher entrez 0:\n");  
        scanf("%d",&entree); 
        if(entree!=0) 
            printf("Vous n'avez pas saisie 0, resaisissez :\n"); 
            scanf("%d",&entree); /
        }
        if(entree==0) 
        {
            nombreAuSort1 = rand()%(15); 
            printf("La carte choisi est : %s\n", pioche1[nombreAuSort1]); 
            strcpy(pioche2[nombreAuSort1],pioche1[nombreAuSort1]); 
            for(i=0,i<16-i,i++)
            {

            memmove(pioche1[nombreAuSort1+i],pioche1[nombreAuSort1+1+i],16); 

            }

            
        }
        for(i=0;i<16;i++)
        {
            printf("%s\n",pioche1[i]);
        }
        for(i=0;i<16;i++)
        {
            printf("%s\n",pioche2[i]);
        }

    }

Je l'ai un peu modifié depuis hier et comme ca il affiche plus de double. Cependant étant donné que avec la fonction memmove je "décale" les nombres dans le tableau ce dernier affiche donc des cases vides et mon programmes tire du vide a partir de quelques tirages.
Et le fait que la carte ne se mettent pas au début du tableau n'est pas réellement intentionnel je lui ai juste affecté la même place dans le tableau 2. Mais l'ordre importe peu étant donné que c'est une pioche.
0
yg_be Messages postés 22726 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 26 avril 2024 1 476 > loki9678
Modifié le 5 janv. 2022 à 11:34
Ton programme tire du vide parce que tu fais deux erreurs:
1) en ligne 22, tu continues à piocher parmi les 16 premières cartes, au lieu de tenir compte du nombre de cartes restantes.
2) en ligne 28, tu décales beaucoup trop de cartes.
0
Dalfab Messages postés 706 Date d'inscription dimanche 7 février 2016 Statut Membre Dernière intervention 2 novembre 2023 101
4 janv. 2022 à 20:37
Bonjour,

Ta méthode n'est pas la plus simple.
En tout cas, il semble que ton
memmove()
n'a pas les bons paramètres.
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 4 janv. 2022 à 23:19
Salut loki9678,

Comme le dit Dalfab, ta méthode est compliquée... en fait, c'est une usine à gaz :-)

Pour mélanger tes cartes et les tirer une à une, fais comme avec un vrai paquet de cartes :

1. tu mélanges le paquet : fais un shuffle du tableau de 16 éléments, ton tableau contient maintenant tes cartes dans un ordre aléatoire
2. la carte du dessus est : carte_courante = 0
3. tu prends la carte du dessus : tableau[carte_courante]
4. tu incrémentes carte_courante tant qu'il y a des cartes restant à tirer et tu boucles sur 3

Tu fais tout ceci avec un seul tableau et sans avoir à décaler quoi que ce soit ou faire quoi que ce soit d'autre qu'incrémenter l'index après avoir mélangé le contenu du tableau.

Pour faire un bon shuffle renseigne toi sur le mélange Fisher-Yates. Outre la méthode de mélange, tu peux aussi envisager d'utiliser un générateur de nombres aléatoires plus performant que rand() si tu veux un mélange évitant les biais de la fonction standard.

Dal
0
Bonjour Dal,
Merci de votre réponse.
Si j'ai bien compris vous me conseillez de créer un tableau de 16 cartes. Ensuite de mélanger ce tableau avec un shuffle que je devrais potentiellement faire avec la méthode de Fisher-Yates. Et ensuite de tirer les cartes 1 par 1 et dans l'ordre du nouveau tableau mélangé ? Peut-être avec une boucle for je pense

Loki9678
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > loki9678
Modifié le 5 janv. 2022 à 12:41
Oui, c'est cela.

Pour tirer les cartes, il suffit de parcourir le tableau des cartes après mélange, et tu es sûr qu'il n'y a pas de répétitions.

Pour le mélange, tu peux utiliser la méthode que tu veux, mais celle de Fisher-Yates est fiable et simple.
0
loki9678 > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
5 janv. 2022 à 16:09
J'ai essayé alors la méthode de Fisher-Yates cependant je crois que le fait que mon tableau soit composé de chaine de caractère empêche le bon fonctionnement du programme.
Voici le nouveau code:
int main()
{
    int nombreAuSort1,  entree,i,j;
    char tampon[10];

    char pioche1[16][10] = {"carte 1","carte 2","carte 3","carte 4","carte 5","carte 6","carte 7","carte 8",
                            "carte 9","carte 10","carte 11","carte 12","carte 13","carte 14","carte 15","carte 16"
                           };
    srand(time(NULL));
    while(pioche1[6]!='\0')
    {
        for(i=0; i<16; i++)
        {
            printf("%s\n",pioche1[i]);
        }
        printf("Entrez 0 pour piocher:\n");
        scanf("%d",&entree);
        while(entree!=0)
        {
            getchar();
            printf("Entrez 0 pour piocher(vous n'avez pas selectionne 0):\n");
            scanf("%d",&entree);
        }
        if(entree==0)
        {
            for(i=15; i>=0; i--)
            {
                j=rand()%(i);
                strcpy(tampon[0],pioche1[i]);
                strcpy(pioche1[i],pioche1[j]);
                strcpy(pioche1[j],tampon[0]);
            }
            printf("Votre carte est :%s", pioche1[0]);

            for(i=0; i<16; i++)
            {
                printf("%s\n",pioche1[i]);
                printf("%s\n",pioche1[i]);
            }
        }

    }

}



Et voici ce qui ce passe quand j'essaye d'afficher la pioche mélangée:
carte 1
carte 2
carte 3
carte 4
carte 5
carte 6
carte 7
carte 8
carte 9
carte 10
carte 11
carte 12
carte 13
carte 14
carte 15
carte 16
Entrez 0 pour piocher:
0

Process returned -1073741819 (0xC0000005) execution time : 7.086 s
Press any key to continue.



Sauriez vous quelle est l'erreur? Sans vouloir pomper votre temps :)
Merci
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > loki9678
Modifié le 5 janv. 2022 à 18:00
  • tu dois mélanger ton tableau de chaînes avant de faire tes "tirages"
  • un "tirage" est ensuite le passage d'un indice à un autre du tableau, tu n'utilises plus rand()
  • la partie du code en lignes 26 à 32 qui semble faire le mélange ne suit pas exactement l'algorithme :


Pour mélanger un tableau a de n éléments (indicés de 0 à n-1), l'algorithme est le suivant.

Pour i allant de n − 1 à 1 faire :
j ← entier aléatoire entre 0 et i
échanger a[j] et a[i]


https://fr.wikipedia.org/wiki/M%C3%A9lange_de_Fisher-Yates

Je vais voir si je peux te faire un exemple simplifié.
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 5 janv. 2022 à 18:57
Voilà un exemple fonctionnel :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


int main(void)
{
        char tampon[10];
        char pioche[16][10] = {
                "carte 1","carte 2","carte 3","carte 4",
                "carte 5","carte 6","carte 7","carte 8",
                "carte 9","carte 10","carte 11","carte 12",
                "carte 13","carte 14","carte 15","carte 16"
        };

        srand(time(NULL));

        /* mélange de Fisher-Yates de la pioche
         * cf. https://fr.wikipedia.org/wiki/M%C3%A9lange_de_Fisher-Yates  */
        for (int i = 15; i > 0; i--) {
                int j = rand() % i;
                strcpy(tampon, pioche[i]);
                strcpy(pioche[i], pioche[j]);
                strcpy(pioche[j], tampon);
        }

        /* tirage de cartes */
        int carte_courante = 0;
        while (1) {
                printf("Tapez n'importe qu'elle touche pour piocher "
                        "(ou 'q' pour quitter)\n");
                int ch = getchar();
                if (ch == 'q')
                        break;
                printf("Tirage n°%d - vous avez pioché : %s\n",
                        carte_courante + 1, pioche[carte_courante]);
                carte_courante++;
                if (carte_courante > 15) {
                        printf("Vous avez tiré toutes les cartes du paquet\n");
                        break;
                }
        }

        return 0;
}



Dal

Edit : correction de la boucle for pour traiter la dernière permutation
0
Merci beaucoup je vais m'inspirer de votre programme pour faire le mien.
Cependant lorsque je teste votre programme à chaque fois que j'entre un caractère pour tirer ca exécute 2 tirages. Le programme exécute 2 tirages par 2 tirages. Est-ce que c'est normal.
Merci!!!!
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > loki9678
Modifié le 5 janv. 2022 à 19:13
Si tu tapes juste Entrée, tu ne devrais pas voir cela.

C'est effectivement "normal", car si tu tapes un caractère (autre que 'q' qui fait sortir de la boucle) et Entrée, tu as en fait tapé 2 char qui sont consommés successivement par 2 appels à getchar() ... et si tu tapes "toto, titi et tata + Entrée" parce que tu es un rebelle tu auras tapé 19 char et cela fera autant de tirages.

Tu pourrais modifier le code pour purger stdin avant de boucler pour éviter ce genre de choses.

Tu peux modifier cet exemple comme tu veux, mais c'est un peu bizarre de demander à quelqu'un de taper 0 pour faire quelque chose.

C'est juste un exemple rapide. La gestion de la saisie ou intéraction avec l'utilisateur au clavier en C n'est pas quelque chose de trivial si tu veux faire quelque chose de robuste.
0
loki9678 > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
5 janv. 2022 à 19:21
Merci beaucoup.
J'ai enfin compris et je vais juste essayer de faire en sorte que la carte tirée se place à la "fin du paquet".
Enfaite je fais un UNO dans lequel il y a un tirage de carte donc j'ai choisi temporairement la touche 0 pour tirer mais je la changerais plus tard.
Et durant le jeu avec une certaine condition il pourra tirer dans la pioche et donc je devrais afficher quelque chose qui lui permettra de tirer. Je trouvais cela plus facile.
0