# Holiday Trip

# Holiday Trip `1.0.3`

## Struct, Enum, Union

If there is a conflict between the subject and the skeleton or moulinette, the subject is always right.
However, please report any inconsistencies to your assistant.
Submissions

- intranet: https://intra.forge.epita.fr/epita-prepa-computer-science/prog-103-p-04-2030/root/
- opening: `2026-02-09 10:42`
- closing: `2026-02-16 10:42`
- git tags:
  - `submit-*` (limit: 3 per week)
  - `archi-*` (limit: 2 per hour)

Repository structure
At the end, your git repo must follow this architecture:

    epita-prepa-computer-science-prog-103-p-04-2030-firstname.lastname
    ├── HolidayTrip
    │   ├── Fundamentals
    │   │   ├── my_strings
    │   │   │   ├── Makefile
    │   │   │   ├── main.c
    │   │   │   ├── my_strings.c
    │   │   │   └── my_strings.h
    │   │   ├── radar
    │   │   │   ├── Makefile
    │   │   │   ├── main.c
    │   │   │   ├── radar.c
    │   │   │   └── radar.h
    │   │   └── reap_and_tear
    │   │       ├── Makefile
    │   │       ├── demon.c
    │   │       ├── demon.h
    │   │       ├── main.c
    │   │       ├── print.c
    │   │       ├── villager.c
    │   │       ├── villager.h
    │   │       ├── weapons.c
    │   │       └── weapons.h
    │   └── Proficiencies
    │       ├── animals
    │       │   ├── Makefile
    │       │   ├── animals.h
    │       │   ├── fish.c
    │       │   ├── insect.c
    │       │   ├── main.c
    │       │   ├── vector.c
    │       │   └── vector.h
    │       └── museum_restoration
    │           ├── Makefile
    │           ├── fossils.c
    │           ├── fossils.h
    │           └── main.c
    ├── .gitignore
    └── README

Do not forget to check the following requirements before submitting your work:

- You shall obviously replace `firstname.lastname` with your login.
- The `.gitignore` file is mandatory.
- Remove all personal tests from your code, except those from the `Tests` folder.
- The given prototypes must be strictly respected.
- The code MUST compile! Otherwise you will not receive a grade.

.gitignore example
Here is an example of a `.gitignore` file:

    *.a
    *.lib
    *.o
    *.obj
    *.out

    .idea/
    *~
    *.DotSettings.user

This needs to be setup before the first submission!

# Introduction

Lore
In 2020, while preparing for her trip to the beautiful island we live on. Isabelle made a new friend, they spent some good times together, but on the 20th of March 2020, they had to part ways.
However they made a song together, and they promised that they would meet each other again.
She received a letter saying that he would arrive today. The issue is that he uses many items and technologies in his world that don't exist in yours, thus you'll have to help him during his trip to rebuild his items, or at least some that have the same purpose.
To do so, let's use structs and enums !!!
Danger(s)
Unless explicitly stated otherwise, the only allowed headers are `<stddef.h>`, `<stdlib.h>`, `<stdio.h>` and `<string.h>`.
Information
Makefiles with empty mains are included in the given files to make testing easier.
You can extract them with the command `tar -xvf assets.tar.gz`.
In this practical, even though you are required to submit the main files, their content will not be tested.
In this first section, we will focus on the basics of data organization in C.
You will learn how to define and use `structs` to group variables and `enums` to represent states or constants.

### `my_strings/my_strings.h`

Lore
Communication is proving difficult: Isabelle's friend comes from a world where text is handled with precision, not just by hoping for a `\0` character.
To process his data and rebuild his items correctly, you need to implement a struct string that keeps track of both the content and its exact length.
Lore
This header file acts as the blueprint for the new communication system. It defines the internal structure of the alien `string` and declares the set of functions (prototypes) you need to implement to make it work.
Hint(s)
Don't forget to add header guards.
This struct represents a string as follows:

- `char *data`: A pointer to the character array (the actual string content).
- `size_t size`: The number of characters in the string.

Code example(s)

    struct string
    {
        char *data;
        size_t size;
    };

Prototype(s)

    struct string *my_str_init(const char* s, size_t size);

    void my_str_destroy(struct string *str);
    void my_str_puts(struct string *str);
    struct string *my_str_n_cat(struct string *str1, const char *str2, size_t str2_len);

### `my_strings/my_strings.c`

Lore
This is the workshop where the translation tool comes to life.
Using the blueprints from the header file, you must now implement the logic that allows Isabelle's friend to communicate.
Be careful: unlike in his world, memory here is managed manually: you build it, you clean it.
This function allocates a new string structure on the heap using `malloc(3)` and returns a pointer to it.
If `size` is zero or `s` is `NULL`, the `data` field is initialized to `NULL` and the `size` field to `0`.
Otherwise, initialize your `data` field with `size` bytes from `s`.
Information
You must include the `my_strings.h` header to use the `struct string`.
Warning(s)
Do not simply assign the pointer `s` to data (shallow copy). The structure must own its own memory. Modifying the original string `s` afterwards should not affect your structure.
Prototype(s)

    struct string *my_str_init(const char* s, size_t size);

Code example(s)

    struct string *str = my_str_init("Hello World!", 12);
    printf("data: %.*s\n", (int)str->size, str->data);

Expected output

    data: Hello World!

Hint(s)
You can get the size of a struct with `sizeof(struct string)`.
Frees the memory allocated for the string structure and its internal data.
If the pointer `str` is `NULL`, the function does nothing.
Prototype(s)

    void my_str_destroy(struct string *str);

Code example(s)

    struct string *str = my_str_init("Hello World!", 12);
    my_str_destroy(str);

Expected output

    (No output, just ensure there are no memory leaks with -fsanitize=address)

Prints the content of the `string` structure to the standard output, followed by a newline.
If the `data` field is `NULL` or the `size` is `0`, it should simply print a newline.
If the `str` pointer is `NULL`, the function does nothing.
Hint(s)
You can use the `putchar(3)` function.
Prototype(s)

    void my_str_puts(struct string *str);

Code example(s)

    struct string *str = my_str_init("Hello Alien World!", 18);
    my_str_puts(str);
    my_str_destroy(str);

