Aloyse et Anna

j'ai push pas mal de fichier envoyer un message si vous en voulez un aute
This commit is contained in:
2024-12-12 16:22:28 +01:00
parent d1d6a3aea3
commit a4703085b6
7 changed files with 2216 additions and 0 deletions

View File

@@ -0,0 +1,146 @@
/**
* @file data_queue_turn.h
* @brief
* Implémentation d'un tuyau de turn * .
*
* @remark
* Cette structure de données est utilisée pour l'historique.
*/
#ifndef QUEUE_TURN_H_
#define QUEUE_TURN_H_
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "alloc.h"
#include "game_history.h"
/* _____ _ _ */
/* | ___(_) | ___ ___ */
/* | |_ | | |/ _ \/ __| */
/* | _| | | | __/\__ \ */
/* |_| |_|_|\___||___/ */
/**
* @brief
* Implémentation d'un tuyau.
*/
typedef struct {
turn ** array; //!< Tableau de turn.
int size_array; //!< Taille du tableau des valeurs.
int left; //!< Indice de la valeur au début du tuyau (si non-vide).
int right; //!< Indice qui suit celui de la valeur à la fin du tuyau (si
//!< non-vide).
bool empty; //!< Booléen indiquant si le tuyau est vide.
} queue_turn ;
/***************************/
/*+ Fonctions auxiliaires +*/
/***************************/
/**
* @brief
* Multiplication par deux de la taille du tuyau.
*/
void grow_queue_turn (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Division par deux de la taille du tuyau.
*/
void shrink_queue_turn (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Libération d'un tour.
*/
void free_turn (turn * //!< Le tour à libérer.
);
/****************/
/*+ Primitives +*/
/****************/
/**
* @brief
* Création d'un tuyau vide.
*
* @return
* Le tuyau vide.
*/
queue_turn * create_queue_turn (void);
/**
* @brief
* Suppression d'un tuyau.
*/
void delete_queue_turn (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Teste si un tuyau est vide.
*
* @return.
* Un Booléen indiquant si le tuyau est vide.
*/
bool is_empty_queue_turn (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Calcul de la taille d'un tuyau.
*
* @return
* La taille du tuyau.
*/
int getsize_queue_turn (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Lit une valeur quelconque du tuyau (sans le modifier).
*
* @return
* La valeur lue.
*/
turn * read_queue_turn (queue_turn * //!< Le tuyau.
,
int //!< L'indice de la valeur à lire (à partir du début du
//!< tuyau (à gauche), la première valeur a pour indice 0).
);
/**
* @brief
* Enfile une nouvelle valeur à droite dans le tuyau.
*/
void enqueue_turn_right (turn * //!< La valeur à enfiler.
,
queue_turn * //!< Le tuyau.
);
/**
* @brief
* Défile la valeur à gauche du tuyau.
*
* @return
* La valeur défilée.
*/
turn * dequeue_turn_left (queue_turn * //!< Le tuyau.
);
/**
* @brief
* Défile la valeur à droite du tuyau.
*
* @return
* La valeur défilée.
*/
turn * dequeue_turn_right (queue_turn * //!< Le tuyau.
);
#endif

541
Aloyse et Anna/game.c Normal file
View File

@@ -0,0 +1,541 @@
#include "game.h"
#include "game_history.h"
#include "maze.h"
/****************************/
/*+ Création et libération +*/
/****************************/
// Génération d'un nouveau jeu
game* create_newgame(int hsize, int vsize, mask* themask, generator gen_maze, objgenerator gen_obj, int nb_min, int braid) {
// Allocation mémoire pour le jeu
game* g = malloc(sizeof(game));
if (g == NULL) {
ERROR("Erreur d'allocation mémoire pour le jeu.");
}
// Création du proto-labyrinthe
maze* lab = NULL;
// Avec masque
if (themask != NULL) {
if (themask->hsize != hsize || themask->vsize != vsize) { // On verifie la taille du masque
resize_mask(themask, hsize, vsize);
}
lab = create_proto_maze(themask);
}
// Sans masque
else {
lab = create_proto_maze_nomask(hsize, vsize);
}
// On verifie la création du labyrinthe
if (lab == NULL) {
ERROR("Erreur de création du proto-labyrinthe");
}
// Modification du labyrinthe en fonction du générateur
if (gen_maze < 0 || gen_maze >= GEN_SIZE) {
free_game(g);
ERROR("Générateur de labyrinthe invalide");
} else {
gen_funs[gen_maze](lab);
}
// Modification du labyrinthe en fonction du générateur d'objets
if (gen_obj < 0 || gen_obj >= OBJ_SIZE) {
free_game(g);
ERROR("Générateur d'objets invalide");
} else {
obj_funs[gen_obj](lab);
}
// Modification du labyrinthe en fonction du nombre de minotaures
if (nb_min < 0) {
free_game(g);
ERROR("Nombre de minotaures invalide");
} else {
gen_minotaurs_maze(lab, nb_min);
}
// Modification du labyrinthe en fonction du tressage
if (braid < 0 || braid > 100) {
free_game(g);
ERROR("Taux de tressage invalide");
} else {
braid_maze(lab, braid);
}
// Initialisation du jeu
g->m = lab; // On affecte le labyrinthe
g->score = 0;
g->nbombs = 0;
g->npolys = 0;
g->player_alive = true;
g->player_dir = rand() % 4; // Le joueur est tourné dans une direction aléatoire
g->minotaurs_alive = malloc(sizeof(bool) * g->m->nb_minotaurs);
g->minotaurs_dirs = malloc(sizeof(cardinal) * g->m->nb_minotaurs);
for (int i = 0; i < g->m->nb_minotaurs; i++) {
g->minotaurs_alive[i] = true; // Les minotaures sont tous vivants
g->minotaurs_dirs[i] = rand() % 4; // Les minotaures sont tournés dans une direction aléatoire
}
g->nb_deadends = count_dead_ends(g->m);
g->exits = get_exits_maze(g->m);
g->turns = 0;
g->log = create_history();
if (g->log == NULL) {
free_game(g);
ERROR("Erreur de création de l'historique");
}
if (g == NULL) {
ERROR("Le labyrinthe n'a pas été créé");
}
return g;
}
void free_game(game* g) {
if (g == NULL) {
ERROR("Pointeur null");
} else {
if (g->m != NULL) {
free_maze(g->m);
}
if (g->minotaurs_alive != NULL) {
free(g->minotaurs_alive);
}
if (g->minotaurs_dirs != NULL) {
free(g->minotaurs_dirs);
}
if (g->log != NULL) {
free_history(g->log);
}
free(g);
}
return;
}
/***********************************************/
/*+ Implémentation des attaques de minotaures +*/
/***********************************************/
int game_try_kill_player(game* g, cardinal* dir) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste les cases adjacentes au joueur pour les 4 directions
for (int i = 0; i < 4; i++) {
int adj = get_adj_maze(g->m, g->m->player, i);
if (adj != -1 && !has_wall_maze(g->m, g->m->player, i) && has_minotaur_maze(g->m, adj) != -1 && g->minotaurs_alive[has_minotaur_maze(g->m, adj)]) {
*dir = (i + 2) % 4;
g->player_alive = false;
return has_minotaur_maze(g->m, adj);
}
}
// Si on n'a pas trouvé de minotaure adjacent
return -1;
}
/***************************/
/*+ Traitement des objets +*/
/***************************/
void game_consume_object(game* g, int nb_copie, object obj) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste le type de l'objet
switch (obj) {
case SMALLT:
g->score += nb_copie * VALSMALL;
break;
case MEDT:
g->score += nb_copie * VALMED;
break;
case LARGET:
g->score += nb_copie * VALLARGE;
break;
case BOMB:
g->nbombs += nb_copie;
break;
case POLY:
g->npolys += nb_copie;
break;
default:
break;
}
if (obj != EXIT && obj != NONE) {
for (int i = 0; i < nb_copie; i++) {
g->m->objects[g->m->player] = NONE;
}
}
return;
}
object game_treat_object(game* g) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
// On récupère l'objet de la cellule du joueur
object obj = get_object_maze(g->m, g->m->player);
// On teste le type de l'objet
switch (obj) {
case SMALLT:
game_consume_object(g, 1, SMALLT);
return SMALLT;
case MEDT:
game_consume_object(g, 1, MEDT);
return MEDT;
case LARGET:
game_consume_object(g, 1, LARGET);
return LARGET;
case BOMB:
game_consume_object(g, 1, BOMB);
return BOMB;
case POLY:
game_consume_object(g, 1, POLY);
return POLY;
case EXIT:
return EXIT;
default:
break;
}
return NONE;
}
/**********************************************************/
/*+ Implémentation d'une demande de mouvement du joueur +*/
/**********************************************************/
bool implement_game_move(game* g, move mov, strategy strag) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste si le joueur est vivant
if (!g->player_alive) {
return false;
}
// On teste si le mouvement est valide
if (!valid_move_maze(g->m, g->m->player, mov)) {
g->player_dir = (cardinal)mov;
return false;
}
// SINON on fait le mouvement
// On déplace le joueur et on le tourne dans la direction dans laquelle il avance
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)mov);
g->player_dir = (cardinal)mov;
make_occupied_maze(g->m, g->m->player);
// On gère les minotaures
// On creer le tableau des mouvements des minotaures
// pas la peine de l'initaliser à M_WAIT car on va le remplir
move* min_move = malloc(sizeof(move) * g->m->nb_minotaurs);
// On applique la stratégie des minotaures
str_funs[strag](g->m, mov, min_move);
// On teste si les minautores peuvent se déplacer
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (g->minotaurs_alive[i]) {
// Si le minotaure est vivant et qu'on peut le déplacer dans la direction demandée
if (valid_move_maze(g->m, g->m->minotaurs[i], min_move[i])) {
free_occupied_maze(g->m, g->m->minotaurs[i]);
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)min_move[i]);
make_occupied_maze(g->m, g->m->minotaurs[i]);
g->minotaurs_dirs[i] = (cardinal)min_move[i];
}
// Sinon on le tourne dans la direction demandée et on mets son mouvements à M_WAIT
else {
g->minotaurs_dirs[i] = (cardinal)min_move[i];
min_move[i] = M_WAIT;
}
}
}
// On teste les objets
object obj = game_treat_object(g);
// On teste si le joueur est attaqué
cardinal* dir_player = malloc(sizeof(cardinal));
*dir_player = g->player_dir;
int min_killer = game_try_kill_player(g, dir_player);
if (min_killer != -1) {
g->player_alive = false;
}
// On gère l'historique
t_move* history_move = malloc(sizeof(t_move));
history_move->obj = obj;
history_move->playermove = mov;
history_move->minomoves = min_move;
history_move->killer = min_killer;
// On trouve la direction du minotaure qui a tué le joueur
if (min_killer != -1) {
for (cardinal i = 0; i < 4; i++) {
if (get_adj_maze(g->m, g->m->minotaurs[min_killer], i) == g->m->player) {
history_move->dirkill = i;
}
}
} else {
history_move->dirkill = NORTH;
}
turn new_turn = {T_MOVE, .tmove = history_move};
add_entry_history(new_turn, g->log);
g->turns++;
return true;
}
/*******************************/
/*+ Implémentation des bombes +*/
/*******************************/
bool game_bomb_wall(game* g) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste si le joueur a une bombe
if (g->nbombs > 0 && g->player_alive) {
// On teste si on peut détruire le mur
if (get_adj_maze(g->m, g->m->player, g->player_dir) != -1 && valid_maze(g->m, get_adj_maze(g->m, g->m->player, g->player_dir)) &&
has_wall_maze(g->m, g->m->player, g->player_dir)) {
del_wall_maze(g->m, g->m->player, g->player_dir);
// On teste si le joueur est attaqué
cardinal* dir_player = malloc(sizeof(cardinal));
*dir_player = g->player_dir;
int min_killer = game_try_kill_player(g, dir_player);
if (min_killer != -1) {
g->player_alive = false;
}
g->nbombs--;
// On gère l'historique
t_bomb* history_move = malloc(sizeof(t_bomb));
history_move->bombdir = g->player_dir;
history_move->destroyed = true;
history_move->killer = game_try_kill_player(g, dir_player);
// On trouve la direction du minotaure qui a tué le joueur
if (min_killer != -1) {
for (cardinal i = 0; i < 4; i++) {
if (get_adj_maze(g->m, g->m->minotaurs[min_killer], i) == g->m->player) {
history_move->dirkill = i;
}
}
} else {
// Sinon on met une direction par défaut
history_move->dirkill = NORTH;
}
turn new_turn = {T_BOMB, .tbomb = history_move};
// On ajoute le tour à l'historique
add_entry_history(new_turn, g->log);
g->turns++;
return true;
}
// Sinon on ne peut pas détruire de mur mais on perd quand même une bombe
else {
g->nbombs--;
// On gère l'historique
t_bomb* history_move = malloc(sizeof(t_bomb));
history_move->bombdir = g->player_dir;
history_move->destroyed = false;
history_move->killer = -1;
history_move->dirkill = NORTH;
// On trouve la direction du minotaure qui a tué le joueur
turn new_turn = {T_BOMB, .tbomb = history_move};
add_entry_history(new_turn, g->log);
g->turns++;
return true;
}
}
return false;
}
/*************************************/
/*+ Implémentation des polys d'algo +*/
/*************************************/
bool game_kill_minotaurs(game* g, int portee) {
if (g == NULL || g->m == NULL) {
ERROR("Pointeur de jeu null");
}
if (portee < 0) {
ERROR("Portée invalide");
}
// On teste si le joueur a un poly d'algo
if (g->npolys > 0 && g->player_alive) {
int nb_min_kill = 0;
// On initialise le tableau des minotaures tués pour l'historique
bool* min_killed = malloc(sizeof(bool) * g->m->nb_minotaurs);
for (int i = 0; i < g->m->nb_minotaurs; i++) {
min_killed[i] = false;
}
// On teste dans les quatres directions
for (int i = 0; i < 4; i++) {
int cell_dir = g->m->player;
int portee_dir = portee;
while (portee_dir > 0 && get_adj_maze(g->m, cell_dir, i) != -1) {
int num_mino = has_minotaur_maze(g->m, get_adj_maze(g->m, cell_dir, i));
if (num_mino != -1 && g->minotaurs_alive[num_mino]) {
nb_min_kill++;
g->minotaurs_alive[num_mino] = false;
min_killed[num_mino] = true;
free_occupied_maze(g->m, get_adj_maze(g->m, cell_dir, i));
}
portee_dir--;
cell_dir = get_adj_maze(g->m, cell_dir, i);
}
}
if (nb_min_kill > 0) {
g->npolys--;
// On gère l'historique
turn new_turn = {T_POLY, .minokilled = min_killed};
add_entry_history(new_turn, g->log);
g->turns++;
return true;
}
}
return false;
}
/*****************************/
/*+ Gestion de l'historique +*/
/*****************************/
bool game_undo(game* g) {
if (g == NULL || g->log == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste si l'historique est vide
if (sizeprev_history(g->log) == 0) {
return false;
}
// Sinon on annule le dernier tour
// On récupère le dernier tour
turn* last_turn = last_move_history(g->log);
rewind_history(g->log);
g->turns--;
switch (last_turn->type) {
case T_MOVE:
// On récupère les caractéristiques du tour
t_move* history_move = last_turn->tmove;
// On teste si le joueur a été attaqué
if (history_move->killer != -1) {
g->player_alive = true;
}
// On replace l'objet consommé
if (history_move->obj != NONE) {
game_consume_object(g, -1, history_move->obj);
g->m->objects[g->m->player] = history_move->obj;
}
// On deplace le joueur
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)(history_move->playermove + 2) % 4);
g->player_dir = (cardinal)((history_move->playermove + 2) % 4);
make_occupied_maze(g->m, g->m->player);
// On gère les déplacements des minotaures
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (g->minotaurs_alive[i]) {
// Si le minotaure est vivant on annule son déplacement
if (history_move->minomoves[i] != M_WAIT) {
free_occupied_maze(g->m, g->m->minotaurs[i]);
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)(history_move->minomoves[i] + 2) % 4);
make_occupied_maze(g->m, g->m->minotaurs[i]);
g->minotaurs_dirs[i] = (cardinal)(history_move->minomoves[i] + 2) % 4;
}
}
}
return true;
case T_BOMB:
t_bomb* history_bomb = last_turn->tbomb;
// Si un mur a été détruit
if (history_bomb->destroyed) {
// On teste si le joueur a été attaqué
if (history_bomb->killer != -1) {
g->player_alive = true;
}
// On replace le mur détruit
build_wall_maze(g->m, g->m->player, history_bomb->bombdir);
}
// On recupère la bombe consommée
g->nbombs++;
return true;
case T_POLY:
bool* history_poly = last_turn->minokilled;
// On ressucite les minotaures tués
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (history_poly[i]) {
g->minotaurs_alive[i] = true;
make_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
return true;
}
return false;
}
bool game_redo(game* g) {
if (g == NULL || g->log == NULL) {
ERROR("Pointeur de jeu null");
}
// On teste si l'historique est vide
if (sizenext_history(g->log) == 0) {
return false;
}
// Sinon on remet le dernier tour annulé
// On récupère le dernier tour annulé
turn* next_turn = next_move_history(g->log);
continue_history(g->log);
g->turns++;
switch (next_turn->type) {
case T_MOVE:
// On récupère les caractéristiques du tour
t_move* history_move = next_turn->tmove;
// On teste si le joueur avait été attaqué
if (history_move->killer != -1) {
g->player_alive = false;
}
// On deplace le joueur
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)(history_move->playermove));
g->player_dir = (cardinal)((history_move->playermove));
make_occupied_maze(g->m, g->m->player);
// On re-recupère l'objet
if (history_move->obj != NONE) {
game_consume_object(g, 1, history_move->obj);
g->m->objects[g->m->player] = NONE;
}
// On gère les déplacements des minotaures
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (g->minotaurs_alive[i]) {
// Si le minotaure est vivant on refait son déplacement
if (history_move->minomoves[i] != M_WAIT) {
free_occupied_maze(g->m, g->m->minotaurs[i]);
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)(history_move->minomoves[i]));
make_occupied_maze(g->m, g->m->minotaurs[i]);
g->minotaurs_dirs[i] = (cardinal)(history_move->minomoves[i]);
}
}
}
return true;
case T_BOMB:
t_bomb* history_bomb = next_turn->tbomb;
// Si un mur avait été détruit puis reconstruit
if (history_bomb->destroyed) {
// On teste si le joueur a été attaqué
if (history_bomb->killer != -1) {
g->player_alive = false;
}
// On reconstruit le mur
del_wall_maze(g->m, g->m->player, history_bomb->bombdir);
}
return true;
case T_POLY:
bool* history_poly = next_turn->minokilled;
// On tue les minotaures qui avaient été ressucités
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (history_poly[i]) {
g->minotaurs_alive[i] = false;
free_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
return true;
}
return false;
return false;
}

