TD n° 11 : Simulation du jeu de cartes de la réussite française
Transcription
TD n° 11 : Simulation du jeu de cartes de la réussite française
TD de programmation structurée : 1ère année 2013-2014 entière. Sur les suites, on ne peut que poser sur le dessus, on doit commencer par 1, et toutes les cartes sont de la même couleur (cœur, pique,carreau, trefle) et sont placées par ordre croissant. TD n° 11 : Simulation du jeu de cartes de la réussite française Buts Durée : Types abstrait : 2 séances Ce Td consiste à simuler le jeu de cartes de réussite. Pour cela, vous allez utiliser les structures chainées de listes, files et piles de cartes. Le jeu comporte un talon où sont distribuées toutes les cartes, face cachée, sauf 4 qui sont posées face visible sur les NBCOL colonnes. L’objectif est de compléter les suites (vides au début) avec les cartes dans l’ordre 1,2,3,4... Pour jouer, on peut soit prendre une carte du dessus du talon, soit prendre la carte du dessus d’une colonne. SUITES COLONNES TALON CARTE TIREE Les contraintes des mouvements des cartes : Figure 1: disposition du jeu Dans les colonnes, vous ne pouvez poser une carte que sur une place vide ou sur une carte immédiatement supérieure et de couleur différente pour former des colonnes de cartes de valeur décroissante et de couleur rouge ou noire alternée (Ex: 8 rouge sur 7 noir, 10 noir sur valet rouge). Vous ne pouvez déplacer que la dernière carte visible de chaque colonne. Les autres sont bloquées,... dommage, non? On peut poser/enlever une carte sur le dessus des colonnes. La première carte d’une colonne peut être quelconque. Vous ne pouvez pas déplacer une colonne Pour gagner à tous les coups, on peut tricher lorsqu’on ne peut pas jouer une carte du talon : on la glisse sous le talon face cachée, pour la rejouer quand tout le paquet sera passé. Le jeu se termine quand les suites sont complètes (on a gagné ou lorsque le jeu est bloqué (on a perdu). L’algorithme est très simple : 1. Créer les 4 colonnes et les 4 suites (piles) qui sont toutes vides 2. Créer le talon (file) vide 3. Mélanger les cartes (cette fonction est donnée, voir section version graphique) 4. Répéter a. Afficher le jeu (le talon, les colonnes et les suites) b. Choisir la carte à jouer (le talon ou une des colonnes) : pour cela, on choisira une correspondance entre les entiers et les talon, colonnes et suites : par exemple, 0 désignera le talon, 1 à NBCOL désigneront les colonnes et NBCOL+1 à NBCOL+4 désigneront les suites. c. défiler (talon) ou dépiler (colonne) cette carte et la visualiser d. Choisir la destination de cette carte (le talon, une colonne ou une suite) e. Vérifier que le mouvement est possible (suite de même couleur, immédiatement croissante ou colonne alternée immédiatement décroissante) f. Si aucun mouvement n’est possible alors perdu=vrai Sinon Enfiler (talon) ou empiler (colonne ou suite) cette carte g. Si toutes les colonnes sont vides et le talon est vide alors gagne=vrai 5. tant que perdu est faux et gagne est faux Remarques : 1. Dans un premier temps, on ne vérifiera pas si le mouvement est possible, en supposant que l’utilisateur ne propose que des mouvements légitimes. 2. Comme on peut toujours remettre une carte dans le talon, il est impossible de perdre avec ces règles. On peut donc éviter le test 4.f comptant les mouvements possibles. Si vous interdisez de remettre les cartes dans le talon, ce test est indispensable. Structures de données Pour simuler le jeu, les structures de données utilisées sont des files et des piles. Vous ne devez utiliser que les fonctions de base définies sur les piles et files de la séance précédente. • Le talon peut être représenté par une file. • Les colonnes et les suites sont des piles, car on ajoute toujours sur le sommet du paquet et on regarde et compare la carte du sommet. Travail à réaliser : 1. Faire un programme qui simule le jeu de la réussite. Dans une première version, ne vérifiez pas la validité d’un coup que l’on veut jouer afin de mettre en place la structure générale de votre programme. 2. Faire une version du programme qui vérifie que le coup est valide. 3. Gérer un affichage graphique des différents éléments du jeu (talon, colonnes, suites) Version graphique Figure 2: mouvements autorisés (vert) et interdits (rouge) 2/5 Des fonctions permettant d’afficher des files et des piles de cartes sous forme graphique sont disponibles. Pour les files, ces fonctions utilisent une représentation des files par liste circulaire. La structure de données représentant une carte contient alors son rang, sa couleur, si elle est face cachée ou non et une nouvelle structure "im" de type ICONE qui contient une image 32 bits ainsi que la dimension de cette image. typedef struct { unsigned int** data; int lig, col; } ICONE; typedef struct { int rang; char visible; char couleur; ICONE im;} CARTE; Voici les fonctions utiles ; • Création des cartes et mélange de ces cartes avec leurs images dans la file ajeu, avec nbcarte pour chaque couleur (nbcarte<14) et en utilisant alea pour démarrer le tirage aléatoire. Pour debugger, utiliser une valeur non nulle pour alea. Pour obtenir des tirages différents, utiliser ensuite des valeurs différentes à chaque exécution. int melanger(File* ajeu, int alea, int nbcarte) Attention : cette fonction utilise la fonction File enfiler(ELEMENT e, File f) que vous devez avoir écrite et tester lors du tp précédent. • affiche une carte à une position : void affichegr(CARTE* e, SDL_Surface* f1,int x, int y) • efface une carte à une position : void effacegr(CARTE* e, SDL_Surface* f1,int x, int y) • Affiche une pile de carte à une position donnée, en décalant les cartes de "decalage" pixels à chaque fois. decalage peut être positif ou négatif. On tient compte des faces cachées. void graphe_pile_d(Pile p, SDL_Surface* f1, int x, int y, int decalage) • Efface une pile de carte à une position donnée, en décalant les cartes de "decalage" pixels à chaque fois. void effacegr_pile_d(Pile p, SDL_Surface* f1, int x, int y, int decalage) • Affiche une file de carte à une position donnée, en décalant les cartes de "decalage" pixels à chaque fois. decalage peut être positif ou négatif. On tient compte des faces cachées. void graphe_file_d(File L, SDL_Surface* f1, int x, int y, int decalage) • Efface une file de carte à une position donnée, en décalant les cartes de "decalage" pixels à chaque fois. void effacegr_file_d(File L, SDL_Surface* f1, int x, int y, int decalage) Voici un exemple qui crée une file de cartes mélangées et faces cachées et une pile de cartes faces visibles (fichier exemple.c) #include <SDL/SDL.h> #include <SDL_phelma.h> #define DECALAGE (20) #include "file.h" #include "pile.h" #include "carte.h" #define DIMX 400 #define DIMY 550 3/5 int main(int argc, char** argv) { int i; // le talon est une file de cartes File talon=creer_file(); // p est une pile de cartes Pile p=creer_pile(); // Une carte CARTE c; // La fenetre graphique SDL_Surface* f1=NULL; /* On crée et mélange toutes les cartes (ici 5*4), avec leur representation sous forme d'image dans la file jeu*/ i=melanger(&talon,1,5); if (i==0) { puts("Il manque les fichiers graphiques"); exit(1); } /* On cree une fenetre graphique */ f1=newfenetregraphique(DIMX,DIMY); /* On affiche le talon complet en x=50, y=10 : Les cartes sont affichees avec un decalage verticale de -20 pixels */ graphe_file_d(talon,f1,50,10,-20); /* On cree une pile avec les premieres cartes du talon */ for (i=0; i<10; i++) { c=defiler(&talon); c.visible=1 ; p=empiler(c,p); } /* On affiche la pile en x=200, y=100; Les cartes sont affichees avec un decalage vertical de -20 pixels */ graphe_pile_d(p,f1,200,100,-20); /* On affiche une carte isolee visible prise sur le talon en 50,300 */ c=defiler(&talon); c.visible=1 ; affichegr(&c,f1,50,300); } Facultatif : Gestion de la souris Comme il est très difficile de faire une partie complète en entrant à la main les numeros de carte à jouer, on peut utiliser la souris. L’exemple ci dessous montre comment gérer la souris et le clavier. La fonction gestionclavier attend que l’on bouge ou clique sur la souris, ou que l’on appuie sur une touche. Lorsque l’on fait ceci, elle modifie les variables *px et *py et retourne une valeur correspondant à une action. Pour appliquer ceci à la reussite comme dans le programme proposé sur le site, il faut par exemple décider qu’un clic sur la touche gauche indique la source du déplacement (etape 5b) et qu’un clic sur la touche droite indique la destination du déplacement (etape 5d). La position de la souris au moment de ces clics vous indique quelles sont les sources (talon ou colonnes) et destination (talon, colonnes, suites). Attention : les coordonnées sont en pixels. Il est pratique de faire une fonction qui a partir des coordonnées x et y, calcule l’entier correspondant à notre codage (0 désignera le talon, 1 à NBCOL désigneront les colonnes et NBCOL+1 à NBCOL+4 désigneront les suites). 4/5 #include #include #include #include <stdio.h> <SDL/SDL.h> <SDL/SDL_image.h> <SDL_phelma.h> /* Fichier demo5.c*/ /* Cette fonction permet de gerer le clavier et la souris */ int gestionclavier(int* px, int* py) { SDL_Event event; /* On attend un evenement, qui peut etre tapez sur le clavier, bouger la souris, etc... Si on ne fait rien, le programme reste bloque ici. */ SDL_WaitEvent(&event); /* On recupere cet evenement et on le traite en fonction de sa nature. */ switch(event.type) { /* Si on decide de quitter la fenetre en cliquant sur fermeture notre fonction retourne 0 */ case SDL_QUIT: return 0; /* Ca, ce sont les evenements de type : appui sur une touche */ /* On retourne 1 a 5 selon la touche tapee (fleche ou ESC), ou -1 si c'est une autre touche */ case SDL_KEYDOWN : switch(event.key.keysym.sym) { case SDLK_UP : return 1; case SDLK_DOWN : return 2; case SDLK_LEFT: return 3; case SDLK_RIGHT : return 4; case SDLK_ESCAPE : return 5; }; return -1; /* La, on bouge la souris : on met les nouvelles coordonnees dans *px et *py et on retourne 6 */ case SDL_MOUSEMOTION: *px=event.motion.x; *py=event.motion.y; return 6; /* La, on clic sur la souris */ /* on met les nouvelles coordonnees dans *px et *py et on retourne 7 a 9 selon le bouton clique */ case SDL_MOUSEBUTTONDOWN: switch (event.button.button) { case SDL_BUTTON_LEFT : *px=event.button.x; *py=event.button.y; return 7; case SDL_BUTTON_MIDDLE : *px=event.button.x; *py=event.button.y; return 8; case SDL_BUTTON_RIGHT : *px=event.button.x; *py=event.button.y; return 9; } } } // Sinon c'est un autre evenement, on retourne -2 return -2; int main(int argc, char *argv[]) { int rep,x,y,dimx=300, dimy=200; SDL_Surface* fenetre; /* Creation d'une fenetre de dimension dimx x dimy, couleurs sur 32 bits */ fenetre = newfenetregraphique(dimx, dimy); /* La boule de traitement : on affiche le type de l'evement et des infos sur cet evenement */ do { /* On attend un evenement */ rep=gestionclavier(&x,&y); /* Il y a eu un evenement graphique */ switch(rep) { case 0 : printf("On doit quitter\n"); break; case 1: printf("On a appuye sur la touche Fleche Haut\n"); break; case 2: printf("On a appuye sur la touche Fleche Bas\n"); break; case 3: printf("On a appuye sur la touche Fleche Gauche\n"); break; case 4: printf("On a appuye sur la touche Fleche Droite\n"); break; case 5: printf("On a appuye sur la touche Escape et on quitte aussi\n"); break; case 6: printf("On a bouge la souris en coordonnees x=%d y=%d\n",x,y); break; case 7: printf("On a le bouton gauche, la souris est en coordonnees x=%d y=%d\n",x,y); break; case 8: printf("On a le bouton milieu, la souris est en coordonnees x=%d y=%d\n",x,y); break; case 9: printf("On a le bouton droit, la souris est en coordonnees x=%d y=%d\n",x,y); break; } } while(rep!=0 && rep!=5); SDL_Quit(); return EXIT_SUCCESS; } 5/5