Files
algo-labyrinthes-giiiiive/game/game_VM.c
Vincent BRUNEAU cdddaa6239 ajouts des fichiers perso
Le plagiat c'est mal donc gare à vos culs
2024-12-12 14:07:36 +01:00

497 lines
14 KiB
C

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