View File

@@ -0,0 +1,110 @@
#include "game_history.h"
#include "data_queue_turn.h"
// La structure pour représenter un historique : à définir.
typedef struct history {
queue_turn* queue_history; // File des tours précédents
int nb_past; // Nombre de tours passés
} history;
history* create_history(void) {
history* ptr = malloc(sizeof(history));
if (ptr == NULL) {
ERROR("Erreur d'allocation mémoire pour l'historique.");
return NULL;
}
ptr->queue_history = create_queue_turn();
if (ptr->queue_history == NULL) {
ERROR("Erreur d'allocation mémoire pour la file des tours.");
free(ptr);
return NULL;
}
ptr->nb_past = 0;
return ptr; // On renvoie l'historique vide
}
void free_history(history* ptr) {
if (ptr == NULL) {
return;
}
if (ptr->queue_history != NULL) {
delete_queue_turn(ptr->queue_history);
}
free(ptr);
return;
}
void add_entry_history(turn to_add_turn, history* ptr_history) {
if (ptr_history == NULL) {
ERROR("add_entry_history : ptr_history NULL");
}
// On alloue la mémoire pour le tour à ajouter
turn* new_turn = malloc(sizeof(turn));
if (new_turn == NULL) {
ERROR("Erreur d'allocation mémoire pour le tour.");
return;
}
// On initialise le tour à ajouter avec les valeurs du tour à ajouter
new_turn->type = to_add_turn.type;
new_turn->tmove = to_add_turn.tmove;
// Si le nombre de tours passés est différent de la taille de la file des tours
// On supprime tous les tours futurs
if (ptr_history->nb_past != getsize_queue_turn(ptr_history->queue_history)) {
// On dequeue tous les tours futurs
while (ptr_history->nb_past != getsize_queue_turn(ptr_history->queue_history)) {
dequeue_turn_right(ptr_history->queue_history);
}
}
// Si l'histoire est plein on supprime le tour le plus à gauche
if (getsize_queue_turn(ptr_history->queue_history) == HISTORY_MAX) {
dequeue_turn_left(ptr_history->queue_history);
ptr_history->nb_past--;
}
// On ajoute le tour à la fin de la file des tours
enqueue_turn_right(new_turn, ptr_history->queue_history);
ptr_history->nb_past++;
return;
}
int sizenext_history(history* ptr_history) { return getsize_queue_turn(ptr_history->queue_history) - ptr_history->nb_past; }
int sizeprev_history(history* ptr_history) { return ptr_history->nb_past; }
void rewind_history(history* ptr_history) {
if (ptr_history == NULL) {
ERROR("rewind_history : ptr_history NULL");
}
if (sizeprev_history(ptr_history) == 0) {
return;
}
ptr_history->nb_past--;
return;
}
void continue_history(history* ptr_history) {
if (ptr_history == NULL) {
ERROR("continue_history : ptr_history NULL");
}
if (sizenext_history(ptr_history) == 0) {
return;
}
ptr_history->nb_past++;
return;
}
turn* last_move_history(history* ptr_history) {
if (sizeprev_history(ptr_history) == 0) {
return NULL;
}
return read_queue_turn(ptr_history->queue_history, ptr_history->nb_past - 1);
}
turn* next_move_history(history* ptr_history) {
if (sizenext_history(ptr_history) == 0) {
return NULL;
}
return read_queue_turn(ptr_history->queue_history, ptr_history->nb_past);
}

