ajouts des fichiers perso

Le plagiat c'est mal donc gare à vos culs
This commit is contained in:
Vincent BRUNEAU
2024-12-12 14:07:36 +01:00
parent 317e9f7bbc
commit cdddaa6239
8 changed files with 2195 additions and 0 deletions

496
game/game_VM.c Normal file
View File

@@ -0,0 +1,496 @@
#include "game.h"
#include <sys/random.h>
#include "maze_2.h"
#define CHECK_ALLOC(ptr) do { if (ptr == NULL) { fprintf(stderr, "Erreur d'allocation\n"); exit(EXIT_FAILURE); } } while(0)
/****************************/
/*+ Création et libération +*/
/****************************/
// Génération d'un nouveau jeu
game* create_newgame(const int sh, const int sv, mask *m, const generator f, const objgenerator fo, const int nb_minotaure, const int tressage)
{
maze *p_maze;
if(m != NULL)
{
resize_mask(m, sh, sv);
p_maze = create_proto_maze(m);
}
else
{
p_maze = create_proto_maze_nomask(sh, sv);
}
gen_minotaurs_maze(p_maze, nb_minotaure);
(*gen_funs[f]) (p_maze);
(*obj_funs[fo]) (p_maze);
braid_maze(p_maze, tressage);
game *p_game = malloc(sizeof(game));
CHECK_ALLOC(p_game);
p_game->m = p_maze;
p_game->score = 0;
p_game->nbombs = 0;
p_game->npolys = 0;
p_game->player_alive = true;
p_game->player_dir = NORTH;
p_game->minotaurs_alive = malloc(nb_minotaure * sizeof(bool));
CHECK_ALLOC(p_game->minotaurs_alive);
for(int i = 0; i < nb_minotaure; i++)
{
p_game->minotaurs_alive[i] = true;
}
p_game->minotaurs_dirs = calloc(nb_minotaure, sizeof(cardinal));
CHECK_ALLOC(p_game->minotaurs_dirs);
p_game->nb_deadends = count_dead_ends(p_maze);
p_game->exits = get_exits_maze(p_maze);
p_game->turns = 0;
p_game->log = create_history();
int start = p_maze->player;
cardinal useless;
while ((game_try_kill_player(p_game, &useless) != -1 && p_game->m->nb_minotaurs < p_game->m->nb_reachable - 10)
|| get_object_maze(p_game->m, start) == EXIT || !can_be_used(p_game->m, start))
{
//on évite le spawn kill et le spawn win (cntraite du nombre de minotaures car faut pas forcer non plus)
getrandom(&start, sizeof(start), 0);
start %= p_game->m->hsize * p_game->m->vsize;
}
free_occupied_maze(p_game->m, p_game->m->player);
p_game->m->player = start;
make_occupied_maze(p_game->m, start);
return p_game;
}
void free_game(game *g) {
free_history(g->log);
free(g->minotaurs_alive);
free(g->minotaurs_dirs);
free_maze(g->m);
free(g);
}
/***********************************************/
/*+ Implémentation des attaques de minotaures +*/
/***********************************************/
// ReSharper disable CppDFANullDereference
int game_try_kill_player(game *g, cardinal *card) {
const int cell = g->m->player;
int neighbour = get_adj_maze(g->m, cell, NORTH);
if(neighbour != -1) {
const int mino = has_minotaur_maze(g->m, neighbour);
if(mino != -1 && g->minotaurs_alive[mino] && !has_wall_maze(g->m, cell, NORTH)) {
*card = SOUTH;
g->minotaurs_dirs[mino] = NORTH;
g->player_alive = false;
return mino;
}
}
neighbour = get_adj_maze(g->m, cell, EAST);
if(neighbour != -1) {
const int mino = has_minotaur_maze(g->m, neighbour);
if(mino != -1 && g->minotaurs_alive[mino] && !has_wall_maze(g->m, cell, EAST)) {
*card = WEST;
g->minotaurs_dirs[mino] = EAST;
g->player_alive = false;
return mino;
}
}
neighbour = get_adj_maze(g->m, cell, SOUTH);
if(neighbour != -1) {
const int mino = has_minotaur_maze(g->m, neighbour);
if(mino != -1 && g->minotaurs_alive[mino] && !has_wall_maze(g->m, cell, SOUTH)) {
*card = NORTH;
g->player_alive = false;
g->minotaurs_dirs[mino] = SOUTH;
return mino;
}
}
neighbour = get_adj_maze(g->m, cell, WEST);
if(neighbour != -1) {
const int mino = has_minotaur_maze(g->m, neighbour);
if(mino != -1 && g->minotaurs_alive[mino] && !has_wall_maze(g->m, cell, WEST)) {
*card = EAST;
g->minotaurs_dirs[mino] = WEST;
g->player_alive = false;
return mino;
}
}
//on n'a pas trouvé de minotaure
return -1;
}
// ReSharper restore CppDFANullDereference
/***************************/
/*+ Traitement des objets +*/
/***************************/
void game_consume_object(game *g, const int iter, const object obj) {
switch (obj) {
case SMALLT:
g->score += iter * VALSMALL;
break;
case MEDT:
g->score += iter * VALMED;
break;
case LARGET:
g->score += iter * VALLARGE;
break;
case BOMB:
g->nbombs += iter;
break;
case POLY:
g->npolys += iter;
break;
default: //inclue EXIT et NONE
break;
}
}
object game_treat_object(game *g) {
const int cell = g->m->player;
const object obj = get_object_maze(g->m, cell);
game_consume_object(g, 1, obj);
if(obj != EXIT)
{
add_object_maze(g->m, cell, NONE);
}
return obj;
}
/**********************************************************/
/*+ Implémentation d'une demande de mouvement du joueur +*/
/**********************************************************/
bool implement_game_move(game *g, const move mv, const strategy strat) {
if (mv != M_WAIT)
{
g->player_dir = (cardinal)mv;
}
if (!g->player_alive || !valid_move_maze(g->m, g->m->player, mv))
{
return false;
}
if (mv != M_WAIT)
{
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, g->player_dir);
make_occupied_maze(g->m, g->m->player);
}
move *mino_move = malloc(g->m->nb_minotaurs * sizeof(move));
str_funs[strat](g->m, mv, mino_move);
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (mino_move[i] != M_WAIT)
{
g->minotaurs_dirs[i] = (cardinal)mino_move[i];
}
if (g->minotaurs_alive[i] && valid_move_maze(g->m, g->m->minotaurs[i], mino_move[i]))
{
//si le mino veut et peut bouger
if (mino_move[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], g->minotaurs_dirs[i]);
make_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
else
{
mino_move[i] = M_WAIT; //on corrige le mouvement pour l'historique
}
}
const t_type typ = T_MOVE;
t_move *tmove = malloc(sizeof(t_move));
CHECK_ALLOC(tmove);
tmove->obj = game_treat_object(g);
tmove->playermove = mv;
tmove->minomoves = mino_move;
cardinal card = NORTH;
tmove->killer = game_try_kill_player(g, &card);
tmove->dirkill = card;
const turn t = {typ, .tmove = tmove};
add_entry_history(t, g->log);
g->turns++;
return true;
}
/*******************************/
/*+ Implémentation des bombes +*/
/*******************************/
bool game_bomb_wall(game *g) {
if (g->nbombs == 0 || !g->player_alive)
{
return false;
}
const int neighbour = get_adj_maze(g->m, g->m->player, g->player_dir);
if (!can_be_used(g->m, neighbour) || !has_wall_maze(g->m, g->m->player, g->player_dir))
{
return false;
}
g->nbombs--;
g->turns++;
del_wall_maze(g->m, g->m->player, g->player_dir);
const t_type typ = T_BOMB;
t_bomb *tbomb = malloc(sizeof(t_bomb));
CHECK_ALLOC(tbomb);
tbomb->bombdir = g->player_dir;
tbomb->destroyed = true;
cardinal card = NORTH;
tbomb->killer = game_try_kill_player(g, &card);
tbomb->dirkill = card;
const turn t = {typ, .tbomb = tbomb};
add_entry_history(t, g->log);
return true;
}
/*************************************/
/*+ Implémentation des polys d'algo +*/
/*************************************/
static bool mino_reachable(maze *p_maze, const int mino, const int cell, const int d)
{
if (!can_be_used(p_maze, cell))
{
return false;
}
if (mino == cell)
{
return true;
}
if (d == 0)
{
return false;
}
int c = get_adj_maze(p_maze, cell, NORTH);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, EAST);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, SOUTH);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, SOUTH);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, WEST);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, WEST);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, c, NORTH);
if (mino_reachable(p_maze, mino, c, d - 1))
{
return true;
}
c = get_adj_maze(p_maze, cell, NORTH);
return mino_reachable(p_maze, mino, c, d - 1);
}
bool game_kill_minotaurs(game *g, const int d) {
if (g->npolys == 0 || !g->player_alive)
{
return false;
}
const int cell = g->m->player;
bool done = false;
bool *minokilled = calloc(g->m->nb_minotaurs, sizeof(bool));
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (g->minotaurs_alive[i] && mino_reachable(g->m, g->m->minotaurs[i], cell, d))
{
g->minotaurs_alive[i] = false;
free_occupied_maze(g->m, g->m->minotaurs[i]);
done = true;
minokilled[i] = true;
}
}
if (!done)
{
free(minokilled);
return false;
}
g->npolys--;
g->turns++;
const t_type typ = T_POLY;
const turn t = {typ, .minokilled = minokilled};
add_entry_history(t, g->log);
return true;
}
/*****************************/
/*+ Gestion de l'historique +*/
/*****************************/
bool game_undo(game *g) {
const turn *t = last_move_history(g->log);
if (t == NULL)
{
return false;
}
if (t->type == T_POLY)
{
g->npolys++;
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (t->minokilled[i])
{
g->minotaurs_alive[i] = true;
make_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
g->turns--;
rewind_history(g->log); //on note que le tour a été annulé
return true;
}
if (t->type == T_BOMB)
{
if (t->tbomb->destroyed)
{
build_wall_maze(g->m, g->m->player, t->tbomb->bombdir);
g->nbombs++;
}
if (t->tbomb->killer != -1)
{
g->player_alive = true;
make_occupied_maze(g->m, g->m->player);
}
g->turns--;
rewind_history(g->log); //on note que le tour a été annulé
return true;
}
if (t->type == T_MOVE)
{
if (t->tmove->obj != NONE)
{
add_object_maze(g->m, g->m->player, t->tmove->obj);
game_consume_object(g, -1, t->tmove->obj);
}
if (t->tmove->killer != -1)
{
g->player_alive = true;
}
if (t->tmove->playermove != M_WAIT)
{
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)((t->tmove->playermove + 2) % 4));
make_occupied_maze(g->m, g->m->player);
}
g->minotaurs_dirs = (cardinal*)t->tmove->minomoves;
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (t->tmove->minomoves[i] != M_WAIT)
{
g->minotaurs_dirs[i] = (cardinal)t->tmove->minomoves[i]; //on met à jour les directions des minotaures
if (g->minotaurs_alive[i])
{
free_occupied_maze(g->m, g->m->minotaurs[i]);
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)((g->minotaurs_dirs[i] + 2) % 4));
make_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
}
g->turns--;
rewind_history(g->log); //on note que le tour a été annulé
return true;
}
fprintf(stderr, "Erreur d'historique, type inconnu\n");
exit(EXIT_FAILURE);
}
bool game_redo(game *g) {
const turn *t = next_move_history(g->log);
if (t == NULL)
{
return false;
}
if (t->type == T_POLY)
{
g->npolys--;
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (t->minokilled[i])
{
g->minotaurs_alive[i] = false;
free_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
g->turns++;
continue_history(g->log); //on note que le tour a été rejoué
return true;
}
if (t->type == T_BOMB)
{
if (t->tbomb->destroyed)
{
del_wall_maze(g->m, g->m->player, t->tbomb->bombdir);
g->player_dir = t->tbomb->bombdir;
g->nbombs--;
}
if (t->tbomb->killer != -1)
{
g->minotaurs_dirs[t->tbomb->killer] = t->tbomb->dirkill;
g->player_alive = false;
free_occupied_maze(g->m, g->m->player);
}
g->turns++;
continue_history(g->log); //on note que le tour a été rejoué
return true;
}
if (t->type == T_MOVE)
{
if (t->tmove->obj != NONE)
{
game_treat_object(g);
}
if (t->tmove->killer != -1)
{
g->player_alive = false;
}
if (t->tmove->playermove != M_WAIT)
{
free_occupied_maze(g->m, g->m->player);
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)t->tmove->playermove);
make_occupied_maze(g->m, g->m->player);
}
for (int i = 0; i < g->m->nb_minotaurs; i++)
{
if (t->tmove->minomoves[i] != M_WAIT)
{
g->minotaurs_dirs[i] = (cardinal)t->tmove->minomoves[i]; //on met à jour les directions des minotaures
if (g->minotaurs_alive[i])
{
free_occupied_maze(g->m, g->m->minotaurs[i]);
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)t->tmove->minomoves[i]);
make_occupied_maze(g->m, g->m->minotaurs[i]);
}
}
}
g->turns++;
continue_history(g->log); //on note que le tour a été rejoué
return true;
}
fprintf(stderr, "Erreur d'historique, type inconnu\n");
exit(EXIT_FAILURE);
}