Expected output

    Hello Alien World!

Appends `str2_len` characters from `str2` to the `string` structure.
You must ensure sufficient memory is allocated and update the `size` field accordingly.
The function must return the pointer to the `string` structure containing the concatenation.
If `str1` is `NULL`, a new string structure must be initialized.
If `str2` is `NULL` or the size is `0`, no operation is performed.
Hint(s)
You might need to use `realloc(3)` to resize the allocated memory.
Prototype(s)

    struct string *my_str_n_cat(struct string *str1, const char *str2, size_t str2_len);

Code example(s)

    struct string *str = my_str_init("Hello ", 6);
    str = my_str_n_cat(str, "Alien World!", 12);
    my_str_puts(str);
    my_str_destroy(str);

Expected output

    Hello Alien World!

### `radar/radar.h`

Lore
Now that the communication protocol is established, the identity of Isabelle's friend is finally revealed: it is the Doom Slayer!
Unfortunately, the Slayer doesn't understand the geography of your peaceful island.
He brought his own UAC-grade radar to locate himself, but its software is incompatible with this dimension's physics.
Isabelle asks for your help to patch his radar so he can navigate and find the "interesting places" she recommended.
In the `radar.h` file, you will find the definition of the `struct point` and the prototypes of the functions you need to implement.
Warning(s)
This is the last time a structure is provided for you.
In the upcoming parts, you will have to define the structs yourself!
Code example(s)

    struct point
    {
        double x;
        double y;
    };

Prototype(s)

    double compute_distance(struct point a, struct point b);
    int is_in_area(struct point center, double radius, struct point point);
    size_t detect_points(struct point center, double range, struct point* interesting_points, size_t nb_points);

### `radar/radar.c`

In this file, you will implement the mathematical tools required to calculate positions and check if entities are within range of each other.
First, you'll have to compute the distance between two points.
Implement the function `compute_distance` to calculate the Euclidean distance between two points, `a` and `b`.
distance=(xb−xa)2+(yb−ya)2 \text{distance} = \sqrt{(x_b - x_a)^2 + (y_b - y_a)^2} distance=(xb​−xa​)2+(yb​−ya​)2
​
Hint(s)
In this file, you can use the `math.h` header
You need to add the `-lm` flag when compiling your code to link the math library.
Prototype(s)

    double compute_distance(struct point a, struct point b);

Code example(s)

    struct point p1 = { 0.0, 0.0 };
    struct point p2 = { 3.0, 4.0 };

    double dist = compute_distance(p1, p2);
    printf("Distance: %.2f\n", dist);

Expected output

    Distance: 5.00

Write the function `is_in_area` that detects if a point is within the area defined by `center` and `radius`.
Note that points located exactly on the border are considered inside.
Prototype(s)

    int is_in_area(struct point center, double radius, struct point point);

Hint(s)
You can use the previous function.
Code example(s)

    struct point center = { 5.0, 5.0 };
    double radius = 3.0;

    struct point inside_point = { 7.0, 7.0 };
    struct point outside_point = { 9.0, 9.0 };

    int inside = is_in_area(center, radius, inside_point);
    int outside = is_in_area(center, radius, outside_point);

    printf("Inside: %d\n", inside);
    printf("Outside: %d\n", outside);

Expected output

    Inside: 1
    Outside: 0

Lore
To finish the implementation of the radar, Isabelle told you she gave him a list of places to visit and their coordinates.
So you add the last feature, detecting all the interesting points in a given area.
This function iterates through the `interesting_points` array of length `nb_points` to find locations within the specified `range` of the `center`.
You must print the matching points according to the following format, and return the number of points found.
`"{x, y}\n"`
Round `x` and `y` to two decimal places.
Prototype(s)

    size_t detect_points(struct point center, double range, struct point *interesting_points, size_t nb_points);

Hint(s)
You can use the previous function.
Code example(s)

    struct point center = { 10.0, 10.0 };
    double range = 5.0;

    struct point points[] = {
        { 11.0, 11.0 },
        { 10.0, 10.0 },
        { 20.0, 20.0 },
        { 14.0, 13.0 }
    };

    size_t size = sizeof(points) / sizeof(struct point);

    size_t found = detect_points(center, range, points, size);
    printf("Total found: %zu\n", found);

Expected output

    {11.00, 11.00}
    {10.00, 10.00}
    {14.00, 13.00}
    Total found: 3

While visiting the island, you talk a bit with doom guy, even though he is not very talkative, he seems to be interested about what you’re saying. You learn that he couldn’t take a fly, so he came by a portal just like the first time. Wait, is it closed ?
You hear a loud scream “THERE ARE DEMONS !!! DEMONS INVADED THE ISLAND !!”

### `reap_and_tear/weapons.h`

Lore
Doom guy wants to fight the demons, but his weapons can't be used on the island since they don't exist.
Let's create them using structs and enums.
In this header, you will define the necessary data structures and function prototypes.
We don't want to bother calculating the exact range every time, so we're going to use an `enum` to approximate the range of weapons.
Code example(s)

    enum distance
    {
        CLOSE,
        NEAR,
        FAR,
    };

Create a struct named `gun` with the following attributes:

- `name`: A string of 50 characters at most (including the null terminator).
- `damage`: An `int` representing how much damage it deals.
- `range`: An `enum distance` representing the effective range.
- `magazine_size`: An `int` representing the maximum capacity.
- `current_magazine`: An `int` representing the current ammo count.

The name should be a fixed-size array.
Prototype(s)

    struct gun *init_gun(char name[50], int damage, enum distance range, int magazine_size);
    void reload(struct gun *gun);
    void destroy_gun(struct gun *gun);

### `reap_and_tear/villager.h`

