
Tiplouf Adventure
Auteur : Gabriel Dezon Code reviewer : Arthur Wambst
Introduction
Vos débuts en tant que Dresseur Pokémon dans la région de Sinnoh ont commencé il y a quelques semaines, quand vous avez pu apprendre grâce à l'école Pokémon et notamment au professeur Bertin, que vous étiez éligible pour recevoir votre premier Pokémon.
Il va être tant de partir à l'aventure afin de mettre en pratique tout ce que vous avez appris jusqu'à présent !
Le professeur Bertin vous as donné rendez-vous dans son laboratoire afin que vous puissiez choisir votre premier Pokémon.
Quel choix faites-vous ?
Ok maintenant que vous avez choisi votre Pokémon (et fait le bon choix), il est temps de partir à l'aventure !
Commençons l'aventure !
Architecture
À la fin, votre dépôt git doit suivre cette architecture :
Vérification de l'arborescence : Vous pouvez vérifier l'arborescence actuelle de votre dépôt avec la commande suivante :
tree . -I '.git' -a
.
├── 201_road
│ ├── calculate_exp
│ │ ├── calculate_exp.c
│ │ ├── calculate_exp.h
| | |── main.c
│ │ └── Makefile
│ ├── count_pokemons
│ │ ├── count_pokemons.c
│ │ ├── count_pokemons.h
│ │ ├── main.c
│ │ └── Makefile
│ ├── choose_page
│ │ ├── choose_page.c
│ │ ├── choose_page.h
│ │ ├── main.c
│ │ └── Makefile
│ ├── confused_reverse
│ │ ├── confused_reverse.c
│ │ ├── confused_reverse.h
│ │ ├── main.c
│ │ └── Makefile
│ └── seeking_fight
│ ├── seeking_fight.c
│ ├── seeking_fight.h
│ ├── main.c
│ └── Makefile
├── vestigion_forest
│ ├── get_pokemons
│ │ ├── get_pokemons.c
│ │ ├── get_pokemons.h
│ │ ├── main.c
│ │ └── Makefile
│ ├── hurlement
│ │ ├── hurlement.c
│ │ ├── hurlement.h
│ │ ├── main.c
│ │ └── Makefile
│ ├── check_pokedex
│ │ ├── check_pokedex.c
│ │ ├── check_pokedex.h
│ │ ├── main.c
│ │ └── Makefile
│ ├── load_pokedex
│ │ ├── load_pokedex.c
│ │ ├── load_pokedex.h
│ │ ├── main.c
│ │ └── Makefile
│ └── horde
│ ├── horde.c
│ ├── horde.h
│ ├── main.c
│ └── Makefile
├── feli_cite
│ └── pokemon_struct
│ ├── pokemon_struct.c
│ ├── pokemon_struct.h
│ ├── main.c
│ └── Makefile
├── pokemon_gym
│ └── tournament_winner
│ ├── tournament_winner.c
│ ├── tournament_winner.h
│ ├── main.c
│ └── Makefile
├── README
└── .gitignore
Exigences importantes avant soumission :
- Le fichier README est obligatoire.
- Le fichier .gitignore est obligatoire.
- Le code DOIT compiler ! Sinon vous n'obtiendrez pas de note.
Route 201: Echauffement
File: 201_road/calculate_exp/calculate_exp.c
Cet exercice nécessite les notions suivantes :
- Arrays
- Boucles
- stddef.h
- stdlib.h
Given Files
#ifndef CALCULATE_EXP_H
#define CALCULATE_EXP_H
#include <stddef.h>
#include <stdlib.h>
unsigned int calculate_exp(const unsigned int *exp_array, size_t size);
#endif // CALCULATE_EXP_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = calculate_exp
SRCS = main.c calculate_exp.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Au cours de nos aventures, Tiplouf aura l'occasion de gangner beaucoup d'expérience lors de ses combats avec les autres pokemons. Nous devons trouver un moyen fiable de calculer combien de niveaux il a gagné en fonction de l'expérience qu'il a accumulé.
Écrivez une fonction calculate_exp qui prend en entrée un tableau de unsigned intreprésentant les points d'expérience gagnés par Tiplouf lors de ses combats. Tiplouf gagne un niveau chaque fois qu'il accumule 100 points d'expérience. La fonction doit retourner le nombre de niveaux gagnés par Tiplouf.
unsigned int calculate_exp(const unsigned int *exp_array, size_t size);
Example
#include <stdio.h>
#include "calculate_exp.h"
int main(void) {
unsigned int exp1[] = {50, 60, 70};
unsigned int exp2[] = {100, 200, 300};
unsigned int exp3[] = {150, 250, 350, 90, 10, 40};
unsigned int result1 = calculate_exp(exp1, 3);
unsigned int result2 = calculate_exp(exp2, 3);
unsigned int result3 = calculate_exp(exp3, 6);
printf("calculate_exp({50, 60, 70}) = %u\n", result1); // 1
printf("calculate_exp({100, 200, 300}) = %u\n", result2); // 6
printf("calculate_exp({150, 250, 350, 90, 10, 40}) = %u\n", result3); // 8
return 0;
}
$ make
$ ./calculate_exp
calculate_exp({50, 60, 70}) = 1
calculate_exp({100, 200, 300}) = 6
calculate_exp({150, 250, 350, 90, 10, 40}) = 8
File: 201_road/count_pokemons/count_pokemons.c
Cet exercice nécessite les notions suivantes :
- Strings
- stddef.h
- stdlib.h
Given Files
#ifndef COUNT_POKEMONS_H
#define COUNT_POKEMONS_H
#include <stddef.h>
#include <stdlib.h>
int count_pokemons(const char *str);
#endif // COUNT_POKEMONS_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = count_pokemons
SRCS = main.c count_pokemons.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Il t'arrive de recevoir des notes du professeur Bertin, te listant les pokemons que tu peux croiser dans la région de Sinnoh. Tu dois être capable de déterminer en un coup d'œil combien de pokemons sont listés.
Écrivez une fonction count_pokemons qui prend en entrée une chaîne de caractères et qui compte le nombre de Pokémons présents dans cette chaîne. Les noms de Pokémons sont séparés par des espaces ou tout autre caractère non alphabétique.
int count_pokemons(const char *str);
Example
#include <stdio.h>
#include "count_pokemons.h"
int main(void) {
int count1 = count_pokemons("Pikachu Bulbizarre Salameche Carapuce");
int count2 = count_pokemons("Evoli, Dracaufeu; Mewtwo");
int count3 = count_pokemons(" ;; Mewtwo-Mew - ");
int count4 = count_pokemons("Pikachu123Bulbizarre!Salameche@Carapuce#");
printf("count_pokemons(\"Pikachu Bulbizarre Salameche Carapuce\") = %d\n", count1); // 4
printf("count_pokemons(\"Evoli, Dracaufeu; Mewtwo\") = %d\n", count2); // 3
printf("count_pokemons(\" ;; Mewtwo-Mew - \") = %d\n", count3); // 2
printf("count_pokemons(\"Pikachu123Bulbizarre!Salameche@Carapuce#\") = %d\n", count4); // 4
return 0;
}
$ make
$ ./count_pokemons
count_pokemons("Pikachu Bulbizarre Salameche Carapuce") = 4
count_pokemons("Evoli, Dracaufeu; Mewtwo") = 3
count_pokemons(" ;; Mewtwo-Mew - ") = 2
count_pokemons("Pikachu123Bulbizarre!Salameche@Carapuce#") = 4
File: 201_road/choose_page/choose_page.c
Cet exercice nécessite les notions suivantes :
- Arithmétique des pointeurs
- stddef.h
- stdlib.h
Given Files
#ifndef CHOOSE_PAGE_H
#define CHOOSE_PAGE_H
#include <stddef.h>
#include <stdlib.h>
void choose_page(char **arr, size_t nb_pokemon, size_t page, char*** out_page, size_t* out_size);
#endif // CHOOSE_PAGE_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = choose_page
SRCS = main.c choose_page.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Vous allez commencer à avoir une grande collection de Pokémons ! Afin de mieux vous y retrouver, vous allez les stocker sur un PC, dans la boîte du Professeur Bertin. Dans ce PC, les pokémons sont affichés par page, chaque page contenant maximum 10 Pokémons.
Écrivez une fonction choose_page qui permet de naviguer dans un tableau de Pokémons en pages. Chaque page contient exactement 10 Pokémons. La fonction prend en paramètres :
arr: un tableau de pointeurs vers des chaînes de caractères (noms de Pokémons)nb_pokemon: le nombre total de Pokémons dans le tableaupage: le numéro de la page demandée (en commençant à 1)out_page: pointeur vers un pointeur qui recevra l'adresse du début de la page demandéeout_size: pointeur vers unsize_tqui recevra le nombre de Pokémons dans cette page
La fonction remplit les deux paramètres de sortie. Si la page demandée est invalide (hors limites), mettez out_page et out_size à 0 (ou NULL pour le pointeur).
Note : Vous ne devez pas allouer de mémoire dans cette fonction. Vous devez vous limiter à des manipulations de pointeurs.
void choose_page(char **arr, size_t nb_pokemon, size_t page, char*** out_page, size_t* out_size);
Example
#include <stdio.h>
#include "choose_page.h"
void print_page(char **page, size_t size) {
if (!page || size == 0) {
printf("Page vide ou invalide\n");
return;
}
for (size_t i = 0; i < size; i++) {
printf(" [%zu] %s\n", i, page[i]);
}
}
int main(void) {
char *pokemons[35] = {
"Pikachu", "Bulbizarre", "Salameche", "Carapuce", "Evoli",
"Mewtwo", "Dracaufeu", "Tiplouf", "Tortipouss", "Ouisticram",
"Roucool", "Magicarpe", "Rattata", "Rondoudou", "Nosferapti",
"Abo", "Machoc", "Psykokwak", "Caninos", "Goupix",
"Miaouss", "Mystherbe", "Ortide", "Rafflesia", "Paras",
"Parasect", "Jonquille", "Ortide", "Glabelle", "Taupiqueur",
"Sabelette", "Sablaireau", "Nidoran-F", "Nidorina", "Nidoqueen"
};
size_t nb_pokemon = 35;
// Test 1 : Page 1
char **page1;
size_t size1;
choose_page(pokemons, nb_pokemon, 1, &page1, &size1);
if (page1) {
printf("=== Page 1 ===\n");
print_page(page1, size1);
}
// Test 2 : Page 2
char **page2;
size_t size2;
choose_page(pokemons, nb_pokemon, 2, &page2, &size2);
if (page2) {
printf("\n=== Page 2 ===\n");
print_page(page2, size2);
}
// Test 3 : Page 4 (partielle)
char **page4;
size_t size4;
choose_page(pokemons, nb_pokemon, 4, &page4, &size4);
if (page4) {
printf("\n=== Page 4 (partielle) ===\n");
print_page(page4, size4);
}
// Test 4 : Page invalide
char **page_invalid;
size_t size_invalid;
choose_page(pokemons, nb_pokemon, 5, &page_invalid, &size_invalid);
if (page_invalid == NULL) {
printf("\n=== Page 5 (invalide) ===\n");
printf("Page invalide : out_page = NULL\n");
}
return 0;
}
$ make
$ ./choose_page
=== Page 1 ===
[0] Pikachu
[1] Bulbizarre
[2] Salameche
[3] Carapuce
[4] Evoli
[5] Mewtwo
[6] Dracaufeu
[7] Tiplouf
[8] Tortipouss
[9] Ouisticram
=== Page 2 ===
[0] Roucool
[1] Magicarpe
[2] Rattata
[3] Rondoudou
[4] Nosferapti
[5] Abo
[6] Machoc
[7] Psykokwak
[8] Caninos
[9] Goupix
=== Page 4 (partielle) ===
[0] Sabelette
[1] Sablaireau
[2] Nidoran-F
[3] Nidorina
[4] Nidoqueen
=== Page 5 (invalide) ===
Page invalide : out_page = NULL
File: 201_road/confused_reverse/confused_reverse.c
Cet exercice nécessite les notions suivantes :
- strings
- stddef.h
- stdlib.h
Given Files
#ifndef CONFUSED_REVERSE_H
#define CONFUSED_REVERSE_H
#include <stddef.h>
#include <stdlib.h>
void confused_reverse(char *s);
#endif // CONFUSED_REVERSE_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = confused_reverse
SRCS = main.c confused_reverse.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Tiplouf est confus ! Il répète toutes ses phrases à l'envers. Écrivez une fonction confused_reverse qui inverse une chaîne de caractères EN PLACE.
void confused_reverse(char *s);
Example
#include <stdio.h>
#include "confused_reverse.h"
int main(void) {
char phrase1[] = "Tiplouf est confus !";
char phrase2[] = "Pokemon";
char phrase3[] = "AlEd";
confused_reverse(phrase1);
confused_reverse(phrase2);
confused_reverse(phrase3);
printf("\"Tiplouf est confus !\" -> \"%s\"\n", phrase1); // ! sufnoc tse fuolpiT
printf("\"Pokemon\" -> \"%s\"\n", phrase2); // nomekoP
printf("\"AlEd\" -> \"%s\"\n", phrase3); // dElA
return 0;
}
$ make
$ ./confused_reverse
"Tiplouf est confus !" -> "! sufnoc tse fuolpiT"
"Pokemon" -> "nomekoP"
"AlEd" -> "dElA"
File: 201_road/seeking_fight/seeking_fight.c
Cet exercice nécessite les notions suivantes :
- Tableaux 2D
- strings
- stddef.h
- stdlib.h
- err.h
- math.h
Given Files
#ifndef SEEKING_FIGHT_H
#define SEEKING_FIGHT_H
#include <stddef.h>
char *seeking_fight(char ***matrix, size_t rows, size_t cols, size_t x, size_t y);
#endif // SEEKING_FIGHT_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
LDFLAGS = -lm
TARGET = seeking_fight
SRCS = main.c seeking_fight.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
La distance euclidienne entre deux points (x1, y1) et (x2, y2) est définie par :
distance = racine( (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1) )
- x1 et y1 : coordonnées du premier point
- x2 et y2 : coordonnées du second point
- (x2 - x1) * (x2 - x1) : carré de la différence des abscisses
- (y2 - y1) * (y2 - y1) : carré de la différence des ordonnées
- racine(...) : racine carrée du résultat
Il existe deux types de dresseurs, les dresseurs ambitions qui laissent les pokemons venir à eux, les prendre par surprise, et les dresseurs avec un minimum d'ambition qui vont chercher les pokemons eux-mêmes. Comment vous dire que l'un des deux n'ira pas bien loin dans la région de Sinnoh... Donc hop, hop, hop, écivons une fonction pour trouver le pokemon le plus proche dans les hautes herbes.
Écrivez une fonction seeking_fight qui prend en paramètres une matrice de char* représentant la carte, ses dimensions (rows, cols), et vos coordonnées (x, y). La fonction doit retourner le nom du Pokémon le plus proche de vous (utilisez la distance euclidienne). Une case vide est représentée par un pointeur NULL, donc un Pokémon n'est présent que si la case contient une chaîne de caractères non NULL.
Si plusieurs Pokémons sont à la même distance minimale, retournez celui qui apparaît en premier lors d'un parcours ligne par ligne de la matrice (de gauche à droite, de haut en bas).
Si les paramètres sont invalides (matrice NULL, x ou y hors de la matrice), appelez errx(EXIT_FAILURE, "message d'erreur") avec un message d'erreur approprié.
sqrtLa fonction sqrt de la bibliothèque math.h peut être utile pour calculer la racine carrée.
double sqrt(double x);
char *seeking_fight(char ***matrix, size_t rows, size_t cols, size_t x, size_t y);
Example
#include <stdio.h>
#include "seeking_fight.h"
int main(void) {
char *row0[] = {NULL, NULL, NULL, "Pikachu", NULL, NULL, NULL};
char *row1[] = {NULL, "Bulbizarre", NULL, NULL, NULL, "Evoli", NULL};
char *row2[] = {NULL, NULL, "Salameche", NULL, "Carapuce", NULL, NULL};
char *row3[] = {"Mewtwo", NULL, NULL, NULL, NULL, NULL, "Dracaufeu"};
char *row4[] = {NULL, "Tiplouf", NULL, NULL, NULL, "Tortipouss", NULL};
char *row5[] = {NULL, NULL, "Ouisticram", NULL, "Roucool", NULL, NULL};
char *row6[] = {NULL, NULL, NULL, "Magicarpe", NULL, NULL, NULL};
char **matrix[] = {row0, row1, row2, row3, row4, row5, row6};
size_t rows = 7, cols = 7;
// Test 1 : position centrale
size_t x1 = 3, y1 = 3;
char *closest1 = seeking_fight(matrix, rows, cols, x1, y1);
printf("Test 1: Le Pokemon le plus proche est : %s\n", closest1);
// Test 2 : coin haut gauche
size_t x2 = 0, y2 = 0;
char *closest2 = seeking_fight(matrix, rows, cols, x2, y2);
printf("Test 2: Le Pokemon le plus proche est : %s\n", closest2);
// Test 3 : bord bas droit
size_t x3 = 6, y3 = 6;
char *closest3 = seeking_fight(matrix, rows, cols, x3, y3);
printf("Test 3: Le Pokemon le plus proche est : %s\n", closest3);
// Test 4 : parametres invalides (x hors limites) -> errx EXIT_FAILURE
size_t x_invalid = 10;
size_t y_valid = 3;
seeking_fight(matrix, rows, cols, x_invalid, y_valid);
return 0;
}
$ make
$ ./seeking_fight
Test 1: Le Pokemon le plus proche est : Salameche
Test 2: Le Pokemon le plus proche est : Bulbizarre
Test 3: Le Pokemon le plus proche est : Tortipouss
seeking_fight: Coordonnees (10, 3) invalides pour une matrice 7x7
Forêt de Vestigion (à l'attaque de la mémoire)
File: vestigion_forest/get_pokemons/get_pokemons.c
Cet exercice nécessite les notions suivantes :
- Gestion dynamique de la mémoire (malloc, free)
- strings
- Arithmétique des pointeurs
- stddef.h
- stdlib.h
- string.h
Given Files
#ifndef GET_POKEMONS_H
#define GET_POKEMONS_H
char *get_pokemons(char **pokemons, char sep);
#endif // GET_POKEMONS_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = get_pokemons
SRCS = main.c get_pokemons.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Vous vous souvenez ? Le professeur Bertin vous a demandé de lui fournir une liste de tous les Pokémons que vous avez rencontrés jusqu'à présent, mais pas question delui envoyer un par un ! Elle veut que vous poussiez lui envoyer tout d'un coup!
Écrivez une fonction get_pokemons qui prend en paramètres :
pokemons: un tableau de pointeurs vers des chaînes de caractères (noms de Pokémons), terminé par NULLsep: un caractère séparateur
La fonction doit allouer dynamiquement une nouvelle chaîne de caractères qui concatène tous les Pokémons du tableau, séparés par le caractère sep.
Exemple : Si pokemons = {"Pikachu", "Bulbizarre", "Salamèche", NULL} et sep = ',', la fonction retourne une chaîne contenant "Pikachu,Bulbizarre,Salamèche".
La fonction doit aussi gérer les cas limites :
- Si le tableau est vide ou NULL, retournez une chaîne vide
"".
char *get_pokemons(char **pokemons, char sep);
Example
#include <stdio.h>
#include <stdlib.h>
#include "get_pokemons.h"
int main(void) {
// Test 1 : avec separateur virgule
char *pokemons1[] = {"Pikachu", "Bulbizarre", "Salameche", NULL};
char *result1 = get_pokemons(pokemons1, ',');
printf("Test 1: %s\n", result1); // Pikachu,Bulbizarre,Salameche
free(result1);
// Test 2 : avec separateur espace
char *pokemons2[] = {"Tiplouf", "Evoli", "Mewtwo", NULL};
char *result2 = get_pokemons(pokemons2, ' ');
printf("Test 2: %s\n", result2); // Tiplouf Evoli Mewtwo
free(result2);
// Test 3 : avec separateur tiret
char *pokemons3[] = {"Roucool", "Magicarpe", NULL};
char *result3 = get_pokemons(pokemons3, '-');
printf("Test 3: %s\n", result3); // Roucool-Magicarpe
free(result3);
// Test 4 : tableau vide
char *pokemons4[] = {NULL};
char *result4 = get_pokemons(pokemons4, ',');
printf("Test 4: '%s' (vide)\n", result4); // (chaine vide)
free(result4);
// Test 5 : un seul Pokemon
char *pokemons5[] = {"Dracaufeu", NULL};
char *result5 = get_pokemons(pokemons5, ',');
printf("Test 5: %s\n", result5); // Dracaufeu
free(result5);
return 0;
}
$ make
$ ./get_pokemons
Test 1: Pikachu,Bulbizarre,Salameche
Test 2: Tiplouf Evoli Mewtwo
Test 3: Roucool-Magicarpe
Test 4: '' (vide)
Test 5: Dracaufeu
File: vestigion_forest/hurlement/hurlement.c
Cet exercice nécessite les notions suivantes :
- Manipulation de tableaux
- Allocation mémoire
- stddef.h
- stdlib.h
Given Files
#ifndef HURLEMENT_H
#define HURLEMENT_H
#include <stddef.h>
void hurlement(const char **tab, size_t n, size_t k);
#endif // HURLEMENT_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = hurlement
SRCS = main.c hurlement.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Tiplouf rencontre un nouveau Pokémon dans les hautes herbes de la Forêt de Vestigion : un Grahyèna ! Ce dernier pousse un hurlement qui fait fuir Tiplouf et t'oblige à réorganiser ton équipe de Pokémons. Pour cela, tu dois effectuer une rotation à droite sur ton équipe.
Écrivez une fonction hurlement qui prend en paramètres :
tab: un tableau de pointeurs vers des chaînes de caractères (noms de Pokémons)n: le nombre de Pokémons dans le tableauk: le nombre de positions à faire tourner vers la droite
La fonction doit allouer dynamiquement un nouveau tableau de chaînes de caractères, effectuer la rotation à droite de k positions, et retourner ce nouveau tableau. Le tableau retourné doit être terminé par un pointeur NULL.
Exemple : Si tab = ["Pikachu", "Bulbizarre", "Salameche", "Carapuce"], n = 4, et k = 2, la fonction retourne ["Salameche", "Carapuce", "Pikachu", "Bulbizarre", NULL].
char** hurlement(const char **tab, size_t n, size_t k);
Example
#include <stdio.h>
#include <stdlib.h>
#include "hurlement.h"
void print_tab(char **tab, size_t n) {
for (size_t i = 0; i < n; i++) {
printf("%s", tab[i]);
if (i < n - 1) printf(", ");
}
printf("\n");
}
int main(void) {
// Test 1 : rotation de 2 positions
const char *tab1[] = {"Pikachu", "Bulbizarre", "Salameche", "Carapuce"};
printf("Test 1 - Avant: ");
print_tab(tab1, 4);
char **res1 = hurlement(tab1, 4, 2);
printf("Test 1 - Apres (k=2): ");
print_tab(res1, 4); // Salameche, Carapuce, Pikachu, Bulbizarre
free(res1);
// Test 2 : rotation de 1 position
const char *tab2[] = {"Tiplouf", "Evoli", "Mewtwo", "Roucool"};
printf("\nTest 2 - Avant: ");
print_tab(tab2, 4);
char **res2 = hurlement(tab2, 4, 1);
printf("Test 2 - Apres (k=1): ");
print_tab(res2, 4); // Roucool, Tiplouf, Evoli, Mewtwo
free(res2);
// Test 3 : rotation de 0 position
const char *tab3[] = {"Dracaufeu", "Ouisticram", "Tortipouss"};
printf("\nTest 3 - Avant: ");
print_tab(tab3, 3);
char **res3 = hurlement(tab3, 3, 0);
printf("Test 3 - Apres (k=0): ");
print_tab(res3, 3); // Dracaufeu, Ouisticram, Tortipouss
free(res3);
// Test 4 : rotation superieure a n
const char *tab4[] = {"Nosferapti", "Abo", "Machoc"};
printf("\nTest 4 - Avant: ");
print_tab(tab4, 3);
char **res4 = hurlement(tab4, 3, 5); // 5 % 3 = 2
printf("Test 4 - Apres (k=5, equivalent a k=2): ");
print_tab(res4, 3); // Machoc, Nosferapti, Abo
free(res4);
return 0;
}
$ make
$ ./hurlement
Test 1 - Avant: Pikachu, Bulbizarre, Salameche, Carapuce
Test 1 - Apres (k=2): Salameche, Carapuce, Pikachu, Bulbizarre
Test 2 - Avant: Tiplouf, Evoli, Mewtwo, Roucool
Test 2 - Apres (k=1): Roucool, Tiplouf, Evoli, Mewtwo
Test 3 - Avant: Dracaufeu, Ouisticram, Tortipouss
Test 3 - Apres (k=0): Dracaufeu, Ouisticram, Tortipouss
Test 4 - Avant: Nosferapti, Abo, Machoc
Test 4 - Apres (k=5, equivalent a k=2): Machoc, Nosferapti, Abo
File: vestigion_forest/check_pokedex/check_pokedex.c
Cet exercice nécessite les notions suivantes :
- Gestion des processus (fork, wait, waitpid)
- Appels système (execvp)
- strings
- stddef.h
- stdlib.h
- unistd.h
- sys/wait.h
Given Files
#ifndef CHECK_POKEDEX_H
#define CHECK_POKEDEX_H
void check_pokedex(const char *command);
#endif // CHECK_POKEDEX_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = check_pokedex
SRCS = main.c check_pokedex.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Au bout du 50 messages reçus par le Professeur Bertin pour la même question dont la réponse est toujours "RTFM", elle décide de vous apprendre à lire dans le manuel par vous-même. Pour cela, elle vous demande d'écrire une fonction qui affiche la page de manuel d'une commande donnée.
Écrivez une fonction check_pokedex qui prend en paramètre une chaîne de caractères représentant une commande (p. ex. "ls", "grep", "gcc"), et affiche le manuel (man page) de cette commande.
La fonction doit :
- Créer un processus enfant
- Dans le processus enfant : exécuter la commande
manavec la commande donnée en paramètre (ex:man ls) - Dans le processus parent : attendre la fin du processus enfant puis écrire *** programme successful *** si l'exécution s'est bien passée, ou *** programme failed *** sinon. Une exécution est considérée comme réussie si le processus enfant se termine avec un code de retour 0.
void check_pokedex(const char *command);
Example
#include <stdio.h>
#include "check_pokedex.h"
int main(void) {
printf("=== Consultation du Pokedex pour 'ls' ===\n");
check_pokedex("ls");
printf("=== Consultation du Pokedex pour 'tiplouf' ===\n");
check_pokedex("tiplouf");
return 0;
}
$ make
$ ./check_pokedex
=== Consultation du Pokedex pour 'ls' ===
LS(1) User Commands LS(1)
NAME
ls - list directory contents
SYNOPSIS
ls [OPTION]... [FILE]...
DESCRIPTION
List information about the FILEs (the current directory by default).
Sort entries alphabetically if none of -cftuvSUX nor --sort is spec-
ified.
...
*** programme successful ***
=== Consultation du Pokedex pour 'tiplouf' ===
No manual entry for tiplouf
*** programme failed ***
File: vestigion_forest/load_pokedex/load_pokedex.c
Cet exercice nécessite les notions suivantes :
- Gestion dynamique de la mémoire (malloc, realloc, free)
- Manipulation de pointeurs
- Arithmétique des pointeurs
- stddef.h
- stdlib.h
- string.h
Given Files
#ifndef LOAD_POKEDEX_H
#define LOAD_POKEDEX_H
#include <stddef.h>
void load_pokedex(int** pokedex, const int* other_pokedex, size_t* len_pokedex, size_t len_other_pokedex);
#endif // LOAD_POKEDEX_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = load_pokedex
SRCS = main.c load_pokedex.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Vous dépassez la capacité de votre Pokédex actuel, vous en recevez donc un nouveau de la part du Professeur Bertin. Il faut maintenant charger les données de l'ancien Pokédex dans le nouveau.
Écrivez une fonction load_pokedex qui fusionne deux Pokédex (tableaux d'entiers) en mettant à jour le premier.
La fonction prend en paramètres :
pokedex: pointeur vers un pointeur d'entiers (le Pokédex principal à fusionner et redimensionner)other_pokedex: pointeur vers un tableau d'entiers (le Pokédex à ajouter)len_pokedex: pointeur vers la taille actuelle du premier Pokédex (sera mise à jour)len_other_pokedex: la taille du deuxième Pokédex
La fonction doit :
- Réallouer le premier Pokédex pour accueillir les éléments du deuxième
- Copier tous les éléments du
other_pokedexà la fin dupokedex - Mettre à jour la valeur pointée par
len_pokedexavec la nouvelle taille
Exemple : Si pokedex = [1, 2, 3] (taille 3) et other_pokedex = [4, 5] (taille 2), après l'appel, pokedex devient [1, 2, 3, 4, 5] et len_pokedex devient 5.
void load_pokedex(int** pokedex, const int* other_pokedex, size_t* len_pokedex, size_t len_other_pokedex);
Example
#include <stdio.h>
#include <stdlib.h>
#include "load_pokedex.h"
void print_pokedex(const int *pokedex, size_t len) {
printf("[");
for (size_t i = 0; i < len; i++) {
printf("%d", pokedex[i]);
if (i < len - 1) printf(", ");
}
printf("]\n");
}
int main(void) {
// Test 1 : fusion basique
int *pokedex1 = malloc(3 * sizeof(int));
pokedex1[0] = 1; pokedex1[1] = 2; pokedex1[2] = 3;
size_t len1 = 3;
int other1[] = {4, 5};
size_t len_other1 = 2;
printf("Test 1 - Avant: ");
print_pokedex(pokedex1, len1);
load_pokedex(&pokedex1, other1, &len1, len_other1);
printf("Test 1 - Apres: ");
print_pokedex(pokedex1, len1); // [1, 2, 3, 4, 5]
free(pokedex1);
// Test 2 : fusion avec un Pokedex vide
int *pokedex2 = malloc(2 * sizeof(int));
pokedex2[0] = 10; pokedex2[1] = 20;
size_t len2 = 2;
int other2[] = {};
size_t len_other2 = 0;
printf("\nTest 2 - Avant: ");
print_pokedex(pokedex2, len2);
load_pokedex(&pokedex2, other2, &len2, len_other2);
printf("Test 2 - Apres: ");
print_pokedex(pokedex2, len2); // [10, 20]
free(pokedex2);
// Test 3 : fusion d'un Pokedex vide avec des donnees
int *pokedex3 = malloc(1 * sizeof(int));
pokedex3[0] = 0;
size_t len3 = 1;
int other3[] = {100, 200, 300};
size_t len_other3 = 3;
printf("\nTest 3 - Avant: ");
print_pokedex(pokedex3, len3);
load_pokedex(&pokedex3, other3, &len3, len_other3);
printf("Test 3 - Apres: ");
print_pokedex(pokedex3, len3); // [0, 100, 200, 300]
free(pokedex3);
// Test 4 : fusion avec des Pokedex plus grands
int *pokedex4 = malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++) pokedex4[i] = i + 1;
size_t len4 = 5;
int other4[] = {10, 20, 30, 40, 50, 60};
size_t len_other4 = 6;
printf("\nTest 4 - Avant: ");
print_pokedex(pokedex4, len4);
load_pokedex(&pokedex4, other4, &len4, len_other4);
printf("Test 4 - Apres: ");
print_pokedex(pokedex4, len4); // [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60]
free(pokedex4);
return 0;
}
$ make
$ ./load_pokedex
Test 1 - Avant: [1, 2, 3]
Test 1 - Apres: [1, 2, 3, 4, 5]
Test 2 - Avant: [10, 20]
Test 2 - Apres: [10, 20]
Test 3 - Avant: [0]
Test 3 - Apres: [0, 100, 200, 300]
Test 4 - Avant: [1, 2, 3, 4, 5]
Test 4 - Apres: [1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 60]
File: vestigion_forest/horde/horde.c
Cet exercice nécessite les notions suivantes :
- Gestion des processus (fork, wait, waitpid)
- Affichage concurrentiel (printf)
- Boucles et itération
- stddef.h
- stdlib.h
- stdio.h
- unistd.h
- sys/wait.h
Given Files
#ifndef HORDE_H
#define HORDE_H
#include <stddef.h>
void horde(size_t nb);
#endif // HORDE_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = horde
SRCS = main.c horde.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Écrivez une fonction horde qui crée nb processus enfants en utilisant fork().
Chaque processus enfant doit :
- Afficher :
"Pokemon [PID]: Attaque Tiplouf"- Remplacer
[PID]par l'identifiant réel du processus (obtenu avecgetpid())
- Remplacer
- Puis terminer
Le processus parent doit :
- Attendre que tous les enfants se terminent
- Après que tous les enfants aient terminé, afficher :
"A toi de jouer"
Exemple : Si nb = 3, créer 3 Pokémons qui attaquent tous Tiplouf, puis le parent répond "A toi de jouer".
void horde(size_t nb);
Example
#include <stdio.h>
#include "horde.h"
int main(void) {
printf("=== Début de la horde ===\n");
horde(3);
printf("=== Fin de la horde ===\n");
return 0;
}
$ make
$ ./horde
=== Début de la horde ===
Pokemon [1234]: Attaque Tiplouf
Pokemon [1235]: Attaque Tiplouf
Pokemon [1236]: Attaque Tiplouf
A toi de jouer
=== Fin de la horde ===
Les PIDs et l'ordre d'affichage peuvent varier d'une exécution à l'autre.
Féli-Cité (Structures et Gestion de Mémoire)
File: feli_cite/pokemon_struct/pokemon_struct.c
Cet exercice nécessite les notions suivantes :
- Structures (struct)
- Gestion dynamique de la mémoire (malloc, free)
- strings
- Tableaux de pointeurs
- stddef.h
- stdlib.h
- stdio.h
- string.h
Given Files
#ifndef POKEMON_STRUCT_H
#define POKEMON_STRUCT_H
#include <stddef.h>
struct Pokemon {
char* name;
int health;
int level;
};
struct Pokemon *pokemon_init(const char *name, int base_health);
void pokemon_free(struct Pokemon *pokemon);
void pokemon_print(const struct Pokemon *pokemon);
const char *pokemon_get_name(const struct Pokemon *pokemon);
struct Pokemon **get_all_pokemon_evolved(struct Pokemon **pokemons, size_t size, int level_threshold);
#endif // POKEMON_STRUCT_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = pokemon_struct
SRCS = main.c pokemon_struct.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "pokemon_struct.h"
void test_pokemon_print(void) {
printf("=== Test: pokemon_print ===\n");
printf("Pokemon cree:\n");
Pokemon *bulbizarre = pokemon_init("Bulbizarre", 45);
pokemon_print(bulbizarre);
pokemon_free(bulbizarre);
}
void test_pokemon_get_name(void) {
printf("=== Test: pokemon_get_name ===\n");
Pokemon *carapuce = pokemon_init("Carapuce", 44);
const char *name = pokemon_get_name(carapuce);
printf("Recuperation du nom: %s\n", name);
pokemon_free(carapuce);
}
void test_pokemon_evolved(void) {
printf("=== Test: get_all_pokemon_evolved ===\n");
Pokemon *pikachu = pokemon_init("Pikachu", 35);
pikachu->level = 5;
Pokemon *bulbizarre = pokemon_init("Bulbizarre", 45);
bulbizarre->level = 3;
Pokemon *salameche = pokemon_init("Salameche", 39);
salameche->level = 2;
Pokemon **all_pokemons = malloc(4 * sizeof(Pokemon *));
all_pokemons[0] = pikachu;
all_pokemons[1] = bulbizarre;
all_pokemons[2] = salameche;
all_pokemons[3] = NULL;
printf("Tous les Pokemons:\n");
for (size_t i = 0; all_pokemons[i] != NULL; i++) {
printf(" - %s (niveau %d)\n", all_pokemons[i]->name, all_pokemons[i]->level);
}
Pokemon **evolved = get_all_pokemon_evolved(all_pokemons, 3, 3);
printf("\nPokemons de niveau >= 3:\n");
for (size_t i = 0; evolved[i] != NULL; i++) {
printf(" - %s (niveau %d)\n", evolved[i]->name, evolved[i]->level);
}
pokemon_free(pikachu);
pokemon_free(bulbizarre);
pokemon_free(salameche);
free(all_pokemons);
free(evolved);
}
void test_all(void) {
test_pokemon_print();
printf("\n");
test_pokemon_get_name();
printf("\n");
test_pokemon_evolved();
}
int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s [print|get_name|evolved|all]\n", argv[0]);
return 1;
} else if (strcmp(argv[1], "print") == 0) {
test_pokemon_print();
} else if (strcmp(argv[1], "get_name") == 0) {
test_pokemon_get_name();
} else if (strcmp(argv[1], "evolved") == 0) {
test_pokemon_evolved();
} else if (strcmp(argv[1], "all") == 0) {
test_all();
} else {
printf("Argument non reconnu: %s\n", argv[1]);
return 1;
}
return 0;
}
Given: pokemon_init
La fonction pokemon_init initialise une structure Pokémon avec un nom et une santé de base. Copiez-la dans votre fichier pokemon_struct.c.
#include <stdlib.h>
#include <string.h>
#include "pokemon_struct.h"
struct Pokemon *pokemon_init(const char *name, int base_health) {
struct Pokemon *pokemon = malloc(sizeof(struct Pokemon));
if (pokemon == NULL) {
return NULL;
}
pokemon->name = strdup(name);
pokemon->health = base_health;
pokemon->level = 1;
return pokemon;
}
Given: pokemon_free
La fonction pokemon_free libère complètement la mémoire alloué par la structure Pokémon. Copiez-la dans votre fichier pokemon_struct.c.
void pokemon_free(struct Pokemon *pokemon) {
if (pokemon == NULL) {
return;
}
free(pokemon->name);
free(pokemon);
}
Your Task: pokemon_print
Écrivez une fonction pokemon_print qui affiche un Pokémon formaté.
La fonction doit afficher le Pokémon au format :
Name: [name]
Health: [health]
Level: [level]
void pokemon_print(const Pokemon *pokemon);
Test: pokemon_print
$ make
$ ./pokemon_struct print
=== Test: pokemon_print ===
Pokemon cree:
Name: Bulbizarre
Health: 45
Level: 1
Your Task: pokemon_get_name
Écrivez une fonction pokemon_get_name qui retourne le nom d'un Pokémon.
La fonction doit simplement retourner le nom du Pokémon.
const char *pokemon_get_name(const Pokemon *pokemon);
Test: pokemon_get_name
$ make
$ ./pokemon_struct get_name
=== Test: pokemon_get_name ===
Recuperation du nom: Carapuce
Your Task: get_all_pokemon_evolved
Écrivez une fonction get_all_pokemon_evolved qui filtre les Pokémons par niveau.
La fonction doit :
- Prendre un tableau de Pokémons et un seuil de niveau
- Retourner un nouveau tableau contenant les Pokémons ayant un niveau >=
level_threshold - Le tableau retourné doit être alloué dynamiquement et terminé par NULL
- Les Pokémons dans le nouveau tableau sont les mêmes objets (pas des copies)
Pokemon **get_all_pokemon_evolved(Pokemon **pokemons, size_t size, int level_threshold);
Test: get_all_pokemon_evolved
$ make
$ ./pokemon_struct evolved
=== Test: get_all_pokemon_evolved ===
Tous les Pokemons:
- Pikachu (niveau 5)
- Bulbizarre (niveau 3)
- Salameche (niveau 2)
Pokemons de niveau >= 3:
- Pikachu (niveau 5)
- Bulbizarre (niveau 3)
Le fichier main.c fourni dans les "Given Files" contient les fonctions de test pour chaque fonction. Utilisez les arguments print, get_name, evolved, ou all pour lancer les tests.
Arène de Féli-Cité (Processus et Pipes)
File: pokemon_gym/tournament_winner/tournament_winner.c
Cet exercice nécessite les notions suivantes :
- Gestion des processus (fork, wait, waitpid)
- Communication inter-processus (pipes)
- Manipulation de tableaux
- Arithmétique des pointeurs
- stddef.h
- stdlib.h
- unistd.h
- sys/wait.h
Given Files
#ifndef TOURNAMENT_WINNER_H
#define TOURNAMENT_WINNER_H
#include <stddef.h>
int tournament_winner(const int *pokemons, size_t size);
#endif // TOURNAMENT_WINNER_H
CC = gcc
CFLAGS = -Wall -Wextra -Werror -g
TARGET = tournament_winner
SRCS = main.c tournament_winner.c
OBJS = $(SRCS:.c=.o)
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(OBJS) $(TARGET)
.PHONY: all clean
Your Task
Allez c'est l'heure du tournoi Pokémon ! C'est la bataille ultime pour déterminer le Pokémon le plus fort parmi tous les participants. Jouons ce combat !
Écrivez une fonction tournament_winner qui détermine le gagnant d'un tournoi (l'entier le plus grand) en utilisant un système de processus récursif et des pipes pour la communication.
La fonction prend en paramètres :
pokemons: un tableau d'entiers représentant les participants du tournoisize: la taille du tableau
Algorithme :
- Cas de base : Si
size == 2, retournez l'entier le plus grand des deux - Cas récursif : Si
size > 2:- Divisez le tableau en deux moitiés (gauche et droite)
- Créez deux processus enfants
- Chaque enfant appelle récursivement
tournament_winnersur sa moitié - Communiquez via des pipes : chaque enfant envoie son résultat au parent
- Le résultat du combat : chaque enfant affiche le vainqueur (le plus grand des deux entiers qu'il a reçus) en disant
"[PID]: Pokemon [value] wins!" - Le parent reçoit les deux résultats et retourne le plus grand
Exemple : Si pokemons = [5, 3, 8, 2, 9, 1, 7, 4], la fonction :
- Crée deux enfants : l'un pour
[5, 3, 8, 2], l'autre pour[9, 1, 7, 4] - Le premier enfant retourne
8, le second retourne9 - Le parent retourne
9(le maximum)
Un combat qui ne contient qu'un seul Pokémon renvoie simplement ce Pokémon comme gagnant, ce cas arrive lorsque la taille du tableau est impaire.
Oui l'exercice peut être résolu sans processus, mais l'objectif est de pratiquer la gestion des processus et des pipes.
int tournament_winner(const int *pokemons, size_t size);
Example
#include <stdio.h>
#include "tournament_winner.h"
int main(void) {
// Test 1 : deux Pokemons
printf("=== Test 1: deux Pokemons ===\n");
int pokemons1[] = {5, 3};
int winner1 = tournament_winner(pokemons1, 2);
printf("Gagnant: %d\n\n", winner1);
// Test 2 : quatre Pokemons
printf("=== Test 2: quatre Pokemons ===\n");
int pokemons2[] = {5, 3, 8, 2};
int winner2 = tournament_winner(pokemons2, 4);
printf("Gagnant: %d\n\n", winner2);
// Test 3 : huit Pokemons
printf("=== Test 3: huit Pokemons ===\n");
int pokemons3[] = {5, 3, 8, 2, 9, 1, 7, 4};
int winner3 = tournament_winner(pokemons3, 8);
printf("Gagnant: %d\n", winner3);
return 0;
}
$ make
$ ./tournament_winner
=== Test 1: deux Pokemons ===
[1234]: Pokemon 5 wins!
Gagnant: 5
=== Test 2: quatre Pokemons ===
[1234]: Pokemon 8 wins!
[1235]: Pokemon 2 wins!
[1233]: Pokemon 8 wins!
Gagnant: 8
=== Test 3: huit Pokemons ===
[1234]: Pokemon 5 wins!
[1235]: Pokemon 8 wins!
[1236]: Pokemon 9 wins!
[1237]: Pokemon 7 wins!
[1233]: Pokemon 8 wins!
[1232]: Pokemon 9 wins!
[1231]: Pokemon 9 wins!
Gagnant: 9
Les PIDs et l'ordre d'affichage peuvent varier d'une exécution à l'autre.