View File

@@ -0,0 +1,264 @@
#include "game_history.h"
// La structure pour représenter un historique: à définir.
typedef struct history {
turn *past; // Les tours passés. (cyclique)
turn *future; // Les tours annulés.
int first_past; // L'indice du premier tour passé. (pour le cycle)
int size_past; // La taille de past.
int size_future; // La taille de future.
int capacity_past; // La capacité de past.
int capacity_future; // La capacité de future.
}
history;
history* create_history(void) {
history *h = malloc(sizeof(history));
if (h == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
h->past = malloc(sizeof(turn));
if (h->past == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
h->future = malloc(sizeof(turn));
if (h->future == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
h->size_past = 0;
h->size_future = 0;
h->first_past = 0;
h->capacity_past = 1;
h->capacity_future = 1;
return h;
}
//************************
//*+ Méthodes statiques +*
//************************
// * @brief
// * agrandit la taille effective de l'historique principal.
// */
static void grow_past(history *h) {
h->capacity_past *= 2;
if (h->capacity_past >= HISTORY_MAX) // Contrainte de taille.
{
h->capacity_past = HISTORY_MAX;
}
h->past = realloc(h->past, h->capacity_past * sizeof(turn));
if (h->past == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
}
// * @brief
// * agrandit la taille effective de l'historique secondaire.
// */
static void grow_future(history *h) {
if (h->capacity_future >= HISTORY_MAX) // Contrainte de taille.
{
fprintf(stdout, "Demande d'agrandissement de l'historique secondaire déjà à sa taille maximale.\n");
return;
}
h->capacity_future *= 2;
h->future = realloc(h->future, h->capacity_future * sizeof(turn));
if (h->future == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
}
// * @brief
// * réduit la taille effective de l'historique principal.
// */
static void reduice_past(history *h) {
if (h->capacity_past <= 1) // Sécurité.
{
return;
}
h->capacity_past /= 2;
turn *new_past = malloc(h->capacity_past * sizeof(turn));
if (new_past == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < h->size_past; i++) {
new_past[i] = h->past[(h->first_past + i) % h->capacity_past];
}
free(h->past);
h->past = new_past;
h->first_past = 0;
}
// * @brief
// * réduit la taille effective de l'historique secondaire.
// */
static void reduice_future(history *h) {
if (h->capacity_future <= 1) // Sécurité.
{
return;
}
h->capacity_future /= 2;
h->future = realloc(h->future, h->capacity_future * sizeof(turn));
if (h->future == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
}
// * @brief
// * supprime les tours annulés de l'historique.
// */
static void kill_future(history *h) {
turn * new_future = malloc(sizeof(turn));
if (new_future == NULL) {
fprintf(stderr, "Erreur d'allocation\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < h->size_future; i++) {
if (h->future[i].type == T_POLY) {
free(h->future[i].minokilled); // On libère les tableaux de booléens.
}
}
free(h->future);
h->future = new_future;
h->size_future = 0;
h->capacity_future = 1;
}
// * @brief
// * renvoie le dernier tour passé.
// * supprime ce tour de l'historique.
// * @return le dernier tour passé.
// */
static turn pop_past(history *h) {
if (h->size_past == 0) {
fprintf(stderr, "Demande de récupération d'un tour passé dans un historique vide.\n");
exit(EXIT_FAILURE);
}
h->size_past--;
const turn t = h->past[(h->size_past + h->first_past) % h->capacity_past];
if (h->size_past < h->capacity_past / 4) {
reduice_past(h);
}
return t;
}
// * @brief
// * renvoie le dernier tour annulé.
// * supprime ce tour de l'historique.
// * @return le dernier tour annulé.
// */
static turn pop_future(history *h) {
if (h->size_future == 0) {
fprintf(stderr, "Demande de récupération d'un tour futur dans un historique vide.\n");
exit(EXIT_FAILURE);
}
h->size_future--;
const turn t = h->future[h->size_future];
if (h->size_future < h->capacity_future / 4) {
reduice_future(h);
}
return t;
}
// * @brief
// * ajoute un tour passé à l'historique.
// */
static void add_past(const turn t, history *h) {
if (h->size_past == HISTORY_MAX) {
// On remplace le plus ancien tour par le nouveau.
if (h->past[h->first_past].type == T_POLY) {
free(h->past[h->first_past].minokilled); // On libère le tableau de booléens.
}
h->past[h->first_past] = t;
h->first_past = (h->first_past + 1) % h->capacity_past;
}
else {
if (h->size_past == h->capacity_past) {
grow_past(h);
}
h->past[(h->size_past + h->first_past) % h->capacity_past] = t;
h->size_past++;
}
}
// * @brief
// * ajoute un tour annulé à l'historique secondaire.
// */
static void add_future(const turn t, history *h) {
if (h->size_future == h->capacity_future) {
grow_future(h);
}
h->future[h->size_future] = t;
h->size_future++;
}
void free_history(history *h) {
for (int i = 0; i < h->size_past; i++) {
if (h->past[(h->first_past + i) % h->capacity_past].type == T_POLY) {
free(h->past[(h->first_past + i) % h->capacity_past].minokilled); // On libère les tableaux de booléens.
}
}
free(h->past);
for (int i = 0; i < h->size_future; i++) {
if (h->future[i].type == T_POLY) {
free(h->future[i].minokilled); // On libère les tableaux de booléens.
}
}
free(h->future);
free(h);
}
void add_entry_history(const turn t, history *h) {
add_past(t, h); //redondant mais j'avais déjà codé ça :'(
kill_future(h);
}
int sizenext_history(history *h) {
return h->size_future;
}
int sizeprev_history(history *h) {
return h->size_past;
}
void rewind_history(history *h) {
if (h->size_past == 0) {
return;
}
const turn t = pop_past(h);
add_future(t, h);
}
void continue_history(history *h) {
if (h->size_future == 0) {
return;
}
const turn t = pop_future(h);
add_past(t, h);
}
turn* last_move_history(history *h) {
if (h->size_past == 0) {
return NULL;
}
return &h->past[(h->size_past + h->first_past - 1) % h->capacity_past];
}
turn* next_move_history(history *h) {
if (h->size_future == 0) {
return NULL;
}
return &h->future[h->size_future - 1];
}

View File

@@ -0,0 +1,214 @@
#include "game_strategies.h"
#include <sys/random.h>
#include "game.h"
const char* str_names[STR_SIZE] = { "Immobile","Aléatoire", "Opposée", "Agressive", "BFS", "Attroupement", "Anti-jeu", "Détection" };
void(*str_funs[STR_SIZE]) (maze*, move, move*) = { &minotaurs_still, &minotaurs_random, &minotaurs_reverse, &minotaurs_closein, &minotaurs_bfs, &minotaurs_centre, &minotaurs_exit, &minotaurs_range };
void minotaurs_still(maze *m, move, move *mino_move) {
for (int i = 0; i < m->nb_minotaurs; i++) {
mino_move[i] = M_WAIT;
}
}
void minotaurs_random(maze *m, move, move *mino_move) {
move r;
for (int i = 0; i < m->nb_minotaurs; i++) {
getrandom(&r, sizeof(r), 0);
mino_move[i] = r % 5;
}
}
void minotaurs_reverse(maze *m, const move mv, move *mino_move) {
for (int i = 0; i < m->nb_minotaurs; i++) {
switch (mv){
case M_NORTH:
mino_move[i] = M_SOUTH;
break;
case M_EAST:
mino_move[i] = M_WEST;
break;
case M_SOUTH:
mino_move[i] = M_NORTH;
break;
case M_WEST:
mino_move[i] = M_EAST;
break;
default: //inclue M_WAIT
mino_move[i] = M_WAIT;
}
}
}
void minotaurs_closein(maze *m, move, move *mino_move) {
const int x_player = m->player % m->hsize;
const int y_player = m->player / m->hsize;
for (int i = 0; i < m->nb_minotaurs; i++)
{
const int delta_x = x_player - (m->minotaurs[i] % m->hsize);
const int delta_y = y_player - (m->minotaurs[i] / m->hsize);
if (abs(delta_x) > abs(delta_y) || (abs(delta_x) == abs(delta_y) && rand() % 2 == 0))
{
if (delta_x > 0)
{
mino_move[i] = M_EAST;
}
else
{
mino_move[i] = M_WEST;
}
}
else
{
if (delta_y > 0)
{
mino_move[i] = M_SOUTH;
}
else
{
mino_move[i] = M_NORTH;
}
}
}
}
void minotaurs_bfs(maze *m, move, move *mino_move) {
queue *q = create_queue();
bool visited[m->hsize * m->vsize];
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
enqueue(m->player, q);
visited[m->player] = true;
while (!is_empty_queue(q))
{
const int cell = dequeue(q);
for (cardinal c = NORTH; c < 4; c++)
{
const int neighbour = get_adj_maze(m, cell, c);
if (valid_maze(m, neighbour) && !visited[neighbour] && !has_wall_maze(m, cell, c))
{
visited[neighbour] = true;
enqueue(neighbour, q);
for (int i = 0; i < m->nb_minotaurs; i++)
{
if (m->minotaurs[i] == neighbour)
{
mino_move[i] = (move)((c + 2) % 4);
}
}
}
}
}
}
void minotaurs_centre(maze *m, move, move *mino_move) {
queue *q = create_queue();
bool visited[m->hsize * m->vsize];
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
enqueue(m->vsize /2 * m->hsize + m->hsize / 2, q);
visited[m->player] = true;
while (!is_empty_queue(q))
{
const int cell = dequeue(q);
for (cardinal c = NORTH; c < 4; c++)
{
const int neighbour = get_adj_maze(m, cell, c);
if (valid_maze(m, neighbour) && !visited[neighbour] && !has_wall_maze(m, cell, c))
{
visited[neighbour] = true;
enqueue(neighbour, q);
for (int i = 0; i < m->nb_minotaurs; i++)
{
if (m->minotaurs[i] == neighbour)
{
mino_move[i] = (move)((c + 2) % 4);
}
}
}
}
}
}
void minotaurs_exit(maze *m, move, move *mino_move) {
queue *q = create_queue();
bool visited[m->hsize * m->vsize];
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
for (int i = 0; i < m->vsize * m->hsize; i++) {
if (get_object_maze(m, i) == EXIT) {
enqueue(i, q);
visited[i] = true;
break;
}
}
visited[m->player] = true;
while (!is_empty_queue(q))
{
const int cell = dequeue(q);
for (cardinal c = NORTH; c < 4; c++)
{
const int neighbour = get_adj_maze(m, cell, c);
if (valid_maze(m, neighbour) && !visited[neighbour] && !has_wall_maze(m, cell, c))
{
visited[neighbour] = true;
enqueue(neighbour, q);
for (int i = 0; i < m->nb_minotaurs; i++)
{
if (m->minotaurs[i] == neighbour)
{
mino_move[i] = (move)((c + 2) % 4);
}
}
}
}
}
}
void minotaurs_range(maze *m, move, move *mino_move){
queue *q = create_queue();
bool visited[m->hsize * m->vsize];
for (int i = 0; i < m->hsize * m->vsize; i++) {
visited[i] = false;
}
enqueue(m->player, q);
visited[m->player] = true;
int size_gen = 0;
int gen = 0;
int gen_rest = 1;
while (!is_empty_queue(q) && gen < 10) //les minotaures sont trop bêtes pour prévoir plus de 10 cases à l'avance
{
const int cell = dequeue(q);
gen_rest--;
for (cardinal c = NORTH; c < 4; c++)
{
const int neighbour = get_adj_maze(m, cell, c);
if (valid_maze(m, neighbour) && !visited[neighbour] && !has_wall_maze(m, cell, c))
{
visited[neighbour] = true;
enqueue(neighbour, q);
size_gen++;
for (int i = 0; i < m->nb_minotaurs; i++)
{
if (m->minotaurs[i] == neighbour)
{
mino_move[i] = (move)((c + 2) % 4);
}
}
}
}
if (gen_rest == 0)
{
gen++;
gen_rest = size_gen;
size_gen = 0;
}
}
}

358
maze/maze_VM.c Normal file
View File

@@ -0,0 +1,358 @@
#include "maze_2.h"
#include "data_queue.h"
#include <bits/types/siginfo_t.h>
/*****************************************/
/*+ Récupération de numéros de cellules +*/
/*****************************************/
int get_adj_maze(maze* p_maze, const int cellule, const cardinal card) {
switch (card) {
case NORTH:
if(cellule < p_maze->hsize) { // Si on est sur la première ligne (on ne peut donc aller plus au nord)
return -1;
}
return cellule - p_maze->hsize;
case EAST:
if(cellule % p_maze->hsize == p_maze->hsize - 1) { // Si on est sur la dernière colonne (on ne peut donc aller plus à l'est)
return -1;
}
return cellule + 1;
case SOUTH:
if(cellule >= (p_maze->vsize - 1) * p_maze->hsize) { // Si on est sur la dernière ligne (on ne peut donc aller plus au sud)
return -1;
}
return cellule + p_maze->hsize;
case WEST:
if(cellule % p_maze->hsize == 0) { // Si on est sur la première colonne (on ne peut donc aller plus à l'ouest)
return -1;
}
return cellule - 1;
default:
return -1;
}
}
/****************************************/
/*+ Gestion des cellules du labyrinthe +*/
/****************************************/
void mask_cell_maze(maze *p_maze, const int cellule) {
p_maze->props[cellule] |= 32; // On masque la cellule (on met le 6ème bit à 1)
}
bool valid_maze(maze *p_maze, const int cellule) {
if(cellule < 0 || cellule / p_maze->vsize >= p_maze->hsize || cellule % p_maze->vsize >= p_maze->vsize) { // Si la cellule n'est pas dans la grille
return false;
}
// ReSharper disable once CppDFANullDereference
return !(p_maze->props[cellule] & 32); // Si la cellule est accessible (booléen stocké dans le 6ème bit)
}
bool is_reach_maze(maze *p_maze, const int cellule) {
return p_maze->props[cellule] & 64; // Si la cellule est accessible (booléen stocké dans le 7ème bit)
}
void make_reach_maze(maze *p_maze, const int cellule) {
p_maze->props[cellule] |= 64; // On rend la cellule accessible (on met le 7ème bit à 1)
}
bool has_wall_maze(maze *p_maze, const int cellule, const cardinal card) {
switch (card)
{
case NORTH:
return p_maze->props[cellule] & 1; // Si il y a un mur au nord (booléen stocké dans le 1er bit)
case EAST:
return p_maze->props[cellule] & 2; // Si il y a un mur à l'est (booléen stocké dans le 2ème bit)
case SOUTH:
return p_maze->props[cellule] & 4; // Si il y a un mur au sud (booléen stocké dans le 3ème bit)
case WEST:
return p_maze->props[cellule] & 8; // Si il y a un mur à l'ouest (booléen stocké dans le 4ème bit)
default:
fprintf(stderr, "has_wall_maze: cardinal inconnu\n");
exit(EXIT_FAILURE);
}
}
void build_wall_maze(maze *p_maze, const int cellule, const cardinal card) {
switch (card)
{
case NORTH:
p_maze->props[cellule] |= 1; // On met un mur au nord (on met le 1er bit à 1)
int neighbour = get_adj_maze(p_maze, cellule, NORTH);
if(neighbour != -1) {
p_maze->props[neighbour] |= 4; // On met un mur au sud de la cellule voisine (on met le 3ème bit à 1)
}
return;
case EAST:
p_maze->props[cellule] |= 2; // On met un mur à l'est (on met le 2ème bit à 1)
neighbour = get_adj_maze(p_maze, cellule, EAST);
if(neighbour != -1) {
p_maze->props[neighbour] |= 8; // On met un mur à l'ouest de la cellule voisine (on met le 4ème bit à 1)
}
return;
case SOUTH:
p_maze->props[cellule] |= 4; // On met un mur au sud (on met le 3ème bit à 1)
neighbour = get_adj_maze(p_maze, cellule, SOUTH);
if(neighbour != -1) {
p_maze->props[neighbour] |= 1; // On met un mur au nord de la cellule voisine (on met le 1er bit à 1)
}
return;
case WEST:
p_maze->props[cellule] |= 8; // On met un mur à l'ouest (on met le 4ème bit à 1)
neighbour = get_adj_maze(p_maze, cellule, WEST);
if(neighbour != -1) {
p_maze->props[neighbour] |= 2; // On met un mur à l'est de la cellule voisine (on met le 2ème bit à 1)
}
return;
default:
fprintf(stderr, "build_wall_maze: cardinal inconnu\n");
exit(EXIT_FAILURE);
}
}
void del_wall_maze(maze *p_maze, const int cellule, const cardinal card) {
switch (card)
{
case NORTH:
p_maze->props[cellule] &= 254; // On enlève le mur au nord (on met le 1er bit à 0)
int neighbour = get_adj_maze(p_maze, cellule, NORTH);
if(neighbour != -1) {
p_maze->props[neighbour] &= 251; // On enlève le mur au sud de la cellule voisine (on met le 3ème bit à 0)
}
return;
case EAST:
p_maze->props[cellule] &= 253; // On enlève le mur à l'est (on met le 2ème bit à 0)
neighbour = get_adj_maze(p_maze, cellule, EAST);
if(neighbour != -1) {
p_maze->props[neighbour] &= 247; // On enlève le mur à l'ouest de la cellule voisine (on met le 4ème bit à 0)
}
return;
case SOUTH:
p_maze->props[cellule] &= 251; // On enlève le mur au sud (on met le 3ème bit à 0)
neighbour = get_adj_maze(p_maze, cellule, SOUTH);
if(neighbour != -1) {
p_maze->props[neighbour] &= 254; // On enlève le mur au nord de la cellule voisine (on met le 1er bit à 0)
}
return;
case WEST:
p_maze->props[cellule] &= 247; // On enlève le mur à l'ouest (on met le 4ème bit à 0)
neighbour = get_adj_maze(p_maze, cellule, WEST);
if(neighbour != -1) {
p_maze->props[neighbour] &= 253; // On enlève le mur à l'est de la cellule voisine (on met le 2ème bit à 0)
}
return;
default:
fprintf(stderr, "build_wall_maze: cardinal inconnu\n");
exit(EXIT_FAILURE);
}
}
bool is_occupied_maze(maze *p_maze, const int cellule) {
return p_maze->props[cellule] & 16; // Si la cellule est occupée (booléen stocké dans le 5ème bit)
}
void make_occupied_maze(maze *p_maze, const int cellule) {
p_maze->props[cellule] |= 16; // On marque la cellule comme occupée (on met le 5ème bit à 1)
}
void free_occupied_maze(maze *p_maze, const int cellule) {
p_maze->props[cellule] &= 239; // On libère la cellule (on met le 5ème bit à 0)
}
bool can_be_used(maze *p_maze, const int cellule) {
return is_reach_maze(p_maze, cellule) && valid_maze(p_maze, cellule); // Si la cellule est utilisable
}
/************************/
/*+ Gestion des objets +*/
/************************/
object get_object_maze(maze *p_maze, const int cellule) {
//on ne vérifie pas si la cellule est valide
return p_maze->objects[cellule]; // On retourne l'objet contenu dans la cellule
}
void add_object_maze(maze *p_maze, const int cellule, const object obj) {
//on ne vérifie pas si la cellule ou l'objet sont valides
p_maze->objects[cellule] = obj; // On ajoute un objet dans la cellule
}
int get_exits_maze(maze *p_maze) {
int exits = 0;
for(int i = 0; i < p_maze->vsize * p_maze->hsize; i++)
{
if(get_object_maze(p_maze, i) == EXIT)
{
exits++;
}
}
return exits;
}
/**************************************/
/*+ Création d'un labyrinthe basique +*/
/**************************************/
maze* create_proto_maze_nomask(const int hsize, const int vsize) {
maze *p_maze = malloc(sizeof(maze));
//check sécurité
if(p_maze == NULL) {
fprintf(stderr, "create_proto_maze_nomask: erreur d'allocation\n");
exit(EXIT_FAILURE);
}
p_maze->hsize = hsize;
p_maze->vsize = vsize;
p_maze->props = malloc(hsize * vsize * sizeof(unsigned char));
p_maze->objects = malloc(hsize * vsize * sizeof(object));
//check sécurité
if(p_maze->props == NULL || p_maze->objects == NULL) {
fprintf(stderr, "create_proto_maze_nomask: erreur d'allocation\n");
exit(EXIT_FAILURE);
}
p_maze->nb_minotaurs = 0;
p_maze->minotaurs = NULL;
p_maze->nb_reachable = hsize * vsize; //puisqu'il n'y a pas de masque, toutes les cellules sont accessibles
for(int i = 0; i < hsize * vsize; i++) {
p_maze->props[i] = 79; // On initialise les propriétés des cellules (toutes les cellules sont murées dans les quatre directions, non occupées, non masquées et accessibles)
p_maze->objects[i] = NONE; // On initialise les objets à NONE
}
const int i = rand() % (hsize * vsize);
p_maze->player = i; // On place le joueur dans une cellule aléatoire
make_occupied_maze(p_maze, i); // On marque la cellule comme occupée
return p_maze;
}
maze* create_proto_maze(mask *m) {
maze *p_maze = malloc(sizeof(maze));
//check sécurité
if(p_maze == NULL) {
fprintf(stderr, "create_proto_maze: erreur d'allocation\n");
exit(EXIT_FAILURE);
}
p_maze->vsize = m->vsize;
p_maze->hsize = m->hsize;
p_maze->props = malloc(m->vsize * m->hsize * sizeof(unsigned char));
p_maze->objects = malloc(m->vsize * m->hsize * sizeof(object));
//check sécurité
if(p_maze->props == NULL || p_maze->objects == NULL) {
fprintf(stderr, "create_proto_maze: erreur d'allocation\n");
exit(EXIT_FAILURE);
}
p_maze->nb_minotaurs = 0;
p_maze->minotaurs = NULL;
for(int i = 0; i < m->vsize * m->hsize; i++) {
p_maze->props[i] = 15; // On initialise les murs (toutes les cellules sont murées dans les quatre directions)
p_maze->objects[i] = NONE;
if(m->grid[i]) {
mask_cell_maze(p_maze, i); // On masque les cellules masquées
}
}
int i = rand() % (m->vsize * m->hsize); // NOLINT(*-msc50-cpp)
while(!valid_maze(p_maze, i)) // On placera le joueur dans une cellule aléatoire valide
{
i = rand() % (m->vsize * m->hsize); // NOLINT(*-msc50-cpp)
}
p_maze->player = i; // On place le joueur dans une cellule aléatoire
queue *q = create_queue();
enqueue(i, q);
make_reach_maze(p_maze, i); // On marque la cellule comme accessible
p_maze->nb_reachable = 1;
while(!is_empty_queue(q)) {
i = dequeue(q);
for(cardinal c = NORTH; c < 4; c++) {
const int neighbour = get_adj_maze(p_maze, i, c);
if(valid_maze(p_maze, neighbour) && !is_reach_maze(p_maze, neighbour)) {
enqueue(neighbour, q);
make_reach_maze(p_maze, neighbour); // On marque les cellules accessibles
p_maze->nb_reachable++;
}
}
}
return p_maze;
}
void free_maze(maze *p_maze) {
free(p_maze->objects);
free(p_maze->props);
free(p_maze->minotaurs);
free(p_maze);
}
/****************************/
/*+ Gestion des minotaures +*/
/****************************/
int has_minotaur_maze(maze *p_maze, const int cellule) {
for(int i = 0; i < p_maze->nb_minotaurs; i++) {
if(p_maze->minotaurs[i] == cellule) {
return i;
}
}
return -1;
}
void gen_minotaurs_maze(maze *p_maze, int nb_minotaurs) {
//la boucle aléatoire est plutôt lourde, on pourrait l'alléger en utilisant un tableau de booléens par exemple
if(p_maze->minotaurs)
{
free(p_maze->minotaurs);
}
if(nb_minotaurs > p_maze -> hsize * p_maze -> vsize - 1) { // Si le nombre de minotaures est supérieur au nombre de cellules - 1
nb_minotaurs = p_maze -> hsize * p_maze -> vsize - 1; // On réduit au maximum disponible
}
p_maze->nb_minotaurs = nb_minotaurs;
p_maze->minotaurs = malloc(nb_minotaurs * sizeof(int));
//check sécurité
if(p_maze->minotaurs == NULL) {
fprintf(stderr, "gen_minotaurs_maze: erreur d'allocation\n");
exit(EXIT_FAILURE);
}
int cellule;
for(int i = 0; i < nb_minotaurs; i++) {
do{
cellule = rand() % (p_maze->vsize * p_maze->hsize); // NOLINT(*-msc50-cpp)
}
while(!valid_maze(p_maze, cellule) || is_occupied_maze(p_maze, cellule) || !is_reach_maze(p_maze, cellule)); // On place les minotaures dans des cellules aléatoires valides et non occupées
p_maze->minotaurs[i] = cellule; // On place le minotaure dans la cellule
make_occupied_maze(p_maze, cellule); // On marque la cellule comme occupée
}
}
/********************************/
/*+ Récupération d'information +*/
/********************************/
bool valid_move_maze(maze *p_maze, const int cellule, const move mv)
{
if(mv == M_WAIT)
{
return true; // Si on est sur une cellule, c'est qu'elle est valide
}
const int neighbour = get_adj_maze(p_maze, cellule, (cardinal)mv);
if(neighbour == -1) {
return false; // Si il n'y a pas de cellule adjacente dans la direction donnée, le mouvement n'est pas valide
}
return !has_wall_maze(p_maze, cellule, (cardinal)mv) && can_be_used(p_maze, neighbour) && !is_occupied_maze(p_maze, neighbour);
// Si il n'y a pas de mur, que la cellule adjacente est valide et non occupée, le mouvement est valide
}

View File

@@ -0,0 +1,125 @@
#include "maze_braiding.h"
#include "maze.h"
#include "maze_2.h"
bool is_dead_end(maze *p_maze, const int cell)
{
char c = 0;
const unsigned char value = p_maze->props[cell] & 31;
if (value & 1)
{
c++;
}
if (value & 2)
{
c++;
}
if (value & 4)
{
c++;
}
if (value & 8)
{
c++;
}
return c == 3;
}
int count_dead_ends(maze *p_maze)
{
int c = 0;
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (is_dead_end(p_maze, i))
{
c++;
}
}
return c;
}
void remove_one_dead_end(maze *p_maze, const int cell, const int odds)
{
bool tab[4] = {0};
bool tab_prio[4] = {0};
if (can_be_used(p_maze, cell) && is_dead_end(p_maze, cell) && rand() % 100 < odds)
{
for (int i = 0; i < 4; i++)
{
if (has_wall_maze(p_maze, cell, i))
{
continue;
}
// on n'a pas de mur
int n = get_adj_maze(p_maze, cell, (i + 2) % 4);
if (n != -1 && can_be_used(p_maze, n))
{
tab[(i + 2) % 4] = true;
if (is_dead_end(p_maze, n))
{
tab_prio[(i + 2) % 4] = true;
}
}
n = get_adj_maze(p_maze, cell, (i + 1) % 4);
if (n != -1 && has_wall_maze(p_maze, n, (i + 3) % 4) && can_be_used(p_maze, n))
{
tab[(i + 1) % 4] = true;
if (is_dead_end(p_maze, n))
{
tab_prio[(i + 1) % 4] = true;
}
}
n = get_adj_maze(p_maze, cell, (i + 3) % 4);
if (n != -1 && has_wall_maze(p_maze, n, (i + 1) % 4) && can_be_used(p_maze, n))
{
tab[(i + 3) % 4] = true;
if (is_dead_end(p_maze, n))
{
tab_prio[(i + 3) % 4] = true;
}
}
}
}
// On choisit un mur à enlever parmis les prioritaires
char c = 0, cp = 0;
for (int i = 0; i < 4; i++)
{
if (tab_prio[i])
{
cp++;
}
if (tab[i])
{
c++;
}
}
if (cp > 0)
{
int r = rand() % 4;
while (tab_prio[r] == false)
{
r = rand() % 4;
}
del_wall_maze(p_maze, cell, r);
return;
}
if (c > 0)
{
int r = rand() % 4;
while (tab[r] == false)
{
r = rand() % 4;
}
del_wall_maze(p_maze, cell, r);
}
}
void braid_maze(maze *p_maze, const int odds)
{
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
remove_one_dead_end(p_maze, i, odds);
}
}

509
maze_gen/maze_gen_VM.c Normal file
View File

@@ -0,0 +1,509 @@
#include "maze_gen.h"
#include "data_binheap.h"
#include "maze.h"
#include "maze_2.h"
#include <sys/random.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"};
void maze_test(maze *)
{
// ne fait rien
}
void random_maze_ab(maze *p_maze)
{
bool visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
int visited_count = 0; // nombre de cases à visiter
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
visited[i] = false; // aucune case n'a été visitée
if (can_be_used(p_maze, i))
{
visited_count++; // on incrémente le nombre de cases à visiter
}
}
uint cell;
do
{
getrandom(&cell, sizeof(cell), 0);
cell %= p_maze->hsize * p_maze->vsize;
}
while (!can_be_used(p_maze, cell)); // on cherche une case utilisable
visited[cell] = true; // on visite la case de départ
visited_count--;
while (visited_count > 0)
{
const cardinal card = rand() % 4; // direction aléatoire
const int neigbour = get_adj_maze(p_maze, cell, card); // case voisine
if (can_be_used(p_maze, neigbour)) // si le voisin est exploitable
{
if (!visited[neigbour])
// si la case voisine n'a pas été visitée, on la visite
{
const int diff = cell - neigbour;
if (diff == 1)
{
del_wall_maze(p_maze, cell, WEST);
}
else if (diff == -1)
{
del_wall_maze(p_maze, cell, EAST);
}
else if (diff == p_maze->hsize)
{
del_wall_maze(p_maze, cell, NORTH);
}
else if (diff == -p_maze->hsize)
{
del_wall_maze(p_maze, cell, SOUTH);
}
else
{
fprintf(stderr, "Erreur rma: les cases ne sont pas voisines\n");
free_maze(p_maze);
exit(EXIT_FAILURE);
}
visited[neigbour] = true;
visited_count--;
}
cell = neigbour; // on se déplace
}
}
}
void random_maze_wilson(maze *p_maze)
{
bool visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
int visited_count = p_maze->hsize * p_maze->vsize - 1;
// nombre de case à visiter (la case de départ est déjà visitée)
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (can_be_used(p_maze, i))
// si la case est accessible
{
visited[i] = false; // on doit la visiter
}
else
{
visited_count--; // on décrémente le nombre de cases à visiter
}
}
int cell;
do
{
getrandom(&cell, sizeof(cell), 0);
cell %= p_maze->hsize * p_maze->vsize;
}
while (!can_be_used(p_maze, cell)); // on cherche une case utilisable
visited[cell] = true; // on visite la case de départ
while (visited_count > 0) // recherche d'une case non visitée
{
do
{
cell = rand() % (p_maze->hsize * p_maze->vsize); // case aléatoire
}
while (visited[cell] || !can_be_used(p_maze, cell)); // tant que la case a été visitée ou n'est pas utilisable
bool path_visited[p_maze->hsize * p_maze->vsize]; // Tableau de booléens pour savoir si une case a été visitée
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
path_visited[i] = false; // aucune case n'a été visitée
}
// hérence jusqu'à une case visitée
dynarray *path = create_dyn(); // liste des cases du chemin
push_dyn(cell, path); // on initialise le chemin
path_visited[cell] = true; // la case est visitée
int neighbour; // case voisine
cardinal card; // direction aléatoire
while (!visited[cell]) // tant que la case n'a pas été visitée
{
push_dyn(cell, path); // on ajoute la case au chemin
do // on cherche un voisin
{
getrandom(&card, sizeof(card), 0);
card %= 4;
neighbour = get_adj_maze(p_maze, cell, card); // case voisine
}
while (!can_be_used(p_maze, neighbour)); // jusqu'à trouver un voisin convenable
cell = neighbour; // on se déplace
// résolution des cycles
while (path_visited[cell] && !is_empty_dyn(path)) // si la case a déjà été visitée, c'est un cycle
{
path_visited[cell] = false; // on efface le chemin en remontant le cycle
cell = pop_dyn(path);
}
path_visited[cell] = true; // on marque la case dans le chemin
}
int cell1 = pop_dyn(path); // cell1 est la cellule sur le chemin (pas encore visitée)
// on casse les murs
while (!is_empty_dyn(path)) // tant qu'il reste des cases sur le chemin
{
const int diff = cell - cell1;
if (diff == 1)
{
del_wall_maze(p_maze, cell, WEST);
}
else if (diff == -1)
{
del_wall_maze(p_maze, cell, EAST);
}
else if (diff == p_maze->hsize)
{
del_wall_maze(p_maze, cell, NORTH);
}
else if (diff == -p_maze->hsize)
{
del_wall_maze(p_maze, cell, SOUTH);
}
else
{
fprintf(stderr, "Erreur rma: les cases ne sont pas voisines\n");
free_maze(p_maze);
exit(EXIT_FAILURE);
}
visited[cell1] = true; // la case est visitée
visited_count--; // on décrémente le nombre de cases à visiter
cell = cell1; // la cellule actuelle devient la cellule précédente (visitée)
cell1 = pop_dyn(path); // la cellule précédente devient la cellule chemin (pas encore visitée)
}
}
}
static void phase_kill_hkdfs(maze *p_maze, bool *visited, int cell, dynarray *d)
{
visited[cell] = true; // on visite la case où nous sommes
// int dir_tab[4] = {0};
// tableau de booléens pour savoir si une direction est possible
int possible_dir = 0; // nombre de directions possibles
for (int i = 0; i < 4; i++)
{
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
if (neighbour != -1 && !visited[neighbour] && can_be_used(p_maze, neighbour))
{
// si la case voisine existe et n'a pas été visitée
// dir_tab[i] = true;
possible_dir++;
}
}
if (possible_dir == 0)
{
// si aucune direction n'est possible, on retourne
return;
}
int random_dir = rand() % 4;
while (get_adj_maze(p_maze, cell, random_dir) == -1 || visited[get_adj_maze(p_maze, cell, random_dir)] || !can_be_used(p_maze, cell))
{
random_dir = rand() % 4;
}
push_dyn(cell, d);
del_wall_maze(p_maze, cell, random_dir);
phase_kill_hkdfs(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), d);
// on continue la phase de kill
return;
}
void random_maze_hkdfs(maze *p_maze)
{
bool visited[p_maze->hsize * p_maze->vsize];
// tableau de booléens pour savoir si une case a été visitée
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (can_be_used(p_maze, i)) // si la case est accessible
{
visited[i] = false; // on doit la visiter
}
else
{
visited[i] = true; // on ne doit pas la visiter
}
}
dynarray *d = create_dyn();
// on choisit une case aléatoire, on la visite et on lance la phase de kill
int cell; // case aléatoire
do
{
cell = rand() % (p_maze->hsize * p_maze->vsize);
}
while (visited[cell] || !can_be_used(p_maze, cell));
push_dyn(cell, d);
phase_kill_hkdfs(p_maze, visited, pop_dyn(d), d);
// booléen pour savoir si la case a des voisins visités
while (!is_empty_dyn(d))
{
phase_kill_hkdfs(p_maze, visited, pop_dyn(d), d);
}
return;
}
static void phase_kill_hkrandom(maze *p_maze, bool *visited, int cell, int *visited_count)
{
if (!visited[cell])
{
(*visited_count)--; // on décrémente le nombre de cases à visiter
}
visited[cell] = true; // on visite la case où nous sommes
int dir_tab[4] = {0};
// tableau de booléens pour savoir si une direction est possible
int possible_dir = 0; // nombre de directions possibles
for (int i = 0; i < 4; i++)
{
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
if (neighbour != -1 && !visited[neighbour])
{
// si la case voisine existe et n'a pas été visitée
dir_tab[i] = true;
possible_dir++;
}
}
if (possible_dir == 0)
{
// si aucune direction n'est possible, on retourne
return;
}
int random_dir = rand() % possible_dir;
while (dir_tab[random_dir] == false)
{
// on cherche une direction possible
random_dir = (random_dir + 1) % 4;
}
del_wall_maze(p_maze, cell, random_dir);
phase_kill_hkrandom(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), visited_count);
// on continue la phase de kill
return;
}
void random_maze_hkrandom(maze *p_maze)
{
bool visited[p_maze->hsize * p_maze->vsize];
// tableau de booléens pour savoir si une case a été visitée
int visited_count = p_maze->hsize * p_maze->vsize;
// nombre de cases à visiter
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (can_be_used(p_maze, i)) // si la case est accessible
{
visited[i] = false; // on doit la visiter
}
else
{
visited[i] = true;
visited_count--; // on décrémente le nombre de cases à visiter
}
}
// on choisit une case aléatoire et on lance la phase de kill
int cell;
do
{
cell = rand() % (p_maze->hsize * p_maze->vsize);
}
while (visited[cell] || !can_be_used(p_maze, cell));
phase_kill_hkrandom(p_maze, visited, cell, &visited_count);
while (visited_count > 0)
{
do
{
cell = rand() % (p_maze->hsize * p_maze->vsize);
}
while (!visited[cell] || !can_be_used(p_maze, cell));
phase_kill_hkrandom(p_maze, visited, cell, &visited_count);
}
}
static void phase_kill_hklinear(maze *p_maze, char *visited, int cell, int *cell_min)
{
visited[cell] = 1; // on visite la case où nous sommes
int possible_dir = 0; // nombre de directions possibles
for (int i = 0; i < 4; i++)
{
int neighbour = get_adj_maze(p_maze, cell, i); // case voisine
if (neighbour != -1 && !visited[neighbour] && can_be_used(p_maze, neighbour))
{
// si la case voisine existe et n'a pas été visitée
possible_dir++;
}
}
if (possible_dir == 0)
{
visited[cell] = 2;
return;
}
int random_dir = rand() % 4;
while (get_adj_maze(p_maze, cell, random_dir) == -1 || visited[get_adj_maze(p_maze, cell, random_dir)] == 1 ||
!can_be_used(p_maze, get_adj_maze(p_maze, cell, random_dir)))
{
random_dir = rand() % 4;
}
del_wall_maze(p_maze, cell, random_dir);
if (cell < *cell_min)
*cell_min = cell;
phase_kill_hklinear(p_maze, visited, get_adj_maze(p_maze, cell, random_dir), cell_min);
// on continue la phase de kill
return;
}
void random_maze_hklinear(maze *p_maze)
{
char visited[p_maze->hsize * p_maze->vsize];
// tableau de booléens pour savoir si une case a été visitée
// nombre de cases à visiter
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (can_be_used(p_maze, i)) // si la case est accessible
{
visited[i] = 0; // on doit la visiter
}
else
{
visited[i] = 2; // on ne doit pas la visiter
}
}
// on choisit une case aléatoire, on la visite et on lance la phase de kill
int cell;
do
{
cell = rand() % (p_maze->hsize * p_maze->vsize); // case aléatoire}
}
while (!can_be_used(p_maze, cell));
phase_kill_hklinear(p_maze, visited, cell, &cell);
while (cell != p_maze->hsize * p_maze->vsize)
{
int n_cell = cell;
while (visited[n_cell] == 2 || visited[n_cell] == 0)
{
n_cell++;
if (visited[n_cell] == 1 && can_be_used(p_maze, n_cell))
{
cell = n_cell;
}
if (n_cell == p_maze->hsize * p_maze->vsize)
{
return;
}
}
phase_kill_hklinear(p_maze, visited, cell, &cell);
}
}
void random_maze_prim(maze *) { return; }
void random_maze_kruskal(maze *) { return; }
static void maze_rec(maze *m, const int x, const int y, const int w, const int h)
{
static int count = 0;
printf("%d : ", count++);
if (w == 1 && h == 1)
{
return;
}
unsigned int wall;
if (w > h)
{
const int middle = x + w / 2; //la coordonnée x du mur à casser
getrandom(&wall, sizeof(wall), 0);
wall = wall % h + y; //la coordonné y du mur à casser
del_wall_maze(m, middle * m->vsize + wall, EAST);
maze_rec(m, x, y, middle - x, h);
maze_rec(m, middle, y, x + w - middle, h);
}
else
{
const int middle = y + h / 2; //la coordonnée y du mur à casser
getrandom(&wall, sizeof(wall), 0);
wall = wall % w + x; //la coordonné x du mur à casser
del_wall_maze(m, wall * m->vsize + middle, SOUTH);
maze_rec(m, x, y, w, middle - y);
maze_rec(m, x, middle, w, y + h - middle);
}
}
void random_maze_rec(maze *p_maze){
maze_rec(p_maze, 0, 0, p_maze->hsize, p_maze->vsize);
}
static void aloyse_random_maze_rec(maze* m) {
// Initialiser le générateur de nombres aléatoires
// 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);
}