Lore
The weapons are ready, and you see that Doom Guy has already started fighting and protecting the villagers.
You see Isabelle trying to take a gun to help him, but it looks impossible: the weapons you created aren't adapted to the residents of the island.
You need to do something about it so you can help the Slayer.
In this header, you will define the `struct villager` and the prototypes for their actions.
Warning(s)
Since this file references `struct demon` (which isn't defined yet), you must add a forward declaration at the top of your file.
Code example(s)

    struct demon;

The `struct villager` represents the residents fighting alongside the Slayer.
Attributes:

- `name`: A string (max 50 chars) representing the villager's name.
- `cur_HP`: An `int` for current health points.
- `HP_max`: An `int` for maximum health points.
- `gun`: A pointer to a `struct gun` (can be NULL).
- `gun_mastery`: An `int` representing proficiency with firearms.
- `medicines`: An `int` representing the inventory count (Max 10).
- `distance`: An `enum distance` representing proximity to the demon.

The name should be a fixed-size array.
Prototype(s)

    struct villager *init_villager(char name[50], int HP_max, struct gun *gun, int gun_mastery);
    void pp_villager(struct villager *villager);
    void destroy_villager(struct villager *villager);
    void update_villager_hp(struct villager *villager, int amount);
    void shoot(struct villager *villager, struct demon *demon);
    void heal(struct villager *villager);
    enum distance walk(struct villager *villager, int direction);
    int prepare_medicine(struct villager *villager);

### `reap_and_tear/demon.h`

Lore
The newly created weapons can't affect the demons yet. You need to adapt them, or you'll risk undefined behavior (and potentially destroying the world with a segfault).
Isabelle seems to be craving blood (weird...), and Timmy & Tommy have started classifying the demons slain by the Doom Slayer.
Since names like "Ultra-Nightmare" are too long, they decided to classify them by "Type" rather than danger level.
In this header, you will define the `struct demon`, the classification enum, and the AI prototypes.
Warning(s)
Since this file references `struct villager`, ensure you have the proper forward declarations.
Code example(s)

    struct villager;

Timmy and Tommy's classification system.
Note: Enum values are just numbers. We want this one to start at 1 (not 0) to use it as a multiplier later.
And yes, Tom Nook is the highest level of threat.
Code example(s)

    enum demon_category
    {
        PARASITE = 1,
        THREAT,
        NIGHTMARE,
        CALAMITY,
        TOM_NOOK
    };

Create the `struct demon` with the following attributes:

- `category`: An `enum demon_category` representing the type.
- `name`: A string (max 50 chars).
- `damage`: An `int` for base damage.
- `range`: An `enum distance` for attack range.
- `cur_HP`: An `int` for current health.
- `HP_max`: An `int` for maximum health.

The name should be a fixed-size array.
Prototype(s)

    struct demon *init_demon(enum demon_category category, char name[50], int HP_max, int damage, enum distance range);
    void pp_demon(struct demon *demon);
    void destroy_demon(struct demon *demon);
    void basic_attack(struct demon *demon, struct villager *target);
    void draining_attack(struct demon *demon, struct villager *target);
    void heavy_attack(struct demon *demon, struct villager *target);
    void chase(struct demon *demon, struct villager *villager);
    void update_demon_hp(struct demon *demon, int amount);
    void demon_action(struct demon *demon, struct villager *villager);

### `reap_and_tear/weapons.c`

In this source file, you must implement the logic to forge (allocate), manage, and destroy the weapons.
This function must:

1. Allocate memory for a `struct gun`.
2. Copy the `name` argument into the structure.
3. Initialize `damage`, `range`, and `magazine_size` with the provided arguments.
4. Set `current_magazine` to be equal to `magazine_size` (a new gun is always fully loaded).
5. Return the pointer to the newly created gun.

Hint(s)
You can use the function `strcpy(3)` to copy strings.
Prototype(s)

    struct gun *init_gun(char name[50], int damage, enum distance range, int magazine_size);

Code example(s)

    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    printf("Gun name: %s\nDamage: %d\nRange: %d\nMagazine: %d/%d\n", gun->name,
          gun->damage, gun->range, gun->current_magazine, gun->magazine_size);

Output

    Gun name: BFG
    Damage: 50
    Range: 2
    Magazine: 16/16

This function refills the gun.
You must set the `current_magazine` value to be equal to the `magazine_size`.
If the `gun` pointer is `NULL`, the function does nothing.
Prototype(s)

    void reload(struct gun *gun);

Code example(s)

    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    gun->current_magazine = 2;
    printf("Before reload: %d\n", gun->current_magazine);
    reload(gun);
    printf("After reload: %d\n", gun->current_magazine);

Output

    Before reload: 2
    After reload: 16

Frees the memory allocated for the `gun` structure.
If the `gun` pointer is `NULL`, the function does nothing.
Prototype(s)

    void destroy_gun(struct gun *gun);

### `reap_and_tear/villager.c`

In this source file, you must implement the logic for the villagers' behavior, combat mechanics, and inventory management.
The function `init_villager` allocates and returns a pointer to a `struct villager` initialized with the given attributes.
Default values:

- `medicines` must be set to `10`.
- `distance` must be set to `NEAR`.
- `cur_HP` must be initialized to `HP_max`.

Prototype(s)

    struct villager *init_villager(char name[50], int HP_max, struct gun *gun, int gun_mastery);

Subtracts `amount` from the villager's HP (can be negative for healing).
If HP <= 0, display: `"You died.\n"`
Be careful not to exceed `HP_max`
If the `villager` pointer is `NULL`, the function does nothing.
Prototype(s)

    void update_villager_hp(struct villager *villager, int amount);

Code example(s)

    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 50, gun, 1);
    update_villager_hp(villager, 100);

Output

    You died.

Frees the villager structure and its equipment.
If the `villager` pointer is `NULL`, the function does nothing.
Prototype(s)

    void destroy_villager(struct villager *villager);

### `reap_and_tear/print.c`

In this file, you will implement functions that print all the info of a villager and a demon.
If the `villager` pointer is `NULL`, the function does nothing.
Print all the information of a villager using the following format:
Shell example(s)

    ============================= Villager info =============================
    Name: {name}
    HP: {current_HP}/{HP_max}
    Gun: {Gun_name} | Magazine: {current_magazine}/{magazine_size} | Mastery: {gun_mastery}
    Medicine: {current_medicine}/10
    Distance: {distance}

