Spécifications - Partie 3

Files d’attente et listes chaînées pour le matchmaking
Objectifs
  • Implémenter une file d’attente (queue) pour gérer les joueurs en attente de match
  • Utiliser une liste chaînée pour stocker dynamiquement les joueurs
  • Intégrer la file au système de matchmaking existant
Ressources
  • Cours sur les listes chaînées et les structures auto-référencées
  • Documentation sur les files (FIFO : First In, First Out)
  • Références sur la gestion de la mémoire avec les listes chaînées
Livrables attendus avant la séance 4
Voici les nouveaux fichiers à completer :
headers/
└── list-utils.h      # Déjà créé : prototypes des fonctions de file
src/
├── list-utils.c      # À compléter : implémentation des fonctions de file
└── main.c            # Optionnel : menu interactif pour tester la file

1 Contexte

Dans un système de matchmaking réel, les joueurs ne rejoignent pas tous en même temps. Ils arrivent progressivement et doivent attendre qu’un nombre suffisant de joueurs soit disponible pour former un match.

Une file d’attente (ou queue en anglais) est parfaite pour ce cas :

  • FIFO : First In, First Out (premier arrivé, premier servi)
  • Les joueurs rejoignent par la queue (arrière)
  • Les joueurs sont retirés par la tête (avant)

Dans cette partie, vous allez :

  1. Créer une structure de liste chaînée pour représenter la file
  2. Implémenter les opérations de base : enqueue (ajouter) et dequeue (retirer)
  3. Intégrer cette file au système de matchmaking

2 Structures de données définies dans list-utils.h

2.1 Structure t_cell (celle de la liste chaînée)

typedef struct s_cell {
    Player * value;           // On stocker l'adresse du joueur
    struct s_cell * next;     // Pointeur vers la cellule suivante
} t_cell;

2.2 Structure t_queue (file qui utilise les cellules)

typedef struct s_queue {
    t_cell * head;   // Pointeur vers le premier élément
    t_cell * tail;   // Pointeur vers le dernier élément
} t_queue;
Explication des structures

La file d’attente est en réalité une liste chaînée de type head-tail où chaque cellule stockant un joueur rejoint la file en fin de liste et sort de la file en début de liste.

3 Fonctions à implémenter

Certaines des fonctions ont déjà été présentées en cours, il vous suffit de les adapter à ce contexte.

3.1 Création d’une cellule

t_cell* createCell(Player* player);

Description :
Alloue dynamiquement une nouvelle cellule dont le champ value est initialisé avec le pointeur player et next à NULL. Retourne un pointeur vers la cellule créée ou NULL en cas d’échec d’allocation.


3.2 Libération d’une cellule

void destroyCell(t_cell* cell);

Description :
Libère la mémoire allouée pour la cellule pointée par cell. Ne libère PAS le joueur contenu dans la cellule. Ne fait rien si cell est NULL.

Indications
  • Cette fonction ne libère que la cellule, pas le Player * qu’elle contient
  • Le joueur sera libéré ailleurs (dans le tableau principal ou après utilisation)

3.3 Création d’une file vide

t_queue * createQueue();

Description :
Alloue dynamiquement une nouvelle file et l’initialise comme une file vide c’est à dire une file dont les champs head et tail sont initialisés à NULL. Retourne un pointeur vers la file créée ou NULL en cas d’échec d’allocation.


3.4 Vérification si la file est vide

int isQueueEmpty(t_queue* queue);

Description :
Vérifie si la file queue est vide. Retourne 1 si vide, 0 sinon.


3.5 Ajout d’un joueur à la file

void enqueue(t_queue * queue, Player * player);

Description :
Ajoute le joueur player à la fin de la file queue. Cette fonction crée donc une nouvelle cellule dont le champ value est initialisé avec player puis l’ajoute à la fin de la liste chaînée. Elle met à jour le champ tail de la file en conséquence et met à jour le champ inQueue du joueur à 1.

Indication

Si la file est vide, la nouvelle cellule devient à la fois head et tail


3.6 Retrait d’un joueur de la file

Player * dequeue(t_queue* queue);

Description :
Retire et retourne le premier joueur de la file. Sauvegarde le pointeur du joueur, avance head, libère la cellule avec free() et marque player->inQueue = 0. Retourne le pointeur vers le joueur retiré ou NULL si la file est vide.

Indications
  • Toujours vérifier que la file n’est pas vide avant de retirer
  • Faire attention au cas où la file ne contient qu’une seule cellule
  • Ne pas oublier de marquer player->inQueue = 0
  • Libérer la cellule mais PAS le joueur

3.7 Affichage de la file

void displayQueue(t_queue* queue);

Description :
Affiche tous les joueurs dans la file (du premier au dernier) avec displayPlayerMini(). Affiche un en-tête et le nombre total de joueurs.

Format suggéré :

======= File d'attente =======
1. [Player1 | Lvl: 10 | SI: 1200]
2. [Player2 | Lvl: 8 | SI: 950]
Total: 2 joueurs en attente
==============================

3.8 Retrait de la cellule de tête (fonction auxiliaire)

t_cell * removeHead(t_queue * queue);

Description :
Cette fonction est utile pour la libération de la file d’attende. Elle retire et retourne la première cellule de la file (sans libérer sa mémoire). Marque player->inQueue = 0. Retourne la cellule retirée ou NULL si la file est vide.


3.9 Destruction de la file

void destroyQueue(t_queue * queue);

Description :
Libère toute la mémoire de la file (les cellules ET la structure de file, mais PAS les joueurs). Utilise removeHead() et destroyCell() pour vider la file puis libère toute la mémoire allouée pour queue.


4 Intégration au menu (optionnel)

Vous pouvez ajouter ces options au menu interactif existant pour tester les fonctionnalités de la file :


9.  Ajouter un joueur à la file d'attente
10. Retirer un joueur de la file d'attente
11. Afficher la file d'attente
12. Former un match (retirer jusqu'à 12 joueurs) # Cette fonctionnalité sera vraiment implémentée dans la Partie 4

5 Débogage courant

Problème courant Cause possible
Segmentation fault lors de dequeue Tentative de retrait sur une file vide
tail pointe vers une cellule supprimée Oubli de mettre tail à NULL quand on retire le dernier élément
Joueur ajouté 2 fois Pas de vérification de inQueue
Affichage incorrect de la file Mauvaise mise à jour des pointeurs head et tail
Fuite mémoire Oubli de libérer les cellules lors de la destruction de la file