- Implémenter la gestion complète des matchs entre joueurs
- Simuler les résultats et mettre à jour les statistiques des joueurs en conséquence
- Apporter votre touche personnelle avec des fonctionnalités bonus
- Cours sur les structures complexes en C
- Documentation sur les algorithmes de mélange (Fisher-Yates)
- Références sur la manipulation de tableaux et de pointeurs
Fichiers à compléter :
headers/
└── match.h # Prototypes des fonctions de gestion des matchs
src/
├── match.c # Implémentation des fonctions de gestion des matchs
└── main.c # Optionnel : menu interactif pour tester les matchs
Vous avez également de rajouter des fichiers sources supplémentaires pour les fonctionnalités bonus ou les améliorations que vous souhaitez implémenter. (Ces fichiers ne sont pas fournis dans le template et ne seront pas soumis aux tests)
1 Contexte
Les matchs dans Fork Knight rassemblent plusieurs joueurs (jusqu’à 12) et déterminent un classement final. Chaque joueur voit son spicyIndex et ses statistiques mises à jour en fonction de sa performance dans le match.
Dans cette partie, vous allez :
- Créer une structure
Matchpour gérer les participants et les résultats - Implémenter des fonctions pour simuler un match, afficher les résultats et mettre à jour les statistiques des joueurs
2 Structure de données
Fichier : headers/match.h
#define MATCH_MAX_PLAYERS 12
typedef struct {
Player ** players; // participants
int * results; // results[r] = index du joueur classé r (0 = vainqueur)
int numPlayers; // nb de joueurs (<= 12)
} Match;results stocke des indices vers players, déjà ordonnés du 1er au dernier.
3 Fonctions à implémenter
3.1 Création d’un match
Match * createMatch();Description :
Alloue dynamiquement un match, alloue dynamiquement le tableau players avec une capacité de MATCH_MAX_PLAYERS, initialise le champ results à NULL, et le champ numPlayers à 0. La fonction retourne un pointeur vers le match créé, ou NULL en cas d’échec d’allocation.
3.2 Libération de la mémoire d’un match
void destroyMatch(Match* match);Description :
Libère la mémoire allouée pour un match. Ne pas libérer les joueurs dans players, seulement le tableau lui-même et le tableau results s’il n’est pas NULL. Enfin, libère la structure Match.
3.3 Ajout d’un joueur au match
void addMatchPlayers(t_queue * queue, Match * match);Description :
Cette fonction prend en paramètre une file queue et un un pointeur match. Elle ajoute des joueurs depuis la file à match->players jusqu’à ce que la file soit vide ou que match->numPlayers atteigne MATCH_MAX_PLAYERS. Pour chaque joueur retiré de la file, le champ inQueue du joueur est mis à 0. (Utilisez la fonction dequeue() pour retirer les joueurs de la file.)
3.4 Simulation du match
void simulateMatch(Match* match);Description :
Simuler un match revient à remplir son tableau results. Cette fonction alloue dynamiquement le tableau results de taille numPlayers puis simule le match en le remplissant avec des valeurs allant de 0 à numPlayers - 1 dans un ordre aléatoire (permutation uniforme) en utilisant l’algorithme de Fisher-Yates pour garantir une distribution uniforme.
Attention :
Il est possible que simulateMatch() soit appelé plusieurs fois sur le même match, assurez-vous de libérer la mémoire précédemment allouée pour results avant d’en allouer une nouvelle.
Algorithme de Fisher-Yates : L’algorithme de Fisher-Yates permet de générer une permutation aléatoire d’un tableau. Voici un exemple d’implémentation en C :
void fisherYatesShuffle(int * array, int n) {
for (int i = n - 1; i > 0; i--) {
int j = rand() % (i + 1); // indice aléatoire entre 0 et i
// Échange array[i] et array[j]
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}Vous pouvez testez cette fonction avec un tableau d’entier pour vérifier qu’elle génère bien des permutations aléatoires.
3.5 Mise à jour des statistiques des joueurs après un match
void updatePlayerStats(Match * match);Description :
Cette fonction met à jour les statistiques de chaque joueur dans match->players en fonction de leur position dans match->results. Pour chaque joueur p à la position r dans results (où r est le rang, 0 pour le vainqueur, 1 pour le second, etc.) :
Incrémente
p->numGamesde 1Si le joueur est le vainqueur (
r == 0), incrémentep->numWinsde 1, sinon incrémentep->numLossesde 1Incrémente
p->spicyIndexd’une valeur calculée comme suit :gain à la position r = (n - r - 1) * (100 / (n - 1))
Exemple Pour un match avec 5 joueurs (n=5) :
- Rang 0 (vainqueur) : gain = (5 - 0 - 1) * (100 / (5 - 1)) = 4 * 25 = 100
- Rang 1 : gain = (5 - 1 - 1) * (100 / (5 - 1)) = 3 * 25 = 75
- Rang 2 : gain = (5 - 2 - 1) * (100 / (5 - 1)) = 2 * 25 = 50
- Rang 3 : gain = (5 - 3 - 1) * (100 / (5 - 1)) = 1 * 25 = 25
- Rang 4 : gain = (5 - 4 - 1) * (100 / (5 - 1)) = 0 * 25 = 0
3.6 Affichage des informations du match
void displayMatchInfo(const Match* match);Description :
Affiche les joueurs participants aux match avec la fonction displayPlayerMini(), ainsi que le nombre total de joueurs. La fonction doit afficher une erreur si le match est NULL.
Format suggéré :
========================================
MATCH INFORMATION
========================================
Participants: 12
----------------------------------------
1. [ForkMaster | Lvl: 10 | Spicy: 1200]
2. [SpoonyKnight | Lvl: 8 | Spicy: 950]
3. [KnifeLord | Lvl: 15 | Spicy: 1500]
4. [RustyFork | Lvl: 3 | Spicy: 600]
5. [SteelBlade | Lvl: 12 | Spicy: 1000]
========================================
3.7 Affichage des résultats du match
void displayMatchResult(const Match* match);Description :
Affiche les résultats du match dans l’ordre du classement final, en utilisant displayPlayerMini() pour chaque joueur. La fonction doit afficher une erreur si le match ou les résultats sont NULL.
Format suggéré :
========================================
MATCH RESULTS
========================================
1. [KnifeLord | Lvl: 15 | Spicy: 1500] (+100)
2. [ForkMaster | Lvl: 10 | Spicy: 1200] (+75)
3. [SpoonyKnight | Lvl: 8 | Spicy: 950] (+50)
4. [RustyFork | Lvl: 3 | Spicy: 600] (+25)
5. [SteelBlade | Lvl: 12 | Spicy: 1000] (+0)
========================================
3.8 Simulation complète d’un match
void launchMatch(t_queue * queue);Description :
Cette fonction combine toutes les étapes précédentes pour simuler un match complet :
- Crée un match avec
createMatch() - Ajoute des joueurs depuis la file
queueavecaddMatchPlayers() - Affiche les informations du match avec
displayMatchInfo() - Simule le match avec
simulateMatch() - Met à jour les statistiques des joueurs avec
updatePlayerStats() - Affiche les résultats du match avec
displayMatchResult() - Libère la mémoire du match avec
destroyMatch()
Elle doit gérer les erreurs d’allocation mémoire et afficher des messages appropriés.
3.9 Lancement d’un match équilibré depuis une file de priorité
void launchBalancedMatch(t_priority_queue * p_queue);Description :
Cette fonction est similaire à launchMatch(), mais elle utilise une file de priorité p_queue pour sélectionner les joueurs. Elle doit extraire jusqu’à MATCH_MAX_PLAYERS joueurs de la file de priorité en utilisant removeHighestPriority(), puis suivre les mêmes étapes que launchMatch() pour simuler et afficher le match.
5 Améliorations possibles pour aller plus loin (bonus)
5.1 Imaginer des Matchs par équipes
- Diviser les 12 joueurs en 2 équipes de 6
- Simuler un résultat d’équipe
- Distribuer les gains selon l’équipe gagnante
5.2 Modes de jeu différents
- Solo (12 joueurs, 1 gagnant)
- Duo (6 équipes de 2)
- Squad (4 équipes de 3)
5.3 Historique des matchs
- Sauvegarder tous les matchs dans un fichier
- Statistiques globales (taux de victoire, progression, etc.)
Bravo ! Vous avez maintenant un système de matchs complet et fonctionnel. 🎮⚔️