Information
Don't forget the final `\n`.
This function will not be tested if the villager has no gun equipped.
Hint(s)
For the `distance`, print `Close`, `Near` or `Far` depending on the distance of the villager.
We advise you to make an auxiliary function that returns these values.
Prototype(s)

    void pp_villager(struct villager* villager);

Code example(s)

    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager = init_villager(name, 50, gun, 1);
    pp_villager(villager);
    destroy_villager(villager);

Output

    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near

### `reap_and_tear/demon.c`

In this file, you will implement the logic for the demons.
The `init_demon` function returns a pointer to a `struct demon` with the given attribute.
You'll have to multiply the `HP_max` and `damage` of the demon by their `category` (that's why we wanted it to start at 1 and not 0).
Example: A "THREAT" (value 2) with base HP 100 will actually have 200 HP.
`cur_HP` must be initialized to `HP_max`.
Prototype(s)

    struct demon *init_demon(enum demon_category category, char name[50], int HP_max, int damage, enum distance range);

Subtracts `amount` from the demon's HP.
If HP <= 0, display: `"You killed the demon {demon_name} !!\n"`
If the `demon` pointer is `NULL`, the function does nothing.
Prototype(s)

    void update_demon_hp(struct demon *demon, int amount);

Code example(s)

    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
    update_demon_hp(demon, 200);

Output

    You killed the demon Cyberdemon !!

Frees the memory allocated for the `demon` structure.
If the `demon` pointer is `NULL`, the function does nothing.
Prototype(s)

    void destroy_demon(struct demon *demon);

### `reap_and_tear/print.c`

If the `demon` pointer is `NULL`, the function does nothing.
Print all the information of a demon using the following format:
Shell example(s)

    ============================= Demon info =============================
    Name: {name} | Category: {category}
    Base damage: {damage} | Range: {range}
    HP: {current_HP}/{HP_max}

Information
Don't forget the final `\n`.
Hint(s)
For the `category`, print `Parasite`, `Threat`, `Nightmare`, `Calamity` or `Tom Nook` depending on the category of the demon.
For the `range`, print `Close`, `Near` or `Far` depending on the range of the demon.
Prototype(s)

    void pp_demon(struct demon* demon);

Code example(s)

    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
    pp_demon(demon);

Output

    ============================= Demon info =============================
    Name: Cyberdemon | Category: Nightmare
    Base damage: 15 | Range: Close
    HP: 120/120

### `reap_and_tear/villager.c`

First of all, you need to use your weapons, the `shoot` function fires a shot with the gun that the `villager` is equipped with and lower the `current_magazine` of the gun by one.
If the player didn't equip a gun (if the `gun` attribute is `NULL`) display the message `"Equip a gun before trying to use one.\n"` and return.
If the magazine is empty, display the message `"Empty gun : You gotta reload.\n"` and return.
Else you have to lower the `current_magazine` by `1` and then :

- If the demon is not in range, just display the message `"No demon in range.\n"` (use the villager's `distance` attribute and the gun's `range` attribute )
- If the demon is in range, lower his HP by the `damage` of the weapon + the `gun_mastery`, the minimum damage you can deal is `0`. Then display the message `"BAM! {name_of_the_demon} lost {number_of_damage} HP.\n"`

If the `villager` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void shoot(struct villager *villager, struct demon *demon);

Code example(s)

    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
    // // Shoot
    shoot(villager, demon);
    pp_villager(villager);
    pp_demon(demon);
    destroy_demon(demon);
    destroy_villager(villager);

Output

    BAM! Cyberdemon lost 51 HP.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 15/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near
    ============================= Demon info =============================
    Name: Cyberdemon | Category: Nightmare
    Base damage: 15 | Range: Close
    HP: 69/120

Uses one medicine to recover HP.

- If no medicine left, display: `"No medicine left, maybe prepare some ?\n"`
- Else:
  - Decrement medicine count by `1`.
  - Heal 25% of `HP_max` (rounded down). Ensure `cur_HP` does not exceed `HP_max`.
  - Display: `"Nice, you healed {amount_healed} HP.\n"`

If the `villager` pointer is `NULL`, the function does nothing.
Prototype(s)

    void heal(struct villager *villager);

Code example(s)

    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Heal
    villager->cur_HP -= 40;
    pp_villager(villager);
    putchar('\n');
    heal(villager);
    pp_villager(villager);
    destroy_villager(villager);

Output

    ============================= Villager info =============================
    Name: Isabelle
    HP: 10/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near

    Nice, you healed 12 HP.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 22/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 9/10
    Distance: Near

Moves the villager based on the `direction` integer.

- Positive (>= 0): Move closer (FAR → NEAR → CLOSE). If already CLOSE, display `"Too close.\n"`
- Negative (< 0): Move further (CLOSE → NEAR → FAR). If already FAR, display `"I can't run away.\n"`
- If movement was successful, display `"You decided to move.\n"`. A movement is considered successful if the villager actually moved.

Returns the new `distance` (enum).
If the `villager` pointer is `NULL`, the function does nothing and return `NEAR`.
Prototype(s)

    enum distance walk(struct villager *villager, int direction);

Code example(s)

    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Walk
    pp_villager(villager);
    putchar('\n');
    walk(villager, 1);
    pp_villager(villager);
    destroy_villager(villager);

Output

    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near

    You decided to move.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Close

Crafts one medicine.

- Add 1 to the villager's medicine count (Cap at 10).
- Display: `"Preparation ready !\n"`

Returns the new number of medicines owned.
If the `villager` pointer is `NULL`, the function does nothing and return `0`.
Prototype(s)

    int prepare_medicine(struct villager *villager);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Prepare Medicine
    villager->medicines -= 5;
    pp_villager(villager);
    prepare_medicine(villager);
    pp_villager(villager);
    destroy_villager(villager);

Output

    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 5/10
    Distance: Near
    Preparation ready !
    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 6/10
    Distance: Near

### `reap_and_tear/demon.c`

The demon attempts to close the gap to attack the villager.
You must update the `distance` attribute of the `villager`:

- If the villager is at `FAR`, change it to `NEAR`.
- If the villager is at `NEAR`, change it to `CLOSE`.
- If they are already at `CLOSE`, the distance does not change.