595
Aloyse et Anna/maze_gen.c Normal file
View File

@@ -0,0 +1,595 @@
#include "maze_gen.h"
#include <stdio.h>
#include <time.h>
#include "data_queue.h"
void (*gen_funs[GEN_SIZE])(maze*) = {&maze_test, &random_maze_ab, &random_maze_wilson, &random_maze_hklinear,
&random_maze_hkdfs, &random_maze_hkrandom, &random_maze_prim, &random_maze_kruskal,
&random_maze_rec};
const char* gen_names[GEN_SIZE] = {"Test (pas de génération)",
"Aldous-Broder",
"Wilson",
"Hunt & Kill: Linéaire",
"Hunt & Kill: DFS",
"Hunt & Kill: Aléatoire",
"Prim",
"Kruskal",
"Récursif"};
// FONCTIONS AUXILLIAIRES
// Fonction auxilliaire qui retourne vrai si la cellule à au moins une cellule adjacente non visitée accessible
static bool has_adj_no_visited(maze* lab, bool* visited, int cell) {
for (int i = 0; i < 4; i++) {
int adj = get_adj_maze(lab, cell, i);
if (adj != -1 && is_reach_maze(lab, adj) && !visited[get_adj_maze(lab, cell, i)]) {
return true;
}
}
return false;
}
// Fonction qui renvoie la hsize (taille horizontale) d'un labyrinthe
static int get_hsize(maze* lab) { return lab->hsize; }
// Fonction qui renvoie la vsize (taille verticale) d'un labyrinthe
static int get_vsize(maze* lab) { return lab->vsize; }
// Fonction auxilliaire pour la boucle kill de la génération de labyrinthe hunt & kill et pour le choix de la cellule de Wilson
static int boucle_kill_direction(maze* lab, bool* visited, int cell) {
int dir[4] = {0, 1, 2, 3}; // Tableau des directions possibles
int size = 4;
bool found_dir = false;
// Tant qu'il reste des directions possibles et qu'on n'en a pas tiré de valide
while (size > 0 && !found_dir) {
const int r = rand() % size;
int c = dir[r]; // On tire une direction aléatoire
// On récupère la cellule adjacente dans la direction tirée
int new_cell = get_adj_maze(lab, cell, c);
// Si on peut se déplacer dans la direction tirée et que la cellule n'a pas été visitée et est accessible
if (new_cell != -1 && valid_maze(lab, new_cell) && is_reach_maze(lab, new_cell) && !visited[new_cell]) {
// On a trouvé une direction valide
found_dir = true;
del_wall_maze(lab, cell, c); // On détruit le mur
cell = new_cell; // On se déplace
}
// Sinon on supprime la direction prise du tableau et on décalle les directions pour recommencer avec les directions restantes
for (int i = r; i < size - 1; i++) {
dir[i] = dir[i + 1];
}
size--;
}
return cell;
}
// Fonction auxilliaire qui renvoie une cellule de départ aléatoire
static int get_start_cell(maze* lab) {
// On récupère les dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Initialisation de la cellule de départ
int cell = rand() % (hsize * vsize);
// On vérifie que la cellule est accessible
int* tab = malloc(sizeof(int) * hsize * vsize);
for (int i = 0; i < hsize * vsize; i++) {
tab[i] = i;
}
int count = hsize * vsize;
while (!is_reach_maze(lab, cell)) {
// On choisit une cellule aléatoire
int ind_rand = rand() % count;
cell = tab[ind_rand];
if (!is_reach_maze(lab, cell)) {
// On échange la cellule choisie avec la dernière cellule du tableau
tab[ind_rand] = tab[count - 1];
count--;
}
}
free(tab);
return cell;
}
// FONCTIONS DE GENERATION DU .h
void maze_test(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
}
void random_maze_ab(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// On récupère les dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Création d'un tableau repertoriant si une cellule a été visitée
bool* visited = malloc(hsize * vsize * sizeof(bool));
for (int i = 0; i < hsize * vsize; i++) {
visited[i] = false;
}
// Création d'un compteur du nombre de cellules visitées
int nb_visited = 0;
// Initialisation de la cellule de départ
int cell = get_start_cell(lab);
// Cette cellule est visitée
visited[cell] = true;
nb_visited++;
// Tant que toutes les cellules accessibles n'ont pas été visitées
while (nb_visited != lab->nb_reachable) {
// On choisit une direction aléatoire
int dir = rand() % 4;
// On récupère la cellule adjacente dans la direction tirée
int cell_adj = get_adj_maze(lab, cell, dir);
// Si on peut se déplacer dans la direction tirée et que la cellule n'a pas été visitée et est accessible
// On détruit le mur entre les deux cellules
if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj) && !visited[cell_adj]) {
del_wall_maze(lab, cell, dir);
visited[cell_adj] = true; // On marque la cellule adjacente comme visitée
nb_visited++; // On incrémente le nombre de cellules visitées
cell = cell_adj; // On se déplace
}
// Sinon si la cellule adjacente est accessible mais a déjà été visitée
else if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj)) {
cell = cell_adj;
}
}
free(visited);
}
void random_maze_wilson(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// On récupère les dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Création d'un tableau repertoriant si une cellule a été visitée
bool* visited = malloc(hsize * vsize * sizeof(bool));
for (int i = 0; i < hsize * vsize; i++) {
visited[i] = false;
}
// Création d'une files pour stocker la marche aléatoire
queue* queue_walk = create_queue();
// Création d'un compteur du nombre de cellules visitées
int nb_visited = 0;
// Initialisation de la cellule de départ
int cell_start = get_start_cell(lab);
// Cette cellule est visitée
visited[cell_start] = true;
nb_visited++;
// Tant que toutes les cellules accessibles n'ont pas été visitées
while (nb_visited != lab->nb_reachable) {
int cell_walk = cell_start;
// On choisit aléatoirement une cellule non visitée
while (visited[cell_walk]) {
cell_walk = get_start_cell(lab);
}
enqueue(cell_walk, queue_walk);
// On effectue une marche aléatoire jusqu'à atteindre une cellule visitée
while (!visited[cell_walk]) {
// On choisit une direction aléatoire
int dir = rand() % 4;
// On récupère la cellule adjacente dans la direction tirée
int cell_adj = get_adj_maze(lab, cell_walk, dir);
// Si on peut se déplacer dans la direction tirée et que la cellule est accessible
if (cell_adj != -1 && valid_maze(lab, cell_adj) && is_reach_maze(lab, cell_adj)) {
cell_walk = cell_adj; // On se déplace
enqueue(cell_walk, queue_walk); // On ajoute la cellule à la marche aléatoire
}
}
// On élime les cycles de la marche aléatoire on part du début de la marche aléatoire
// Pour chaque cellule si elle revient dans la marche aléatoire on supprime les cellules entre les deux
// On marque les cellules de la marche aléatoire comme visitées et on casse les murs
int cell_che = dequeue(queue_walk);
while (!is_empty_queue(queue_walk)) {
if (!visited[cell_che]) {
visited[cell_che] = true;
nb_visited++;
}
// Si elle revient dans la marche aléatoire ou dequeue toutes les cellules entre les deux
bool found_in_walk = false;
int count = 0;
for (int i = 0; i < getsize_queue(queue_walk); i++) {
if (read_queue(queue_walk, i) == cell_che) {
found_in_walk = true;
count = i;
break;
}
}
if (found_in_walk) {
while (getsize_queue(queue_walk) != count) {
dequeue(queue_walk);
}
}
if (!is_empty_queue(queue_walk)) {
// On récupère la cellule suivante et on casse le mur entre les deux
int next_cell = dequeue(queue_walk);
for (int dir = 0; dir < 4; dir++) {
if (get_adj_maze(lab, cell_che, dir) == next_cell) {
del_wall_maze(lab, cell_che, dir);
}
}
cell_che = next_cell;
}
}
// On marque la dernière cellule de la marche aléatoire comme visitée
if (!visited[cell_che]) {
visited[cell_che] = true;
nb_visited++;
}
}
free(visited);
delete_queue(queue_walk);
}
void random_maze_hkdfs(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// Récupération des dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Création d'un tableau repertoriant si une cellule a été visitée
bool* visited = malloc(hsize * vsize * sizeof(bool));
for (int i = 0; i < hsize * vsize; i++) {
visited[i] = false;
}
// Création d'un compteur du nombre de cellules visitées
int nb_visited = 0;
// Initialisation d'une pile stockant les cellules visitées pour le DFS
dynarray* stack = create_dyn();
// Initialisation de la cellule de départ
int cell = get_start_cell(lab);
// Cette cellule est visitée
visited[cell] = true;
nb_visited++;
push_dyn(cell, stack); // On empile la cellule
// Tant que toutes les cellules accessibles n'ont pas été visitées
while (nb_visited != lab->nb_reachable) {
// BOUCLE HUNT
// On regarde si la dernière cellule visitée à une voisin non visitée jusqu'à trouver une cellule
bool found_hunt = false;
while (!found_hunt) {
int hunt = pop_dyn(stack); // On dépile la cellule
// On regarde si une de ses voisines n'a pas été visitée si c'est le cas, on se déplace dans cette cellule
if (has_adj_no_visited(lab, visited, hunt)) {
cell = hunt;
found_hunt = true;
}
}
push_dyn(cell, stack); // On empile la cellule
// BOUCLE KILL
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
// On recupère une cellule adjacente non visitée
cell = boucle_kill_direction(lab, visited, cell);
visited[cell] = true;
nb_visited++;
push_dyn(cell, stack);
}
}
free(visited);
free_dyn(stack);
}
void random_maze_hkrandom(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// Récupération des dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Création d'un tableau repertoriant si une cellule a été visitée
bool* visited = malloc(hsize * vsize * sizeof(bool));
for (int i = 0; i < hsize * vsize; i++) {
visited[i] = false;
}
// Création d'un tableau repetoriant les cellules visitées et un compteur qui permet de savoir combien de cellules ont été visitées et avec ou sans
// Voisins adjacents
int* visited_cells = malloc(hsize * vsize * sizeof(int));
int nb_visited = 0;
int nb_visited_total = 0;
// Initialisation de la cellule de départ
int cell = rand() % (hsize * vsize);
// On vérifie que la cellule est accessible
int* tab = malloc(sizeof(int) * hsize * vsize);
for (int i = 0; i < hsize * vsize; i++) {
tab[i] = i;
}
int count = hsize * vsize;
while (!is_reach_maze(lab, cell)) {
// On choisit une cellule aléatoire
int ind_rand = rand() % count;
cell = tab[ind_rand];
if (!is_reach_maze(lab, cell)) {
// On échange la cellule choisie avec la dernière cellule du tableau
tab[ind_rand] = tab[count - 1];
count--;
}
}
free(tab);
// Cette cellule est visitée
visited[cell] = true;
visited_cells[0] = cell;
nb_visited++;
nb_visited_total++;
// Tant que toutes les cellules n'ont pas été visitées
while (nb_visited_total != lab->nb_reachable) {
// BOUCLE HUNT
// On choisit une cellule aléatoire parmis les cellules visitées
bool found_hunt = false;
while (!found_hunt) {
// On tire une cellule aléatoire parmis le tableau des cellules
// Visitées
int ind_hunt = rand() % nb_visited;
// On regarde si une de ses voisines n'a pas été visitée si c'est le
// Cas, on se déplace dans cette cellule
if (has_adj_no_visited(lab, visited, visited_cells[ind_hunt])) {
cell = visited_cells[ind_hunt];
found_hunt = true;
} else {
// La cellule n'a pas de voisins non visités
// On la retire du tableau des cellules visitées car on n'a plus besoin de la tester
visited_cells[ind_hunt] = visited_cells[nb_visited - 1];
nb_visited--;
}
}
// BOUCLE KILL
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
// On recupère une cellule adjacente non visitée
cell = boucle_kill_direction(lab, visited, cell);
visited[cell] = true;
visited_cells[nb_visited] = cell;
nb_visited++;
nb_visited_total++;
}
}
free(visited);
free(visited_cells);
}
void random_maze_hklinear(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// Récupération des dimensions du labyrinthe
int hsize = get_hsize(lab); // Taille horizontale
int vsize = get_vsize(lab); // Taille verticale
// Création d'un tableau repertoriant si une cellule a été visitée
bool* visited = malloc(hsize * vsize * sizeof(bool));
for (int i = 0; i < hsize * vsize; i++) {
visited[i] = false;
}
// Création d'un compteur du nombre de cellules visitées
int nb_visited = 0;
// Initialisation de la cellule de départ
int cell = get_start_cell(lab);
// Cette cellule est visitée
visited[cell] = true;
nb_visited++;
// Tant que toutes les cellules n'ont pas été visitées
while (nb_visited != lab->nb_reachable) {
// BOUCLE HUNT
// On parcourt toutes les cellules
bool found_hunt = false;
int hunt = 0;
while (!found_hunt && hunt < hsize * vsize) {
// Si la cellule a été visitée on regarde si une de ses voisines n'a pas été visitée si c'est le cas, on se déplace dans cette cellule
if (visited[hunt]) {
if (has_adj_no_visited(lab, visited, hunt)) {
cell = hunt;
found_hunt = true;
}
}
hunt++;
}
// BOUCLE KILL
// Détruire un mur aléatoire tant que toutes les cellules voisines n'ont pas été visitées pour créer un long couloir/chemin
while (has_adj_no_visited(lab, visited, cell)) { // Tant que cell a une voisine non visitée
// On recupère une cellule adjacente non visitée
cell = boucle_kill_direction(lab, visited, cell);
visited[cell] = true; // On marque la cellule comme visitée
nb_visited++; // On incrémente le nombre de cellules visitées
}
}
free(visited);
}
// Structure pour représenter une arête
typedef struct {
int cell1; // Première cellule de l'arête
int cell2; // Seconde cellule de l'arête
cardinal dir; // Direction de l'arête
} edge;
// Fonction pour ajouter une arête à la liste des arêtes à traiter
static void add_edges(maze* m, int cell, edge* edges, int* edge_count) {
for (int dir = 0; dir < 4; dir++) {
int adj_cell = get_adj_maze(m, cell, dir);
if (adj_cell != -1 && valid_maze(m, adj_cell) && is_reach_maze(m, adj_cell)) {
edges[*edge_count].cell1 = cell;
edges[*edge_count].cell2 = adj_cell;
edges[*edge_count].dir = dir;
(*edge_count)++;
}
}
}
void random_maze_prim(maze* m) {
srand(time(NULL));
int total_cells = m->hsize * m->vsize;
bool* visited = (bool*)calloc(total_cells, sizeof(bool));
edge* edges = (edge*)malloc(total_cells * 4 * sizeof(edge)); // Maximum 4 arêtes par cellule
int edge_count = 0;
// Initialisation de la cellule de départ
int start_cell = get_start_cell(m);
visited[start_cell] = true;
// Ajouter toutes les arêtes issues de cette cellule à l'ensemble des arêtes à traiter
add_edges(m, start_cell, edges, &edge_count);
// Tant qu'il reste des arêtes à traiter
while (edge_count > 0) {
// Choisir une arête aléatoirement et la retirer de l'ensemble des arêtes à traiter
int rand_index = rand() % edge_count;
edge chosen_edge = edges[rand_index];
edges[rand_index] = edges[--edge_count];
int cell1 = chosen_edge.cell1;
int cell2 = chosen_edge.cell2;
cardinal dir = chosen_edge.dir;
// Si la cellule vers laquelle mène cette arête n'a pas encore été visitée
if (!visited[cell2]) {
// Casser le mur correspondant à l'arête
del_wall_maze(m, cell1, dir);
del_wall_maze(m, cell2, (dir + 2) % 4); // Casser le mur opposé
fflush(stdout);
// Ajouter la cellule à l'ensemble des cellules visitées
visited[cell2] = true;
// Ajouter toutes les arêtes issues de cette cellule à l'ensemble des arêtes à traiter
add_edges(m, cell2, edges, &edge_count);
}
}
free(visited);
free(edges);
}
void random_maze_kruskal(maze* lab) {
if (lab == NULL) {
ERROR("Pointeur de labyrinthe null");
}
// On crée une partition triviale de l'enemble des cellules
ufind* uf_cell = create_ufind(lab->hsize * lab->vsize);
// On crée un tableau pour stocker les arêtes
edge* tab_edges = malloc(lab->hsize * lab->vsize * 4 * sizeof(edge)); // Maximum 4 arêtes par cellule
// On fait parcours toutes les cellules pour ajouter les arêtes entre les cellules accessibles
int edge_count = 0;
for (int i = 0; i < lab->hsize * lab->vsize; i++) {
// On ajoute les arêtes de la cellule i si i est accessible
if (is_reach_maze(lab, i)) {
add_edges(lab, i, tab_edges, &edge_count);
}
}
// Tant qu'il reste des arêtes à traiter
while (edge_count > 0) {
// Choisir une arête aléatoirement et la retirer de l'ensemble des arêtes à traiter
int rand_index = rand() % edge_count;
edge chosen_edge = tab_edges[rand_index];
// On remplace l'arête choisie par la dernière arête du tableau
tab_edges[rand_index] = tab_edges[edge_count - 1];
edge_count--;
// On récupère les cellules et la direction de l'arête
int cell1 = chosen_edge.cell1;
int cell2 = chosen_edge.cell2;
cardinal dir = chosen_edge.dir; // Cell1 -> cell2
// Si les deux cellules ne sont pas dans la même classe
if (find_ufind(cell1, uf_cell) != find_ufind(cell2, uf_cell)) {
// Casser le mur correspondant à l'arête
del_wall_maze(lab, cell1, dir);
// Fusionner les deux classes
union_ufind(cell1, cell2, uf_cell);
}
}
// On free la partition et le tableau des arêtes
delete_ufind(uf_cell);
free(tab_edges);
}
void random_maze_rec(maze* m) {
// Initialiser le générateur de nombres aléatoires
srand(time(NULL));
// Définir une pile pour gérer la récursion manuellement
typedef struct {
int x, y, width, height;
} Region;
// Taille maximale de la pile (au pire des cas, on divise chaque cellule individuellement)
int max_stack_size = m->hsize * m->vsize;
Region* stack = (Region*)malloc(max_stack_size * sizeof(Region));
int stack_size = 0;
// Pousser la région initiale sur la pile
stack[stack_size++] = (Region){0, 0, m->hsize, m->vsize};
// Boucle principale pour traiter la pile
while (stack_size > 0) {
// Pop une région de la pile
Region current = stack[--stack_size];
// Cas de base: si la région est réduite à une seule cellule, on ne fait rien
if (current.width <= 1 && current.height <= 1) {
continue;
}
// Choisir de diviser horizontalement ou verticalement
if (current.height >= current.width) {
// Diviser horizontalement
int divide_line = current.y + current.height / 2;
// Pousser les deux nouvelles régions sur la pile
stack[stack_size++] = (Region){current.x, current.y, current.width, divide_line - current.y};
stack[stack_size++] = (Region){current.x, divide_line, current.width, current.y + current.height - divide_line};
// Casser un mur aléatoirement sur la ligne de séparation
int random_x = current.x + rand() % current.width;
del_wall_maze(m, divide_line * m->hsize + random_x, NORTH);
} else {
// Diviser verticalement
int divide_column = current.x + current.width / 2;
// Pousser les deux nouvelles régions sur la pile
stack[stack_size++] = (Region){current.x, current.y, divide_column - current.x, current.height};
stack[stack_size++] = (Region){divide_column, current.y, current.x + current.width - divide_column, current.height};
// Casser un mur aléatoirement sur la colonne de séparation
int random_y = current.y + rand() % current.height;
del_wall_maze(m, random_y * m->hsize + divide_column, WEST);
}
}
// Libérer la mémoire allouée pour la pile
free(stack);
}

