diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..888e1f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.a +*.lib +*.o +*.obj +*.out + +.idea/ +*~ +*.DotSettings.user + diff --git a/Holiday Trip.html b/Holiday Trip.html new file mode 100644 index 0000000..5466265 --- /dev/null +++ b/Holiday Trip.html @@ -0,0 +1,3436 @@ + + +
1.0.0 2026-02-09 10:42 2026-02-16 10:42 submit-* (limit: 3 per week) archi-* (limit: 2 per hour) 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
+firstname.lastname with your login. .gitignore file is mandatory. Tests folder. .gitignore file:*.a
+*.lib
+*.o
+*.obj
+*.out
+
+.idea/
+*~
+*.DotSettings.user
+<stddef.h>, <stdlib.h>, <stdio.h> and <string.h>.tar -xvf assets.tar.gz.structs to group variables and enums to represent states or constants.my_strings/my_strings.h \0 character.string and declares the set of functions (prototypes) you need to implement to make it work.char *data: A pointer to the character array (the actual string content).size_t size: The number of characters in the string.struct string
+{
+ char *data;
+ size_t size;
+};
+ 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 malloc(3) and returns a pointer to it.size is zero or s is NULL, the data field is initialized to NULL and the size field to 0.data field with size bytes from s.my_strings.h header to use the struct string.s to data (shallow copy). The structure must own its own memory. Modifying the original string s afterwards should not affect your structure.struct string *my_str_init(const char* s, size_t size);
+ struct string *str = my_str_init("Hello World!", 12);
+printf("data: %.*s\n", (int)str->size, str->data);
+ data: Hello World!
+ sizeof(struct string).str is NULL, the function does nothing.void my_str_destroy(struct string *str);
+ struct string *str = my_str_init("Hello World!", 12);
+my_str_destroy(str);
+ (No output, just ensure there are no memory leaks with -fsanitize=address)
+ string structure to the standard output, followed by a newline.data field is NULL or the size is 0, it should simply print a newline.str pointer is NULL, the function does nothing.putchar(3) function.void my_str_puts(struct string *str);
+ struct string *str = my_str_init("Hello Alien World!", 18);
+my_str_puts(str);
+my_str_destroy(str);
+ Hello Alien World!
+ str2_len characters from str2 to the string structure.size field accordingly.string structure containing the concatenation.str1 is NULL, a new string structure must be initialized.str2 is NULL or the size is 0, no operation is performed.realloc(3) to resize the allocated memory.struct string *my_str_n_cat(struct string *str1, const char *str2, size_t str2_len);
+ struct string *str = my_str_init("Hello ", 6);
+str = my_str_n_cat(str, "Alien World!", 13);
+my_str_puts(str);
+my_str_destroy(str);
+ Hello Alien World!
+ radar/radar.h radar.h file, you will find the definition of the struct point and the prototypes of the functions you need to implement.struct point
+{
+ double x;
+ double y;
+};
+ 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 compute_distance to calculate the Euclidean distance between two points, a and b.math.h header-lm flag when compiling your code to link the math library.double compute_distance(struct point a, struct point b);
+ 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);
+ Distance: 5.00
+ is_in_area that detects if a point is within the area defined by center and radius.int is_in_area(struct point center, double radius, struct point point);
+ 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);
+ Inside: 1
+Outside: 0
+ interesting_points array of length nb_points to find locations within the specified range of the center."{x, y}\n"size_t detect_points(struct point center, double range, struct point *interesting_points, size_t nb_points);
+ 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);
+ {11.00, 11.00}
+{10.00, 10.00}
+{14.00, 13.00}
+Total found: 3
+ reap_and_tear/weapons.h enum to approximate the range of weapons.enum distance
+{
+ CLOSE,
+ NEAR,
+ FAR,
+};
+ 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.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 struct villager and the prototypes for their actions.struct demon (which isn't defined yet), you must add a forward declaration at the top of your file.struct demon;
+ struct villager represents the residents fighting alongside the Slayer.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.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 struct demon, the classification enum, and the AI prototypes.struct villager, ensure you have the proper forward declarations.struct villager;
+ enum demon_category
+{
+ PARASITE = 1,
+ THREAT,
+ NIGHTMARE,
+ CALAMITY,
+ TOM_NOOK
+};
+ 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.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 struct gun.name argument into the structure.damage, range, and magazine_size with the provided arguments.current_magazine to be equal to magazine_size (a new gun is always fully loaded).strcpy(3) to copy strings.struct gun *init_gun(char name[50], int damage, enum distance range, int magazine_size);
+ 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);
+ Gun name: BFG
+Damage: 50
+Range: 2
+Magazine: 16/16
+ current_magazine value to be equal to the magazine_size.gun pointer is NULL, the function does nothing.void reload(struct gun *gun);
+ 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);
+ Before reload: 2
+After reload: 16
+ gun structure.gun pointer is NULL, the function does nothing.void destroy_gun(struct gun *gun);
+ reap_and_tear/villager.c init_villager allocates and returns a pointer to a struct villager initialized with the given attributes.medicines must be set to 10.distance must be set to NEAR.cur_HP must be initialized to HP_max.struct villager *init_villager(char name[50], int HP_max, struct gun *gun, int gun_mastery);
+ amount from the villager's HP (can be negative for healing)."You died.\n"HP_maxvillager pointer is NULL, the function does nothing.void update_villager_hp(struct villager *villager, int amount);
+ 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);
+ You died.
+ villager pointer is NULL, the function does nothing.void destroy_villager(struct villager *villager);
+ reap_and_tear/print.c villager pointer is NULL, the function does nothing.============================= 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}
+ \n.distance, print Close, Near or Far depending on the distance of the villager.void pp_villager(struct villager* 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);
+pp_villager(villager);
+destroy_villager(villager);
+ ============================= Villager info =============================
+Name: Isabelle
+HP: 50/50
+Gun: BFG | Magazine: 16/16 | Mastery: 1
+Medicine: 10/10
+Distance: Near
+ reap_and_tear/demon.c init_demon function returns a pointer to a struct demon with the given attribute.HP_max and damage of the demon by their category (that's why we wanted it to start at 1 and not 0).cur_HP must be initialized to HP_max.struct demon *init_demon(enum demon_category category, char name[50], int HP_max, int damage, enum distance range);
+ amount from the demon's HP."You killed the demon {demon_name} !!\n"demon pointer is NULL, the function does nothing.void update_demon_hp(struct demon *demon, int amount);
+ char demon_name[50] = "Cyberdemon";
+struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
+update_demon_hp(demon, 200);
+ You killed the demon Cyberdemon !!
+ demon structure.demon pointer is NULL, the function does nothing.void destroy_demon(struct demon *demon);
+ reap_and_tear/print.c demon pointer is NULL, the function does nothing.============================= Demon info =============================
+Name: {name} | Category: {category}
+Base damage: {damage} | Range: {range}
+HP: {current_HP}/{HP_max}
+ \n.category, print Parasite, Threat, Nightmare, Calamity or Tom Nook depending on the category of the demon.range, print Close, Near or Far depending on the range of the demon.void pp_demon(struct demon* demon);
+ char demon_name[50] = "Cyberdemon";
+struct demon *demon = init_demon(NIGHTMARE, demon_name, 40, 5, CLOSE);
+pp_demon(demon);
+ ============================= Demon info =============================
+Name: Cyberdemon | Category: Nightmare
+Base damage: 15 | Range: Close
+HP: 120/120
+ reap_and_tear/villager.c shoot function fires a shot with the gun that the villager is equipped with and lower the current_magazine of the gun by one.gun attribute is NULL) display the message "Equip a gun before trying to use one.\n" and return."Empty gun : You gotta reload.\n" and return.current_magazine by 1 and then :"No demon in range.\n" (use the villager's distance attribute and the gun's range attribute )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"villager or demon pointer are NULL, the function does nothing.void shoot(struct villager *villager, struct demon *demon);
+ 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);
+ 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
+ "No medicine left, maybe prepare some ?\n"1.HP_max (rounded down). Ensure cur_HP does not exceed HP_max."Nice, you healed {amount_healed} HP.\n"villager pointer is NULL, the function does nothing.void heal(struct villager *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);
+
+// Heal
+villager->cur_HP -= 40;
+pp_villager(villager);
+putchar('\n');
+heal(villager);
+pp_villager(villager);
+destroy_villager(villager);
+ ============================= 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
+ direction integer."Too close.\n""I can't run away.\n""You decided to move.\n". A movement is considered successful if the villager actually moved.distance (enum).villager pointer is NULL, the function does nothing and return NEAR.enum distance walk(struct villager *villager, int direction);
+ 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);
+ ============================= 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
+ "Preparation ready !\n"villager pointer is NULL, the function does nothing and return 0.int prepare_medicine(struct villager *villager);
+ // 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);
+ ============================= 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 distance attribute of the villager:FAR, change it to NEAR.NEAR, change it to CLOSE.CLOSE, the distance does not change."The demon {demon_name} is chasing you.\n"villager or demon pointer are NULL, the function does nothing.void chase(struct demon *demon, struct villager *villager);
+ // 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);
+ ============================= 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
+ damage attribute to the target if he is in range."RAAAAAGH! {name_of_the_demon} attacks you to deal {number_of_damage} damage.\n"target or demon pointer are NULL, the function does nothing.void basic_attack(struct demon *demon, struct villager *target);
+ // 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);
+ 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
+ "SLURRRRP! {name_of_the_demon} attacks you to deal {number_of_damage} damage and regenerates {number_of_regenerated_hp} HP.\n"target or demon pointer are NULL, the function does nothing.void draining_attack(struct demon *demon, struct villager *target);
+ // 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);
+ 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
+ double damage to the target, but the demon takes some recoil damage (10% of its own max HP)."BAM! {demon name} attacks you with all his strength to deal {nb of dommage} damage.\n"target or demon pointer are NULL, the function does nothing.void heavy_attack(struct demon *demon, struct villager *target);
+ // 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);
+ 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
+ villager or demon pointer are NULL, the function does nothing.void demon_action(struct demon *demon, struct villager *villager);
+ // 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);
+ 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.
+ 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.main.c and run your program.main function, otherwise you won't be able to compile#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;
+}
+ unions. Since this concept wasn't covered in class, we will explore it here.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.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 enum animal_type
+{
+ INSECT,
+ FISH,
+};
+ struct fish
+{
+ char* species;
+ int swimming_speed;
+ size_t size;
+ int lives_in_fresh_water;
+};
+ struct insect
+{
+ char* species;
+ size_t size;
+ int can_fly;
+ int can_swim;
+};
+ union animals
+{
+ struct insect* insect;
+ struct fish* fish;
+};
+ struct animal
+{
+ enum animal_type type;
+ union animals animal;
+ char* color;
+};
+ 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);
+ 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.struct animal can hold a struct fish* OR a struct insect*, but never both at the same time.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".value or data) and assign your pointer to the specific member: animal->data.fish = fish;.my_animal->animal.fish.animals/fish.c struct animal using unions.struct fish with the given argument.species string.strdup(3) to malloc and copy strings.struct fish *fish_init(const char *species, int speed, size_t size, int fresh_water);
+ 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);
+ Fish species: Salmon
+Swimming speed: 10
+Size: 5
+Lives in fresh water: 1
+ struct animal from a specific struct fish.color string.NULL, do nothing and return NULL.struct animal *animal_from_fish(const char *color, struct fish *fish);
+ 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);
+ Animal type: 1
+Animal color: Blue
+Fish species from animal: Trout
+ struct fish.fish pointer is NULL, the function does nothing.void free_fish(struct fish *fish);
+ struct fish *f = fish_init("Carp", 6, 3, 0);
+free_fish(f);
+ (No output, just ensure no memory leaks occur with -fsanitize=address)
+ animals/insect.c struct animal.struct insect.species string.struct insect *insect_init(const char *species, size_t size, int can_fly, int can_swim);
+ 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);
+ Insect species: Dragonfly
+Size: 2
+Can fly: 1
+Can swim: 0
+ struct animal from a specific struct insect.color string.NULL, do nothing and return NULL.struct animal *animal_from_insect(const char *color, struct insect *insect);
+ 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);
+ Animal type: 0
+Animal color: Yellow
+Insect species from animal: Butterfly
+ struct insect.insect pointer is NULL, the function does nothing.void free_insect(struct insect *insect);
+ struct insect *i = insect_init("Beetle", 3, 0, 1);
+free_insect(i);
+ (No output, just ensure no memory leaks occur with -fsanitize=address)
+ animals/vector.h struct vector and the interface to manipulate it.struct vector
+{
+ struct animal **animal;
+ size_t size;
+ size_t capacity;
+};
+ 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);
+ int tab[10];, you cannot store an 11th element without causing a buffer overflow.realloc is computationally expensive (it may need to copy the whole array to a new memory location). 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 capacity of n.struct vector.size to 0.capacity to n.struct vector *vector_init(size_t n);
+ struct vector *v = vector_init(5);
+printf("Initial size: %zu\n", v->size);
+printf("Initial capacity: %zu\n", v->capacity);
+ Initial size: 0
+Initial capacity: 5
+ capacity of the vector to new_capacity.realloc to resize the internal animal array to the new capacity.capacity attribute of the structure.vector pointer is NULL, the function does nothing and return NULL.struct vector *vector_resize(struct vector *v, size_t new_capacity);
+ struct vector *v = vector_init(2);
+v = vector_resize(v, 4);
+printf("Resized capacity: %zu\n", v->capacity);
+ Resized capacity: 4
+ animal to the end of the list and updates the size.vector_resize to double the current capacity.animal pointer at the correct index.size.struct vector *vector_append(struct vector *v, struct animal *animal);
+ 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);
+ Vector size after appends: 3
+Vector capacity after appends: 4
+ struct animal.type attribute (the Tag) to know which specific free function to call:FISH: Call free_fish on the specific union member.INSECT: Call free_insect on the specific union member.color string, and finally the animal structure itself.void free_animal(struct animal *animal);
+ struct fish *f = fish_init("Salmon", 10, 5, 1);
+struct animal *a = animal_from_fish("Blue", f);
+free_animal(a);
+ (No output, just ensure no memory leaks occur with -fsanitize=address)
+ void vector_destroy(struct vector *v);
+ 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);
+ (No output, just ensure no memory leaks occur with -fsanitize=address)
+ museum_restoration/fossils.h enum body_part
+{
+ SKULL,
+ TORSO,
+ TAIL,
+ WINGS,
+ LEGS,
+ COMPLETE,
+};
+ 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).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 struct fossil initialized with the given attributes.species string and copy the provided string into it.struct fossil *init_fossil(char *species, enum body_part body_part, size_t age, char has_wings);
+ struct fossil.has_wings == 0. If not, return NULL.species and age.SKULL, TORSO, TAIL, LEGS.COMPLETE fossil (same age/species). You MUST free the 4 input parts and set their pointers to NULL in the array.NULL (do not free anything).struct fossil *assemble_wingless(struct fossil *fossils[4]);
+ struct fossil.has_wings != 0. If not, return NULL.species and age.SKULL, TORSO, TAIL, LEGS, WING.COMPLETE fossil. You MUST free the 5 input parts and set their pointers to NULL.NULL.struct fossil *assemble_with_wings(struct fossil *fossils[5]);
+ fossils) and its size (nb_fossils).COMPLETE fossils in a new array.NULL-terminated array containing pointers to all the completed fossils.struct fossil **assemble_all_fossils(struct fossil **fossils, size_t nb_fossils);
+