Aloyse et Anna
j'ai push pas mal de fichier envoyer un message si vous en voulez un aute
This commit is contained in:
146
Aloyse et Anna/data_queue_turn.h
Normal file
146
Aloyse et Anna/data_queue_turn.h
Normal 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
541
Aloyse et Anna/game.c
Normal 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;
|
||||
}
|
||||
110
Aloyse et Anna/game_history.c
Normal file
110
Aloyse et Anna/game_history.c
Normal 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
595
Aloyse et Anna/maze_gen.c
Normal 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
178
Aloyse et Anna/maze_masks.c
Normal 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
518
Aloyse et Anna/solve.c
Normal 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
128
Aloyse et Anna/solve_adv.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user