Ce document décrit les exigences pour la création d'un système de gestion de cartes à jouer en C, incluant la définition des structures de données et l'implémentation des fonctions de manipulation.
Règle générale de notation :
0.5 point sera enlevé pour chaque fonction implémentée mais non testée dans la fonction main.
cards.h)On veut définir des types pour traiter des cartes à jouer. Nos cartes à jouer sont soit des cartes ayant une valeur numérique (de 1 à 10) et une couleur (pique, coeur, carreau ou treffle), soit des cartes nommées (par exemple "jocker").
color
color (via une enum) qui peut prendre une valeur parmi : SPADES, HEARTS, DIAMONDS, et CLUBS.
card
card (via une struct) correspondant à une carte.
int) et la couleur (color).char*).deck et clist
deck et clist correspondant à un jeu de cartes et à sa liste.
deck : Doit contenir deux éléments :
int positif non nul).clist*) d'une liste doublement chaînée.clist : Chaque cellule (maillon) de la liste doit contenir :
card*).deck parent.clist* next).clist* prev).next et prev contiendront NULL en début/fin de paquet.deck et clist seront toujours manipulés par des pointeurs.typedef ... deck; et clist;typedef struct deck_t deck;
typedef struct clist_t clist;
Ces lignes, placées avant la définition des structures, sont des déclarations anticipées (forward declarations).
Elles résolvent un problème "d'œuf et de poule" :
clist_t doit contenir un pointeur deck*.deck_t doit contenir un pointeur clist*.Lequel définissez-vous en premier ? Ces typedef disent au compilateur : "Fais-moi confiance, les types deck et clist vont exister. Tu peux les utiliser comme pointeurs pour l'instant."
Cela permet aux deux structures de se référencer mutuellement.
color.card (avec l'union).
card fonctionne (tout en structure), 1 point sur 2 sera attribué.clist et deck (gestion correcte de la récursion des pointeurs).cards.c)Vous devez implémenter les fonctions suivantes (dont les prototypes sont dans cards.h) en respectant les critères de notation ci-dessous.
card* createclassiccard(int value, color col);
card* createnamedcard(const char* name);
malloc) de la carte (avec test de réussite).is_named) et le return.createnamedcard) pour l'allocation dynamique du nom (char*).createnamedcard) pour la copie correcte de la chaîne de caractères du nom.deck* createonecarddeck(card* c);
deck.clist* start).nbrcards) et le return.void addcardbefore(clist* l, card* newcard);
clist.next/prev).tmp == NULL et insertion au milieu) sont gérés correctement (mise à jour de d->start si nécessaire).void freedeck(deck* d);
d et d->start sont correctement libérés (avec un test pour d != NULL).char* name) des cartes nommées est également libéré le cas échéant.clist et de toutes les card est faite correctement (sans fuite de mémoire).card* removecard(clist* l);
nbrcards < 2) et la mise à jour de nbrcards.d->start, prev->next, next->prev).clist retirée n'est pas free).void fprintdeck (const char* filename, deck* d);
fopen) et la fermeture (fclose) correctes du fichier. (Les modes "w" ou "a" sont acceptés).namedcard vs carte numérique).clist** distribute(int nbplayers, deck* d);
main)La fonction main doit être utilisée pour tester toutes les fonctions implémentées (sauf distribute qui est bonus).
Rappel : 0.5 point sera enlevé pour chaque fonction non testée.
Exemple de main de test fourni dans cards.c :
int main(void){
card* c1 = createclassiccard(6,HEARTS);
card* c2 = createclassiccard(2,SPADES);
card* c3 = createclassiccard(3,CLUBS);
card* c4 = createnamedcard("jocker");
card* c5 = createnamedcard("rulescard");
deck* d = createonecarddeck(c1);
addcardbefore(d->start, c2);
addcardbefore(d->start, c3);
addcardbefore(d->start->next, c4);
addcardbefore(d->start, c5);
removecard(d->start);
fprintdeck("foo1.txt",d);
free(distribute(2,d));
fprintdeck("foo2.txt",d);
freedeck(d);
return EXIT_SUCCESS;
}