Then, you must display the message: `"The demon {demon_name} is chasing you.\n"`
If the `villager` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void chase(struct demon *demon, struct villager *villager);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);

    // Chase
    pp_villager(villager);
    chase(demon, villager);
    pp_villager(villager);
    destroy_villager(villager);
    destroy_demon(demon);

Output

    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near
    The demon Cyberdemon is chasing you.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 50/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Close

This is the attack the demons use most of the time, it allows the demon to deal a number of damage equal to their `damage` attribute to the target if he is in range.
You'll have to decrease the HP of the target by the amount of damage they took.
Display `"RAAAAAGH! {name_of_the_demon} attacks you to deal {number_of_damage} damage.\n"`
If the `target` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void basic_attack(struct demon *demon, struct villager *target);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);

    // Basic attack
    basic_attack(demon, villager);
    pp_villager(villager);
    destroy_villager(villager);
    destroy_demon(demon);

Output

    RAAAAAGH! Cyberdemon attacks you to deal 15 damage.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 35/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near

This is the attack that demons use when they have low health. It is weaker than the basic attack but it allows them to heal some HP.

- They deal half the damage they usually deal (minimum 1)
- They heal half the damage they dealt (add half the damage they dealt to their HP)

The range is the same as the basic attack.
Display `"SLURRRRP! {name_of_the_demon} attacks you to deal {number_of_damage} damage and regenerates {number_of_regenerated_hp} HP.\n"`
If the `target` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void draining_attack(struct demon *demon, struct villager *target);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";

    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);

    // Draining attack
    demon->cur_HP -= 10;
    draining_attack(demon, villager);
    pp_villager(villager);
    pp_demon(demon);
    destroy_demon(demon);
    destroy_villager(villager);

Output

    SLURRRRP! Cyberdemon attacks you to deal 7 damage and regenerates 3 HP.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 43/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near
    ============================= Demon info =============================
    Name: Cyberdemon | Category: Nightmare
    Base damage: 15 | Range: Far
    HP: 113/120

A risky but powerful attack.
Deals `double` damage to the target, but the demon takes some recoil damage (`10`% of its own max HP).
Display `"BAM! {demon name} attacks you with all his strength to deal {nb of damage} damage.\n"`
If the `target` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void heavy_attack(struct demon *demon, struct villager *target);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";

    struct gun *gun = init_gun(gun_name, 50, FAR, 16);

    struct villager *villager =
        init_villager(name, 50, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, FAR);

    // Heavy attack
    heavy_attack(demon, villager);
    pp_villager(villager);
    pp_demon(demon);
    destroy_demon(demon);
    destroy_villager(villager);

Output

    BAM! Cyberdemon attacks you with all his strength to deal 30 damage.
    ============================= Villager info =============================
    Name: Isabelle
    HP: 20/50
    Gun: BFG | Magazine: 16/16 | Mastery: 1
    Medicine: 10/10
    Distance: Near
    ============================= Demon info =============================
    Name: Cyberdemon | Category: Nightmare
    Base damage: 15 | Range: Far
    HP: 108/120

This function determines how the demon attacks.

- If distance > range => chase
- Else if demon.HP > 75% => heavy attack
- Else if demon.HP < 25% => draining attack
- Else basic attack

If the `villager` or `demon` pointer are `NULL`, the function does nothing.
Prototype(s)

    void demon_action(struct demon *demon, struct villager *villager);

Code example(s)

    // Init Villager
    char name[50] = "Isabelle";
    char gun_name[50] = "BFG";
    struct gun *gun = init_gun(gun_name, 50, FAR, 16);
    struct villager *villager =
        init_villager(name, 500, gun, 1);

    // Init demon
    char demon_name[50] = "Cyberdemon";
    struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);

    // Demon action
    demon_action(demon, villager); // Distance = Near but its range is close
    demon_action(demon, villager); // In range and high HP
    demon->cur_HP = demon->HP_max / 2;
    demon_action(demon, villager); // In range and mid HP
    demon->cur_HP = 1;
    demon_action(demon, villager); // In range and low HP

    destroy_villager(villager);
    destroy_demon(demon);

Output

    The demon Cyberdemon is chasing you.
    BAM! Cyberdemon attacks you with all his strength to deal 30 damage.
    RAAAAAGH! Cyberdemon attack you to deal 15 damage.
    SLURRRRP! Cyberdemon attack you to deal 7 damage and regenerates 3 HP.

Now the real fight can start, you managed to create weapons to protect the island, but now it's time to use them !
To control your character, you'll have to type specific commands :

- `s` to shoot with you gun.
- `r` to reload your gun.
- `h` to heal yourself.
- `p` to prepare medicine.
- `w+` to walk towards the demon.
- `w-` to walk away from the demon.

Any other action won't work.
Copy this in a file `main.c` and run your program.
Warning(s)
Be careful, when compiling make sure that you don't have any other `main` function, otherwise you won't be able to compile
Hint(s)
For more fun, feel free to modify the main function however you like.
Code example(s)

    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #include "demon.h"
    #include "villager.h"
    #include "weapons.h"

    #define PURPLE(string) "\x1b[35m" string "\x1b[0m"

    #define MAX_BUFFER 1024

    void villager_action(struct villager *villager, struct demon *demon, char *command)
    {
        if (!strcmp(command, "s"))
        {
            shoot(villager, demon);
        }
        else if (!strcmp(command, "r"))
        {
            printf("You reload your gun");
            reload(villager->gun);
        }
        else if (!strcmp(command, "h"))
        {
            heal(villager);
        }
        else if (!strcmp(command, "w+"))
        {
            walk(villager, 1);
        }
        else if (!strcmp(command, "w-"))
        {
            walk(villager, -1);
        }
        else if (!strcmp(command, "p"))
        {
            prepare_medicine(villager);
        }
        else
            printf(PURPLE("No such action\n"));
    }

    static void end_fight(struct villager *villager, struct demon *demon)
    {
        if (villager->cur_HP <= 0 || demon->cur_HP <= 0)
        {
            pp_villager(villager);
            pp_demon(demon);
            destroy_villager(villager);
            destroy_demon(demon);
            exit(0);
        }
    }

    int main()
    {
        printf("\033[2J\033[1;1H");
        // Init gun and villager
        char name[50] = "Isabelle";
        char gun_name[50] = "BFG";
        struct gun *gun = init_gun(gun_name, 50, FAR, 16);
        struct villager *villager =
            init_villager(name, 50, gun, 1);

        // Init demon
        char demon_name[50] = "Cyberdemon";
        struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
        pp_villager(villager);
        pp_demon(demon);

        char input[MAX_BUFFER];

        while (fgets(input, MAX_BUFFER, stdin) != NULL)
        {
            printf("\033[2J\033[1;1H");
            int i = 0;
            while (input[i] != '\0')
            {
                if (input[i] == '\n')
                {
                    input[i] = '\0';
                    break;
                }
                i++;
            }

            printf("\x1b[34m");
            villager_action(villager, demon, input);
            printf("\x1b[0m");

            end_fight(villager, demon);

            printf("\x1b[31m");
            demon_action(demon, villager);
            printf("\x1b[0m");

            end_fight(villager, demon);

            pp_villager(villager);
            pp_demon(demon);

            printf("> ");
        }

        destroy_demon(demon);
        destroy_villager(villager);
        return 0;
    }