178
Aloyse et Anna/maze_masks.c Normal file
View File

@@ -0,0 +1,178 @@
#include "maze_masks.h"
#include <stdio.h>
#include <string.h>
#include "error.h"
/***********************/
/*+ Fonctions de base +*/
/***********************/
mask* create_empty_mask(int hsize, int vsize) {
// Vérification des paramètres
if (hsize <= 0 || vsize <= 0) {
ERROR("dimensions invalides pour le masque\n");
return NULL;
}
// Allocation mémoire pour le masque
mask* m = malloc(sizeof(mask));
if (m == NULL) {
ERROR("Erreur d'allocation mémoire pour le masque");
}
// Initialisation des dimensions
m->hsize = hsize;
m->vsize = vsize;
m->nbmasked = 0;
// Initialisation de la grille
m->grid = malloc(hsize * vsize * sizeof(bool));
if (m->grid == NULL) {
ERROR("Erreur d'allocation mémoire pour la grille du masque");
free(m); // Libération la structure
}
for (int i = 0; i < hsize * vsize; i++) {
m->grid[i] = false; // Initialisation à faux
}
return m;
}
void free_mask(mask* m) {
// Vérification des paramètres
if (m == NULL) {
return;
}
free(m->grid);
free(m);
}
void resize_mask(mask* m, int new_hsize, int new_vsize) {
// Vérification des paramètres
if (!m || new_hsize <= 0 || new_vsize <= 0) {
ERROR("dimensions invalides ou masque NULL\n");
}
// Allocation de la nouvelle grille
bool* new_grid = malloc(new_hsize * new_vsize * sizeof(bool));
if (new_grid == NULL) {
ERROR("allocation de la grille de masquage échouée\n");
}
// Échelles de redimensionnement
double scale_x = (double)m->hsize / new_hsize;
double scale_y = (double)m->vsize / new_vsize;
// Remplissage de la nouvelle grille en conservant le motif
for (int new_y = 0; new_y < new_vsize; ++new_y) {
for (int new_x = 0; new_x < new_hsize; ++new_x) {
// Calcul de l'abcsisse dans dans l'ancienne grille
int old_x = (int)(new_x * scale_x);
// Calcul de l'ordonnée dans l'ancienne grille
int old_y = (int)(new_y * scale_y);
// Copie dans la nouvelle cellule la valeur de la cellule trouvée dans l'ancienne grille
new_grid[new_y * new_hsize + new_x] = m->grid[old_y * m->hsize + old_x];
}
}
// Libération de l'ancienne grille
free(m->grid);
// Mise à jour des dimensions et de la grille
m->grid = new_grid;
m->hsize = new_hsize;
m->vsize = new_vsize;
// Recalcul du nombre de cellules masquées
m->nbmasked = 0;
for (int i = 0; i < new_hsize * new_vsize; ++i) {
if (m->grid[i]) {
m->nbmasked++;
}
}
// Vérification qu'au moins une cellule reste non masquée
if (m->nbmasked == new_hsize * new_vsize) {
m->grid[0] = false;
}
}
void print_mask(mask* m) {
// Vérification des paramètres
if (m == NULL) {
ERROR("Le masque est NULL.\n");
return;
}
// Parcours du masque ligne par ligne
for (int i = 0; i < m->vsize; i++) {
for (int j = 0; j < m->hsize; j++) {
int index = i * m->hsize + j; // Calcul de l'indice dans le tableau 1D
if (m->grid[index]) {
printf("X"); // Cellule masquée
} else {
printf("."); // Cellule non-masquée
}
}
printf("\n"); // Nouvelle ligne après chaque ligne du masque
}
}
/**************************************/
/*+ Génération à partir d'un fichier +*/
/**************************************/
mask* read_mask(const char* file) {
// Ouverture du fichier en lecture
FILE* f = fopen(file, "r");
int countv = 1;
int count_total = 0;
int c = fgetc(f);
while (c != EOF) {
int d = fgetc(f);
if (c == '\n' && d != EOF) {
countv++;
}
count_total++;
c = d;
}
count_total -= countv - 1;
int counth = count_total / countv;
mask* m = create_empty_mask(counth, countv);
m->hsize = counth;
m->vsize = countv;
m->grid = malloc(counth * countv * sizeof(bool));
for (int i = 0; i < counth * countv; i++) {
m->grid[i] = false;
}
fseek(f, 0, SEEK_SET);
int c1 = fgetc(f);
int i = 0;
while (c1 != EOF && i < counth * countv) {
if (c1 != '\n') {
if (c1 == 'X') {
m->grid[i] = true;
m->nbmasked++;
}
i++;
}
c1 = fgetc(f);
}
if (m->nbmasked == counth * countv) {
ERROR("toutes les cellules sont masquées après la lecture du fichier\n");
free(m->grid);
m->grid = NULL;
}
fclose(f);
return m;
}

