This document describes the requirements for creating a card game management system in C, including data structure definitions and function implementations.
General Grading Rule:
0.5 points will be deducted for each function that is implemented but not tested in the main function.
cards.h File)We want to define types to handle playing cards. Our playing cards are either cards with a numeric value (from 1 to 10) and a suit (spades, hearts, diamonds, or clubs), or named cards (e.g., "joker").
color
color (via an enum) that can take one of the following values: SPADES, HEARTS, DIAMONDS, and CLUBS.
typedef enum {
SPADES, // Pique
HEARTS, // Coeur
DIAMONDS, // Carreau
CLUBS // Trèfle
} color;
card
card (via a struct) corresponding to a card.
int) and the suit (color).char*).typedef struct card {
bool is_named;
union {
struct {
int value;
color col;
} numeric;
char* name;
} data;
} card;
deck and clist
deck and clist corresponding to a deck of cards and its list.
deck: Must contain two elements:
int).clist*) of a doubly linked list.clist: Each cell (link) in the list must contain:
card*).deck.clist* next).clist* prev).next and prev pointers will contain NULL at the beginning/end of the deck.deck and clist objects will always be manipulated via pointers.typedef ... deck; and clist;typedef struct deck_t deck;
typedef struct clist_t clist;
struct clist_t {
card* content; // Pointeur vers la carte contenue dans cette cellule
deck* ptr_deck; // Pointeur vers le jeu de cartes (deck) auquel cette cellule appartient
clist* next; // Pointeur vers la cellule suivante (NULL si fin de liste)
clist* previous; // Pointeur vers la cellule précédente (NULL si début de liste)
};
struct deck_t {
int nb_cards; // Nombre total de cartes dans le jeu (doit être > 0)
clist* start; // Pointeur vers la première cellule de la liste de cartes
};
typedef struct deck_t deck;
typedef struct clist_t clist;
These lines, placed before the structure definitions, are forward declarations.
They solve a "chicken and egg" problem:
clist_t needs to contain a deck* pointer.deck_t needs to contain a clist* pointer.Which one do you define first? These typedef lines tell the compiler: "Trust me, types named deck and clist will exist. You can use them as pointers for now."
This allows the two structures to reference each other.
color enumeration.card structure (with the union).
card still works (all in a struct), 1 out of 2 points will be awarded.clist and deck structures (correct handling of pointer recursion).cards.c File)You must implement the following functions (prototyped in cards.h) respecting the grading criteria below.
card* createclassiccard(int value, color col);
card* createnamedcard(const char* name);
malloc) of the card (with success test).is_named) and the return.createnamedcard) for the dynamic allocation of the name (char*).createnamedcard) for the correct copying of the name string.card* createclassiccard(int value, color col){
if (value < 1 || value > 10 || col > CLUBS)
{
fprintf(stderr, "wrong arguments for creating a card\n");
exit(EXIT_FAILURE);
}
card* res = mallocandcheck(sizeof(card));
res->is_named = false;
res->data.numeric.col=col;
res->data.numeric.value=value;
return res;
}
card* createnamedcard(const char* name){
if (name == NULL)
{
fprintf(stderr, "wrong arguments for creating a card\n");
exit(EXIT_FAILURE);
}
card* res = mallocandcheck(sizeof(card));
res->is_named = true;
int length = 0;
while(name[length] != '\0'){
length++;
}
res->data.name = mallocandcheck(length+1);
int i = 0;
while(i < length+1){
res->data.name[i] = name[i];
i++;
}
return res;
}
deck* createonecarddeck(card* c);
deck.clist* start).nbrcards) and the return.deck* createonecarddeck(card* c){
deck* res = mallocandcheck(sizeof(deck));
res->nb_cards=1;
res->start = mallocandcheck(sizeof(clist));
res->start->content = c;
res->start->next = NULL;
res->start->previous = NULL;
res->start->ptr_deck = res;
return res;
}
void addcardbefore(clist* l, card* newcard);
clist cell.next/prev pointers).tmp == NULL and insertion in the middle) are handled correctly (updating d->start if necessary).void addcardbefore(clist* l, card* newcard){
clist* newclist = mallocandcheck(sizeof(clist));
clist* tmp = l->previous;
l->previous = newclist;
l->ptr_deck->nb_cards++;
newclist->content = newcard;
newclist->next = l;
newclist->previous = tmp;
if(tmp == NULL)
{
newclist->ptr_deck = l->ptr_deck;
l->ptr_deck->start = newclist;
}
else
{
newclist->ptr_deck = tmp->ptr_deck;
tmp->next = newclist;
}
}
void freedeck(deck* d);
d and d->start are correctly freed (with a test for d != NULL).char* name) of named cards is also freed where applicable.clist cells and all card are freed correctly (without memory leaks).void freedeck(deck* d){
if(d != NULL)
{
clist* l = d->start;
while(l!= NULL)
{
clist* temp = l->next;
if(l->content != NULL)
if(l->content->is_named)
free(l->content->data.name);
free(l->content);
free(l);
l = temp;
}
free(d);
}
}
card* removecard(clist* l);
nbrcards < 2) and updating nbrcards.d->start, prev->next, next->prev).clist cell is not freed).card* removecard(clist* l){
deck* d = l->ptr_deck;
if(d->nb_cards < 2)
{
fprintf(stderr, "wrong argument for card removal\n");
exit(EXIT_FAILURE);
}
d->nb_cards--;
clist* next = l->next;
if(l->previous == NULL)
{
d->start = next;
next->previous = NULL;
}
else
{
clist* prev = l->previous;
prev->next = next;
next->previous = prev;
}
card* res = l->content;
free(l);
return res;
}
void fprintdeck (const char* filename, deck* d);
fopen) and closing (fclose) the file. ("w" or "a" modes are accepted).namedcard vs. numeric card case).void fprintdeck (const char* filename, deck* d){
FILE* f = fopen(filename, "w");
if(f == NULL)
{
fprintf(stderr, "could not open file\n");
exit(EXIT_FAILURE);
}
clist* l = d->start;
while(l!=NULL)
{
if(l->content->is_named)
fprintf(f, "%s\n", l->content->data.name);
else
fprintf(f, "%d %d\n",l->content->data.numeric.value, l->content->data.numeric.col);
l = l->next;
}
fclose(f);
}
clist** distribute(int nbplayers, deck* d);
main Function)The main function must be used to test all implemented functions (except distribute, which is a bonus).
Reminder: 0.5 points will be deducted for each untested function.
Example of test main provided in 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;
}