In this part, we introduce `unions`. Since this concept wasn't covered in class, we will explore it here.
A `union` is similar to a `struct`, but with a key difference: all its members share the same memory space. This means only one member can be stored (or "active") at a time.
Unions are primarily used for memory optimization or when you need a variable that can hold different data types at different times (a concept known as polymorphism in C).
They are often paired with `enums` (a pattern called a Tagged Union). The `enum` acts as a "tag" to indicate which member of the `union` is currently set. Using this tag, you can safely determine which attribute to access.

### `animals/animals.h`

Here are the structs, union and enums that we'll use, just copy them, we'll explain everything you need to know later on:
Code example(s)

    enum animal_type
    {
        INSECT,
        FISH,
    };

Code example(s)

    struct fish
    {
        char* species;
        int swimming_speed;
        size_t size;
        int lives_in_fresh_water;
    };

Code example(s)

    struct insect
    {
        char* species;
        size_t size;
        int can_fly;
        int can_swim;
    };

Code example(s)

    union animals
    {
        struct insect* insect;
        struct fish* fish;
    };

Code example(s)

    struct animal
    {
        enum animal_type type;
        union animals animal;
        char* color;
    };

Prototype(s)

    struct fish* fish_init(const char* species, int speed, size_t size, int fresh_water);
    struct animal* animal_from_fish(const char* color, struct fish* fish);
    void free_fish(struct fish* fish);
    struct insect *insect_init(const char *species, size_t size, int can_fly, int can_swim);
    struct animal* animal_from_insect(const char* color, struct insect* insect);
    void free_insect(struct insect* insect);
    void free_animal(struct animal* animal);

The `struct animal` uses a Union to store data. Unlike a struct where every field exists in memory at once, a union uses a single shared memory space for all its fields.
This means `struct animal` can hold a `struct fish*` OR a `struct insect*`, but never both at the same time.
To handle this safely, we use a Tagged Union pattern:

1. The Tag (Enum): You must set the `type` attribute of the animal to the correct enum value (e.g., `FISH`). This tells the program "The data currently stored in the union is a fish".
2. The Union (Data): You access the union field (e.g., `value` or `data`) and assign your pointer to the specific member: `animal->data.fish = fish;`.

For example, you can access the fish in the union with `my_animal->animal.fish`.

### `animals/fish.c`

In this file, you will manage the creation of specific animals (Fish) and their encapsulation into the generic `struct animal` using unions.
This function allocates and initializes a `struct fish` with the given argument.
You must copy the `species` string.
Hint(s)
You can use the function `strdup(3)` to malloc and copy strings.
Prototype(s)

    struct fish *fish_init(const char *species, int speed, size_t size, int fresh_water);

Code example(s)

    struct fish *f = fish_init("Salmon", 10, 5, 1);
    printf("Fish species: %s\n", f->species);
    printf("Swimming speed: %d\n", f->swimming_speed);
    printf("Size: %zu\n", f->size);
    printf("Lives in fresh water: %d\n", f->lives_in_fresh_water);

Example Output

    Fish species: Salmon
    Swimming speed: 10
    Size: 5
    Lives in fresh water: 1

This function creates a generic `struct animal` from a specific `struct fish`.
You must copy the `color` string.
If one of the arguments is `NULL`, do nothing and return `NULL`.
Prototype(s)

    struct animal *animal_from_fish(const char *color, struct fish *fish);

Code example(s)

    struct fish *f = fish_init("Trout", 8, 4, 1);
    struct animal *a = animal_from_fish("Blue", f);
    printf("Animal type: %d\n", a->type);
    printf("Animal color: %s\n", a->color);
    printf("Fish species from animal: %s\n", a->animal.fish->species);

Example Output

    Animal type: 1
    Animal color: Blue
    Fish species from animal: Trout

Frees the memory allocated for the `struct fish`.
If the `fish` pointer is `NULL`, the function does nothing.
Prototype(s)

    void free_fish(struct fish *fish);

Code example(s)

    struct fish *f = fish_init("Carp", 6, 3, 0);
    free_fish(f);

Example Output

    (No output, just ensure no memory leaks occur with -fsanitize=address)

### `animals/insect.c`

In this file, you will manage the creation of insects and their encapsulation into the generic `struct animal`.
Allocates and initializes a `struct insect`.
You must copy the `species` string.
Prototype(s)

    struct insect *insect_init(const char *species, size_t size, int can_fly, int can_swim);

Code example(s)

    struct insect *i = insect_init("Dragonfly", 2, 1, 0);
    printf("Insect species: %s\n", i->species);
    printf("Size: %zu\n", i->size);
    printf("Can fly: %d\n", i->can_fly);
    printf("Can swim: %d\n", i->can_swim);

Example Output

    Insect species: Dragonfly
    Size: 2
    Can fly: 1
    Can swim: 0

Creates a generic `struct animal` from a specific `struct insect`.
You must copy the `color` string.
If one of the arguments is `NULL`, do nothing and return `NULL`.
Prototype(s)

    struct animal *animal_from_insect(const char *color, struct insect *insect);