119
maze_masks/maze_masks_VB.c Normal file
View File

@@ -0,0 +1,119 @@
#include "maze_masks.h"
/***********************/
/*+ Fonctions de base +*/
/***********************/
mask* create_empty_mask(const int hsize, const int vsize) {
mask *m = malloc(sizeof(mask));
m->hsize = hsize;
m->vsize = vsize;
m->nbmasked = 0;
m->grid = malloc(hsize * vsize * sizeof(bool));
for(int i = 0; i < hsize * vsize; i++) {
m->grid[i] = false;
}
return m;
}
void free_mask(mask *m) {
if(m == NULL) {
return;
}
free(m->grid);
free(m);
}
void resize_mask(mask *m, const int hsize, const int vsize) {
if (m == NULL) {
return;
}
bool *newgrid = malloc(hsize * vsize * sizeof(bool));
if (newgrid == NULL) {
fprintf(stderr, "resize_mask: erreur d'allocation d'un malloc\n");
return;
}
for (int i = 0; i < vsize; i++) {
for (int j = 0; j < hsize; j++) {
const int old_i = i * m->vsize / vsize;
const int old_j = j * m->hsize / hsize;
if (old_i < m->vsize && old_j < m->hsize) {
newgrid[i * hsize + j] = m->grid[old_i * m->hsize + old_j];
} else { //en cas de débordement dû à l'imprécision des arrondis
newgrid[i * hsize + j] = true;
}
}
}
free(m->grid);
m->grid = newgrid;
m->hsize = hsize;
m->vsize = vsize;
m->nbmasked = 0;
for (int i = 0; i < hsize * vsize; i++) {
if (m->grid[i]) {
m->nbmasked++;
}
}
}
void print_mask(mask *m) {
printf("mask :\n");
for(int i = 0; i < m->vsize; i++) {
for(int j = 0; j < m->hsize; j++) {
printf("%c", m->grid[i * m->hsize + j] ? 'X' : ' ');
}
printf("\n");
}
}
/**************************************/
/*+ Génération à partir d'un fichier +*/
/**************************************/
mask* read_mask(const char *fillname) {
FILE *f = fopen(fillname, "r");
if(!f) {
return NULL;
}
int hsize = 0, vsize = 0;
char c = fgetc(f);
while(c != '\n' && c != EOF){
hsize++;
c = fgetc(f);
}
while(c != EOF) {
if (c == '\n') {
vsize++;
}
c = fgetc(f);
}
mask *m = create_empty_mask(hsize, vsize);
rewind(f);
for(int i = 0; i < vsize; i++) {
for(int j = 0; j < hsize; j++) {
c = fgetc(f);
if(c == 'X') {
m->grid[i * hsize + j] = true;
m->nbmasked++;
}
else {
m->grid[i * hsize + j] = false;
}
}
fgetc(f);
}
fclose(f);
return m;
}

