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