ajouts des fichiers perso
Le plagiat c'est mal donc gare à vos culs
This commit is contained in:
496
game/game_VM.c
Normal file
496
game/game_VM.c
Normal 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);
|
||||
}
|
||||
264
game_history/game_history_VM.c
Normal file
264
game_history/game_history_VM.c
Normal 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];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
214
game_strategies/game_strategies_VM.c
Normal file
214
game_strategies/game_strategies_VM.c
Normal 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
358
maze/maze_VM.c
Normal 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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
125
maze_braiding/maze_braiding_VM.c
Normal file
125
maze_braiding/maze_braiding_VM.c
Normal 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
509
maze_gen/maze_gen_VM.c
Normal 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
119
maze_masks/maze_masks_VB.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
110
maze_objects/maze_objects_VM.c
Normal file
110
maze_objects/maze_objects_VM.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user