View File

@@ -0,0 +1,110 @@
#include "maze_objects.h"
#include "maze_2.h"
#include "sys/random.h"
void (*obj_funs[OBJ_SIZE])(maze *) = {&obj_empty, &obj_simple, &obj_monney, &obj_minimal};
const char *obj_names[OBJ_SIZE] = {
"Pas d'objets",
"Simple",
"Trésor",
"Minimal",
};
void obj_empty(maze *) {}
void obj_simple(maze *p_maze)
{
int cell;
do
{
getrandom(&cell, sizeof(cell), 0);
cell %= p_maze->vsize * p_maze->hsize;
}
while (!can_be_used(p_maze, cell));
p_maze->objects[cell] = EXIT;
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (!can_be_used(p_maze, i))
{
p_maze->objects[i] = NONE;
continue;
}
getrandom(&cell, sizeof(cell), 0);
cell %= 50;
if (cell == 0 && p_maze->objects[i] != EXIT)
{
p_maze->objects[i] = SMALLT;
}
else if (cell == 1 && p_maze->objects[i] != EXIT)
{
p_maze->objects[i] = MEDT;
}
else if (cell == 2 && p_maze->objects[i] != EXIT)
{
p_maze->objects[i] = LARGET;
}
else if (cell == 3 && p_maze->objects[i] != EXIT)
{
p_maze->objects[i] = BOMB;
}
else if (cell == 4 && p_maze->objects[i] != EXIT)
{
p_maze->objects[i] = POLY;
}
}
}
void obj_monney(maze *p_maze)
{
int cell;
do
{
getrandom(&cell, sizeof(cell), 0);
cell %= p_maze->vsize * p_maze->hsize;
}
while (!can_be_used(p_maze, cell));
p_maze->objects[cell] = EXIT;
for (int i = 0; i < p_maze->hsize * p_maze->vsize; i++)
{
if (!(valid_maze(p_maze, i) && is_reach_maze(p_maze, i)))
{
p_maze->objects[i] = NONE;
continue;
}
getrandom(&cell, sizeof(cell), 0);
cell %= 4;
if (cell == 0 && p_maze->objects[i] != EXIT)
{
getrandom(&cell, sizeof(cell), 0);
cell %= 7;
if (cell == 0)
{
p_maze->objects[i] = LARGET;
}
else if (cell < 3)
{
p_maze->objects[i] = MEDT;
}
else
{
p_maze->objects[i] = SMALLT;
}
}
}
}
void obj_minimal(maze *p_maze)
{
int cell;
do
{
getrandom(&cell, sizeof(cell), 0);
cell %= p_maze->vsize * p_maze->hsize;
}
while (!can_be_used(p_maze, cell));
p_maze->objects[cell] = EXIT;
}