518
Aloyse et Anna/solve.c Normal file
View File

@@ -0,0 +1,518 @@
#include "solve.h"
#include <stdio.h>
#include <stdlib.h>
#include "data_queue.h"
#include "error.h"
#include "maze.h"
/***************************************************/
/*+ Définition et manipulation d'un chemin simple **/
/***************************************************/
sim_path* sim_emptypath(int start) {
sim_path* chm = malloc(sizeof(sim_path));
if (chm == NULL) {
ERROR("Erreur d'allocation de mémoire pour le chemin \n");
return NULL;
}
chm->start = start;
chm->end = start;
chm->length = 0;
chm->moves = NULL;
return chm;
}
void sim_addtopath(maze* m, move dir, sim_path* chm) {
// Création d'un nouveau mouvement
sim_move_seq* new_move = malloc(sizeof(sim_move_seq));
if (new_move == NULL) {
ERROR("Erreur d'allocation de mémoire pour le mouvement \n");
return;
}
new_move->direction = dir;
new_move->next = chm->moves;
// Met à jour le chemin
chm->moves = new_move;
// Met à jour la cellule de départ
int new_start = get_adj_maze(m, chm->start, (cardinal)((dir + 2) % 4));
if (new_start != -1) {
chm->start = new_start;
chm->length++;
} else {
ERROR("Mouvement invalide \n");
// Restaure le chemin et libère la mémoire
chm->moves = new_move->next;
free(new_move);
}
}
sim_path* sim_copypath(sim_path* chm) {
sim_path* new_chm = malloc(sizeof(sim_path));
if (new_chm == NULL) {
ERROR("Erreur d'allocation de mémoire pour le chemin \n");
return NULL;
}
new_chm->start = chm->start;
new_chm->end = chm->end;
new_chm->length = chm->length;
new_chm->moves = NULL;
sim_move_seq* current = chm->moves;
sim_move_seq* new_current = NULL;
while (current != NULL) {
sim_move_seq* new_move = malloc(sizeof(sim_move_seq));
if (new_move == NULL) {
ERROR("Erreur d'allocation de mémoire pour le mouvement \n");
return NULL;
}
new_move->direction = current->direction;
new_move->next = NULL;
if (new_current == NULL) {
new_chm->moves = new_move;
} else {
new_current->next = new_move;
}
new_current = new_move;
current = current->next;
}
return new_chm;
}
void sim_freepath(sim_path* chm) {
if (chm == NULL) {
return;
}
// Libérer chaque nœud de la liste chaînée des mouvements
sim_move_seq* current = chm->moves;
while (current != NULL) {
sim_move_seq* next = current->next;
free(current);
current = next;
}
// Libérer la structure sim_path
free(chm);
}
/**********************************************/
/*+ Définition et manipulation d'un parcours **/
/**********************************************/
const char* salgo_names[ALG_SIZE] = {"BFS", "DFS", "A*"};
const char* sgoal_names[GOA_SIZE] = {"Trésor", "Bombe", "Poly d'algo", "Sortie"};
sim_search* sim_create_search(sim_algorithm algo, sim_goal goal) {
// Allouer de la mémoire pour la nouvelle structure sim_search
sim_search* search = malloc(sizeof(sim_search));
if (search == NULL) {
ERROR("Erreur d'allocation de mémoire pour sim_search\n");
return NULL;
}
// Initialiser les champs de la structure
search->algo = algo;
search->goal = goal;
search->search = create_dyn(); // Créer un tableau dynamique pour les sommets visités
if (search->search == NULL) {
ERROR("Erreur d'allocation de mémoire pour le tableau dynamique\n");
free(search);
return NULL;
}
// Le chemin sera calculé plus tard
search->path = NULL;
return search;
}
void sim_free_search(sim_search* search) {
if (search == NULL) {
return;
}
// Libérer le tableau dynamique des sommets visités
if (search->search != NULL) {
free_dyn(search->search);
}
// Libérer le chemin trouvé
if (search->path != NULL) {
sim_freepath(search->path);
}
// Libérer la structure sim_search
free(search);
}
/******************************************************************/
/*+ Les heuristiques (uniquement utilisées par l'algorithme A*) **/
/******************************************************************/
// Tableau des noms de stratégies (pour l'affichage)
const char* heu_names[HEU_SIZE] = {"Neutre", "Manhattan", "Eviter les minotaures"};
// Tableau des fonctions heuristiques
int (*heu_funs[HEU_SIZE])(game*, int, dynarray*) = {&astar_none, &astar_manhattan, &astar_runaway};
int astar_none(game* g, int cell, dynarray* goals) {
// Ce comporte deja comme un BFS a cause de esti qui es incrementer de 1 a chaque fois par cost donc la priorité est assuré par le cout
// Pour eviter les warnings
int x1 = cell % g->m->hsize;
int y1 = cell / g->m->hsize;
size_dyn(goals);
return y1 * 0 + x1 * 0;
}
int astar_manhattan(game* g, int cell, dynarray* goals) {
// Récupérer les coordonnées de la cellule actuelle
int x1 = cell % g->m->hsize;
int y1 = cell / g->m->hsize;
int min_distance = g->m->hsize * g->m->vsize;
// Parcourir toutes les cellules cibles pour trouver la plus proche
for (int i = 0; i < size_dyn(goals); i++) {
int goal = goals->array[i];
int x2 = goal % g->m->hsize;
int y2 = goal / g->m->hsize;
// Calculer la distance de Manhattan
int distance = abs(x1 - x2) + abs(y1 - y2);
// Mettre à jour la distance minimale
if (distance < min_distance) {
min_distance = distance;
}
}
return min_distance;
}
int astar_runaway(game* g, int cell, dynarray* goals) {
// Utiliser astar_manhattan pour calculer la distance de Manhattan à la cellule cible la plus proche
int min_distance = astar_manhattan(g, cell, goals);
// Récupérer les coordonnées de la cellule actuelle
int x1 = cell % g->m->hsize;
int y1 = cell / g->m->hsize;
// Ajouter une pénalité pour les minotaures proches
int penalty = 0;
for (int i = 0; i < g->m->nb_minotaurs; i++) {
if (g->minotaurs_alive[i]) {
int minotaur = g->m->minotaurs[i];
int x2 = minotaur % g->m->hsize;
int y2 = minotaur / g->m->hsize;
// Calculer la distance de Manhattan au minotaur
int distance = abs(x1 - x2) + abs(y1 - y2);
// Ajouter une pénalité inversement proportionnelle à la distance
if (distance > 0) {
penalty += 10 / distance;
}
}
}
return min_distance + penalty;
}
/*********************************/
/*+ Les algorithmes de parcours **/
/*********************************/
sim_search* (*salgo_funs[ALG_SIZE])(game*, int, sim_goal, int(heu_fun)(game*, int, dynarray*), bool) = {&sim_bfs, &sim_dfs, &sim_astar};
// Fonction pour reconstituer le chemin menant à une cellule
static sim_path* reconstruct_path(maze* m, int start, int end, int* parents) {
// Alloue de la mémoire pour le chemin
sim_path* chm = malloc(sizeof(sim_path));
chm->start = end;
chm->end = end;
chm->length = 0;
chm->moves = NULL;
// Reconstitue le chemin en remontant depuis la cellule de fin jusqu'à la cellule de départ
int current = end;
while (current != start) {
int parent = parents[current];
move direction;
// Détermine la direction du mouvement en comparant la cellule actuelle avec son parent
if (parent == current - 1) {
direction = M_EAST;
} else if (parent == current + 1) {
direction = M_WEST;
} else if (parent == current - m->hsize) {
direction = M_SOUTH;
} else if (parent == current + m->hsize) {
direction = M_NORTH;
}
// Ajoute le mouvement au début du chemin
sim_addtopath(m, direction, chm);
current = parent;
}
return chm;
}
// Fonction de conversion de sim_goal à object
static sim_goal convert_object_to_goal(object obj) {
switch (obj) {
case SMALLT:
case MEDT:
case LARGET:
return GOA_TREASURE;
case BOMB:
return GOA_BOMB;
case POLY:
return GOA_POLY;
case EXIT:
return GOA_EXIT;
default:
return GOA_SIZE; // Utiliser une valeur spéciale pour indiquer qu'il n'y a pas d'objet
}
}
sim_search* sim_bfs(game* g, int start, sim_goal goal, int (*heu_fun)(game*, int, dynarray*), bool consider_minotaurs) {
maze* m = g->m;
// Crée une file vide et y enfile la cellule de départ
queue* q = create_queue();
enqueue(start, q);
// Initialise un tableau pour garder trace des cellules visitées
bool* visited = malloc(m->hsize * m->vsize * sizeof(bool));
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
// Initialise un tableau pour garder trace des parents de chaque cellule
int* parents = malloc(m->hsize * m->vsize * sizeof(int));
for (int i = 0; i < m->hsize * m->vsize; i++) {
parents[i] = -2;
}
// Initialise un tableau dynamique pour garder l'ordre des cellules visitées
dynarray* search_order = create_dyn();
sim_path* found_path = NULL;
// Utilisation du paramètre heu_fun pour éviter l'avertissement de compilation
if (heu_fun != NULL) {
heu_fun(g, start, search_order);
}
// Boucle principale du DFS
while (!is_empty_queue(q)) {
// Défile une cellule de la file
int cell = dequeue(q);
// Si la cellule a déjà été visitée, passe au tour de boucle suivant
if (!visited[cell]) {
// Ajoute la cellule à l'ordre des cellules visitées
push_dyn(cell, search_order);
// Si la cellule contient l'objet recherché, reconstitue le chemin et termine le parcours
if (convert_object_to_goal(get_object_maze(m, cell)) == goal) {
found_path = reconstruct_path(m, start, cell, parents);
break;
}
// Marque la cellule comme visitée
visited[cell] = true;
// Enfile toutes les cellules accessibles depuis la cellule actuelle
for (int dir = 0; dir < 4; dir++) {
int adj = get_adj_maze(m, cell, (cardinal)dir);
if (adj != -1 && !visited[adj] && !has_wall_maze(m, cell, (cardinal)dir) && valid_maze(m, adj) && is_reach_maze(m, adj)) {
if (((consider_minotaurs == false) || (consider_minotaurs == true && has_minotaur_maze(m, adj) == -1))) {
enqueue(adj, q);
parents[adj] = cell;
}
}
}
}
}
// Crée un objet sim_search pour stocker les résultats du parcours
sim_search* result = (sim_search*)malloc(sizeof(sim_search));
result->algo = ALG_BFS;
result->goal = goal;
result->search = search_order;
result->path = found_path;
// Libère la mémoire allouée pour les tableaux visited et parents, et la file q
free(visited);
free(parents);
delete_queue(q);
return result;
}
sim_search* sim_dfs(game* g, int start, sim_goal goal, int (*heu_fun)(game*, int, dynarray*), bool consider_minotaurs) {
maze* m = g->m;
// Crée une file vide et y enfile la cellule de départ
dynarray* s = create_dyn();
push_dyn(start, s);
// Initialise un tableau pour garder trace des cellules visitées
bool* visited = malloc(m->hsize * m->vsize * sizeof(bool));
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
// Initialise un tableau pour garder trace des parents de chaque cellule
int* parents = malloc(m->hsize * m->vsize * sizeof(int));
for (int i = 0; i < m->hsize * m->vsize; i++) {
parents[i] = -2;
}
// Initialise un tableau dynamique pour garder l'ordre des cellules visitées
dynarray* search_order = create_dyn();
sim_path* found_path = NULL;
// Utilisation du paramètre heu_fun pour éviter l'avertissement de compilation
if (heu_fun != NULL) {
heu_fun(g, start, search_order);
}
// Boucle principale du BFS
while (!is_empty_dyn(s)) {
// Défile une cellule de la file
int cell = pop_dyn(s);
// Si la cellule a déjà été visitée, passe au tour de boucle suivant
if (!visited[cell]) {
// Ajoute la cellule à l'ordre des cellules visitées
push_dyn(cell, search_order);
// Si la cellule contient l'objet recherché, reconstitue le chemin et termine le parcours
if (convert_object_to_goal(get_object_maze(m, cell)) == goal) {
found_path = reconstruct_path(m, start, cell, parents);
break;
}
// Marque la cellule comme visitée
visited[cell] = true;
// Enfile toutes les cellules accessibles depuis la cellule actuelle
for (int dir = 0; dir < 4; dir++) {
int adj = get_adj_maze(m, cell, (cardinal)dir);
if (adj != -1 && !visited[adj] && !has_wall_maze(m, cell, (cardinal)dir) && valid_maze(m, adj) && is_reach_maze(m, adj)) {
if (((consider_minotaurs == false) || (consider_minotaurs == true && has_minotaur_maze(m, adj) == -1))) {
push_dyn(adj, s);
parents[adj] = cell;
}
}
}
}
}
// Crée un objet sim_search pour stocker les résultats du parcours
sim_search* result = (sim_search*)malloc(sizeof(sim_search));
result->algo = ALG_DFS;
result->goal = goal;
result->search = search_order;
result->path = found_path;
// Libère la mémoire allouée pour les tableaux visited et parents, et la file q
free(visited);
free(parents);
free_dyn(s);
return result;
}
// Structure pour stocker les informations nécessaires pour chaque cellule dans le tas binaire
typedef struct {
int cell; // Numéro de la cellule
int cost; // Coût pour atteindre cette cellule
int esti; // Estimation du coût total (cost + heuristique)
} astar_node;
// Fonction de comparaison pour le tas binaire
static int compare_astar_nodes(void* a, void* b) {
astar_node* node_a = (astar_node*)a;
astar_node* node_b = (astar_node*)b;
return node_a->esti - node_b->esti;
}
sim_search* sim_astar(game* g, int start, sim_goal goal, int (*heuristique)(game*, int, dynarray*), bool consider_minotaurs) {
maze* m = g->m;
// Crée un tas binaire vide
binheap* open_set = create_binheap(compare_astar_nodes);
// Initialise un tableau pour garder trace des cellules visitées
bool* visited = malloc(m->hsize * m->vsize * sizeof(bool));
// Initialise un tableau pour garder trace des parents de chaque cellule
int* parents = malloc(m->hsize * m->vsize * sizeof(int));
// Initialise un tableau pour garder trace des coûts pour atteindre chaque cellule
int* cost = malloc(m->hsize * m->vsize * sizeof(int));
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
parents[i] = -2;
cost[i] = m->hsize * m->vsize;
}
// Initialise un tableau dynamique pour garder l'ordre des cellules visitées
dynarray* search_order = create_dyn();
sim_path* found_path = NULL;
dynarray* goals = create_dyn();
for (int i = 0; i < m->hsize * m->vsize; i++) {
if (convert_object_to_goal(get_object_maze(m, i)) == goal) {
push_dyn(i, goals);
}
}
// Initialisation de la cellule de départ
astar_node* start_node = malloc(sizeof(astar_node));
start_node->cell = start;
start_node->cost = 0;
start_node->esti = heuristique(g, start, goals);
push_binheap(open_set, start_node);
cost[start] = 0;
// Parcours du labyrinthe
while (!isempty_binheap(open_set)) {
astar_node* current_node = popmin_binheap(open_set);
int current = current_node->cell;
free(current_node);
if (!visited[current]) {
// Ajoute la cellule à l'ordre des cellules visitées
push_dyn(current, search_order);
visited[current] = true;
// Vérifie si l'objectif est atteint
if (convert_object_to_goal(get_object_maze(m, current)) == goal) {
found_path = reconstruct_path(m, start, current, parents);
break;
}
// Exploration des cellules adjacentes
for (int dir = 0; dir < 4; dir++) {
int adj = get_adj_maze(m, current, (cardinal)dir);
if (adj != -1 && !visited[adj] && !has_wall_maze(m, current, (cardinal)dir) && valid_maze(m, adj) && is_reach_maze(m, adj)) {
if (((consider_minotaurs == false) || (consider_minotaurs == true && has_minotaur_maze(m, adj) == -1))) {
int new_cost = cost[current] + 1;
if (new_cost < cost[adj]) {
cost[adj] = new_cost;
parents[adj] = current;
astar_node* adj_node = malloc(sizeof(astar_node));
adj_node->cell = adj;
adj_node->cost = new_cost;
adj_node->esti = new_cost + heuristique(g, adj, goals);
push_binheap(open_set, adj_node);
}
}
}
}
}
}
sim_search* search_result = sim_create_search(ALG_AST, goal);
search_result->path = found_path;
search_result->search = search_order;
free(visited);
free(cost);
free(parents);
delete_binheap(open_set);
return search_result;
}