Code example(s)

    struct insect *i = insect_init("Butterfly", 1, 1, 0);
    struct animal *a = animal_from_insect("Yellow", i);
    printf("Animal type: %d\n", a->type);
    printf("Animal color: %s\n", a->color);
    printf("Insect species from animal: %s\n", a->animal.insect->species);

Example Output

    Animal type: 0
    Animal color: Yellow
    Insect species from animal: Butterfly

Frees the memory allocated for the `struct insect`.
If the `insect` pointer is `NULL`, the function does nothing.
Prototype(s)

    void free_insect(struct insect *insect);

Code example(s)

    struct insect *i = insect_init("Beetle", 3, 0, 1);
    free_insect(i);

Example Output

    (No output, just ensure no memory leaks occur with -fsanitize=address)

### `animals/vector.h`

Lore
You are catching a lot of fish and insects, but your pockets have a limit.
You need a storage system that can grow as your collection expands.
Since standard arrays in C have a fixed size, we need something smarter: A Vector.
In this header, you will define the `struct vector` and the interface to manipulate it.
Define the structure that manages your dynamic list of animals.
Code example(s)

    struct vector
    {
        struct animal **animal;
        size_t size;
        size_t capacity;
    };

Prototype(s)

    struct vector *vector_init(size_t n);
    struct vector *vector_resize(struct vector *v, size_t new_capacity);
    struct vector *vector_append(struct vector *v, struct animal *animal);
    void vector_destroy(struct vector *v);

What is a Vector?
In C, standard arrays have a fixed size defined at compilation or creation. If you define `int tab[10];`, you cannot store an 11th element without causing a buffer overflow.
A Vector (or Dynamic Array) solves this by managing memory dynamically. It behaves like a normal array but can grow automatically. It relies on two key properties:

- Size: The number of elements actually stored and used in the array (what the user sees).
- Capacity: The total amount of memory currently allocated (the hidden "buffer").

Calling `realloc` is computationally expensive (it may need to copy the whole array to a new memory location).
To avoid doing this every time we add an item, we allocate extra space. When the `size` reaches the `capacity` (the vector is full), we don't just add +1 slot. Instead, we typically double the capacity. This minimizes the number of times we need to ask the system for more memory.

### `animals/vector.c`

In this file, you will implement the logic for the dynamic array (Vector) that will hold your collection of animals.
Initializes an empty vector with an initial `capacity` of `n`.

- Allocate memory for the `struct vector`.
- Allocate memory for the internal array of pointers.
- Set `size` to 0.
- Set `capacity` to `n`.

Prototype(s)

    struct vector *vector_init(size_t n);

Code example(s)

    struct vector *v = vector_init(5);
    printf("Initial size: %zu\n", v->size);
    printf("Initial capacity: %zu\n", v->capacity);

Example Output

    Initial size: 0
    Initial capacity: 5

Changes the `capacity` of the vector to `new_capacity`.

- Use `realloc` to resize the internal `animal` array to the new capacity.
- Update the `capacity` attribute of the structure.

Returns the pointer to the vector.
If the `vector` pointer is `NULL`, the function does nothing and return `NULL`.
Prototype(s)

    struct vector *vector_resize(struct vector *v, size_t new_capacity);

Code example(s)

    struct vector *v = vector_init(2);
    v = vector_resize(v, 4);
    printf("Resized capacity: %zu\n", v->capacity);

Example Output

    Resized capacity: 4

Adds the given `animal` to the end of the list and updates the `size`.
Growth Logic:

- Check if the vector is full.
- If it is full, call `vector_resize` to double the current capacity.
- Add the `animal` pointer at the correct index.
- Increment the `size`.

If one of the arguments is `NULL`, the function does nothing and returns `NULL`.
Prototype(s)

    struct vector *vector_append(struct vector *v, struct animal *animal);

Code example(s)

    struct vector *v = vector_init(2);

    struct fish *f1 = fish_init("Salmon", 10, 5, 1);
    struct animal *a1 = animal_from_fish("Blue", f1);
    v = vector_append(v, a1);

    struct fish *f2 = fish_init("Trout", 8, 4, 1);
    struct animal *a2 = animal_from_fish("Green", f2);
    v = vector_append(v, a2);

    struct fish *f3 = fish_init("Carp", 6, 3, 0);
    struct animal *a3 = animal_from_fish("Red", f3);
    v = vector_append(v, a3);

    printf("Vector size after appends: %zu\n", v->size);
    printf("Vector capacity after appends: %zu\n", v->capacity);

Example Output

    Vector size after appends: 3
    Vector capacity after appends: 4

Frees the memory allocated for a generic `struct animal`.
Since the animal uses a Union, you cannot simply free the content. You must check its `type` attribute (the Tag) to know which specific free function to call:

- If the type is `FISH`: Call `free_fish` on the specific union member.
- If the type is `INSECT`: Call `free_insect` on the specific union member.

Once the specific content is freed, do not forget to free the `color` string, and finally the `animal` structure itself.
If the `animal` pointer is `NULL`, the function does nothing.
Prototype(s)

    void free_animal(struct animal *animal);

Code example(s)

    struct fish *f = fish_init("Salmon", 10, 5, 1);
    struct animal *a = animal_from_fish("Blue", f);
    free_animal(a);

Example Output

    (No output, just ensure no memory leaks occur with -fsanitize=address)

Frees the memory allocated for the vector container.

- First, free the internal array of pointers.
- Then, free the vector structure itself.

If the `vector` pointer is `NULL`, the function does nothing.
Prototype(s)

    void vector_destroy(struct vector *v);

Code example(s)

    struct vector *v = vector_init(5);

    struct fish *f = fish_init("Trout", 8, 4, 1);
    struct animal *a = animal_from_fish("Green", f);
    v = vector_append(v, a);

    vector_destroy(v);

Example Output

    (No output, just ensure no memory leaks occur with -fsanitize=address)

