Files
algo-labyrinthes-giiiiive/Aloyse et Anna/solve.c
Anna Mielcarek a4703085b6 Aloyse et Anna
j'ai push pas mal de fichier envoyer un message si vous en voulez un aute
2024-12-12 16:22:28 +01:00

519 lines
18 KiB
C

#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;
}