128
Aloyse et Anna/solve_adv.c Normal file
View File

@@ -0,0 +1,128 @@
#include "solve_adv.h"
cmp_search* (*cmp_funs[CMP_SIZE])(game*) = {&cmp_taketreasures, &cmp_avoidminotaurs};
const char* cmp_names[CMP_SIZE] = {"Récupération de tous les trésors", "Eviter les minotaures"};
void cmp_free(cmp_search* chm_com) {
if (chm_com == NULL) {
return;
}
free(chm_com->array);
free(chm_com);
}
cmp_search* cmp_taketreasures(game* g) {
maze* m = g->m;
cmp_search* chm_com = malloc(sizeof(cmp_search));
if (chm_com == NULL) {
ERROR("Erreur d'allocation de mémoire pour cmp_search\n");
return NULL;
}
// Tableau avec les tresors
int* goals_cell = malloc(m->hsize * m->vsize * sizeof(int));
int* goals_object = malloc(m->hsize * m->vsize * sizeof(object));
int indice = 0;
int count = 0;
for (int i = 0; i < m->hsize * m->vsize; i++) {
if (get_object_maze(m, i) == SMALLT || get_object_maze(m, i) == MEDT || get_object_maze(m, i) == LARGET) {
count++;
goals_cell[indice] = i;
goals_object[indice] = get_object_maze(m, i);
indice++;
}
}
goals_cell = realloc(goals_cell, count * sizeof(int));
goals_object = realloc(goals_object, count * sizeof(object));
chm_com->array = malloc((count + 1) * sizeof(sim_path*));
chm_com->algo = CMP_TREAS;
chm_com->size = 0;
int start = m->player;
for (int i = 0; i < count; i++) {
sim_search* chm = sim_astar(g, start, GOA_TREASURE, &astar_manhattan, false);
if (chm == NULL) {
ERROR("Erreur de calcul du chemin\n");
return NULL;
}
chm_com->array[i] = chm->path;
chm_com->size++;
start = chm->path->end;
chm_com->length += chm->path->length;
int cell_treasure = chm->path->end;
add_object_maze(m, cell_treasure, NONE);
}
sim_search* chm = sim_astar(g, start, GOA_EXIT, &astar_manhattan, false);
chm_com->array[count] = chm->path;
chm_com->size++;
chm_com->length += chm->path->length;
// Remettre les tresors
for (int i = 0; i < count; i++) {
add_object_maze(m, goals_cell[i], goals_object[i]);
}
free(goals_cell);
free(goals_object);
return chm_com;
}
cmp_search* cmp_avoidminotaurs(game* g) {
maze* m = g->m;
cmp_search* chm_com = malloc(sizeof(cmp_search));
if (chm_com == NULL) {
ERROR("Erreur d'allocation de mémoire pour cmp_search\n");
return NULL;
}
// Tableau avec les tresors
int* goals_cell = malloc(m->hsize * m->vsize * sizeof(int));
int* goals_object = malloc(m->hsize * m->vsize * sizeof(object));
int indice = 0;
int count = 0;
for (int i = 0; i < m->hsize * m->vsize; i++) {
if (get_object_maze(m, i) == SMALLT || get_object_maze(m, i) == MEDT || get_object_maze(m, i) == LARGET) {
count++;
goals_cell[indice] = i;
goals_object[indice] = get_object_maze(m, i);
indice++;
}
}
goals_cell = realloc(goals_cell, count * sizeof(int));
goals_object = realloc(goals_object, count * sizeof(object));
chm_com->array = malloc((count + 1) * sizeof(sim_path*));
chm_com->algo = CMP_TREAS;
chm_com->size = 0;
int start = m->player;
for (int i = 0; i < count; i++) {
sim_search* chm = sim_astar(g, start, GOA_TREASURE, &astar_runaway, false);
if (chm == NULL) {
ERROR("Erreur de calcul du chemin\n");
return NULL;
}
chm_com->array[i] = chm->path;
chm_com->size++;
start = chm->path->end;
chm_com->length += chm->path->length;
int cell_treasure = chm->path->end;
add_object_maze(m, cell_treasure, NONE);
}
sim_search* chm = sim_astar(g, start, GOA_EXIT, &astar_runaway, false);
chm_com->array[count] = chm->path;
chm_com->size++;
chm_com->length += chm->path->length;
// Remettre les tresors
for (int i = 0; i < count; i++) {
add_object_maze(m, goals_cell[i], goals_object[i]);
}
free(goals_cell);
free(goals_object);
return chm_com;
}