Lore
The battle is over (for now). The demons have been pushed back, but they left a trail of destruction in their wake.
You find Blathers in a state of total panic: the museum has been ransacked!
Millions of years of history are scattered on the floor. Skulls, tails, and wings are mixed up in a giant pile of ancient bones.
To everyone's surprise, the Doom Slayer starts picking up a T-Rex skull with gentle care. It seems he has a soft spot for big, dead predators.
It's time to help them reassemble the collection before Blathers faints!
In this final part, you will manipulate arrays of structures and implement algorithms to sort and reassemble matching pieces together.

### `museum_restoration/fossils.h`

Lore
After the attack of the demons, Blathers' museum got all messed up.
But since it's the best way to discover everything about the island, you and the Doom Slayer offered to help.
In this header, you will define the structures and enums necessary to categorize and reconstruct the fossils scattered around the museum.
Here is the enum that represents the different body parts of a fossil.
Code example(s)

    enum body_part
    {
        SKULL,
        TORSO,
        TAIL,
        WINGS,
        LEGS,
        COMPLETE,
    };

Create the structure `struct fossil` with the following attributes:

- `species`: `char*` representing the name of the species.
- `body_part`: `enum body_part` indicating which part this is (or COMPLETE).
- `age`: `size_t` representing the fossil's age in thousands of years (e.g., 10 = 10,000 years).
- `has_wings`: `char` acting as a boolean (1 if the species should have wings, 0 otherwise).

Prototype(s)

    struct fossil *init_fossil(char *species, enum body_part body_part, size_t age, char has_wings);
    struct fossil *assemble_wingless(struct fossil *fossils[4]);
    struct fossil *assemble_with_wings(struct fossil *fossils[5]);
    struct fossil **assemble_all_fossils(struct fossil **fossils, size_t nb_fossils);

### `museum_restoration/fossils.c`

In this file, you will implement the logic to initialize fossils and the algorithms to reassemble them into complete skeletons.
Allocates and returns a pointer to a `struct fossil` initialized with the given attributes.
You must dynamically allocate memory for the `species` string and copy the provided string into it.
Prototype(s)

    struct fossil *init_fossil(char *species, enum body_part body_part, size_t age, char has_wings);

Tries to assemble a fossil that does not have wings.
Input: An array of 4 pointers to `struct fossil`.
Logic:

1. Check that all 4 fossils have `has_wings == 0`. If not, return `NULL`.
2. Check that they all share the same `species` and `age`.
3. Check that you have exactly one of each required part: `SKULL`, `TORSO`, `TAIL`, `LEGS`.

Output:

- If successful: Return a new `COMPLETE` fossil (same age/species). You MUST free the 4 input parts and set their pointers to `NULL` in the array.
- If invalid: Return `NULL` (do not free anything).

If the `fossils` array is `NULL`, the function does nothing and returns `NULL`.
Prototype(s)

    struct fossil *assemble_wingless(struct fossil *fossils[4]);

Tries to assemble a fossil that has wings.
Input: An array of 5 pointers to `struct fossil`.
Logic:

1. Check that all 5 fossils have `has_wings != 0`. If not, return `NULL`.
2. Check that they all share the same `species` and `age`.
3. Check that you have exactly one of each required part: `SKULL`, `TORSO`, `TAIL`, `LEGS`, `WINGS`.

Output:

- If successful: Return a new `COMPLETE` fossil. You MUST free the 5 input parts and set their pointers to `NULL`.
- If invalid: Return `NULL`.

If the `fossils` array is `NULL`, the function does nothing and returns `NULL`.
Prototype(s)

    struct fossil *assemble_with_wings(struct fossil *fossils[5]);

Takes a large list of scattered fossils and assembles as many as possible.
Input: A pointer to an array of fossil pointers (`fossils`) and its size (`nb_fossils`).
Behavior:

- Iterate through the list to find matching groups (same species/age/wing_status).
- If a valid group is found (4 parts for wingless, 5 for winged), call the appropriate assemble function.
- Store the newly created `COMPLETE` fossils in a new array.

Return: A dynamically allocated `NULL`-terminated array containing pointers to all the completed fossils.
If the `fossils` pointer is `NULL`, the function does nothing and returns `NULL`.
Warning(s)
If a fossil is already complete, it should also be added the list
Prototype(s)

    struct fossil **assemble_all_fossils(struct fossil **fossils, size_t nb_fossils);

- https://www.w3schools.com/c/c_unions.php
- https://www.w3schools.com/c/c_structs.php
- https://www.w3schools.com/c/c_enums.php
- https://en.wikipedia.org/wiki/Tagged_union

[ `1.0.3` ] 2025-02-13 10:42:00
Fundamentals

- `Fundamentals/radar/radar.c` > `detect_points` : specified precision for print output.
- `Fundamentals/reap_and_tear/demon.c` > `heavy_attack` : fix example output.
- `Fundamentals/reap_and_tear/villager.c` > `heal` : fix example output.
- `Fundamentals/reap_and_tear/villager.c` > `walk` : fix example output.

[ `1.0.2` ] 2025-02-11 10:42:00
Proficiencies

- `Proficiencies/animals/vector.c` > `vector_append` : add precision for NULL input.
- `Proficiencies/animals/vector.c` > `vector_append` : add precision for NULL input.
- `Proficiencies/animals/vector.c` > `vector_destroy` : add precision for NULL input.
- `Proficiencies/museum_restoration/fossils.c` > `assemble_all_fossils` : add precision for NULL input.
- `Proficiencies/museum_restoration/fossils.c` > `assemble_wingless` : add precision for NULL input.
- `Proficiencies/museum_restoration/fossils.c` > `assemble_with_wings` : add precision for NULL input.
- `Proficiencies/museum_restoration/fossils.c` > `assemble_with_wings` : fix typo.

[ `1.0.1` ] 2025-02-10 10:42:00
Fundamentals

- `Fundamentals/my_strings/my_strings.c` > `my_string_n_cat` : fix example.

##### This page and all subpages are for internal use at EPITA only.

The use of this document must abide by the following rules:

- You are seeing it from the EPITA’ Gitlab pages.
- This page and all subpages are strictly personal and must not be passed onto someone else.
- Non-compliance with these rules can lead to severe sanctions.

##### Copyright © 2026-2027 - EPITA