Aloyse et Anna
j'ai push pas mal de fichier envoyer un message si vous en voulez un aute
This commit is contained in:
541
Aloyse et Anna/game.c
Normal file
541
Aloyse et Anna/game.c
Normal file
@@ -0,0 +1,541 @@
|
||||
#include "game.h"
|
||||
|
||||
#include "game_history.h"
|
||||
#include "maze.h"
|
||||
|
||||
/****************************/
|
||||
/*+ Création et libération +*/
|
||||
/****************************/
|
||||
|
||||
// Génération d'un nouveau jeu
|
||||
game* create_newgame(int hsize, int vsize, mask* themask, generator gen_maze, objgenerator gen_obj, int nb_min, int braid) {
|
||||
// Allocation mémoire pour le jeu
|
||||
game* g = malloc(sizeof(game));
|
||||
if (g == NULL) {
|
||||
ERROR("Erreur d'allocation mémoire pour le jeu.");
|
||||
}
|
||||
|
||||
// Création du proto-labyrinthe
|
||||
maze* lab = NULL;
|
||||
// Avec masque
|
||||
if (themask != NULL) {
|
||||
if (themask->hsize != hsize || themask->vsize != vsize) { // On verifie la taille du masque
|
||||
resize_mask(themask, hsize, vsize);
|
||||
}
|
||||
lab = create_proto_maze(themask);
|
||||
}
|
||||
// Sans masque
|
||||
else {
|
||||
lab = create_proto_maze_nomask(hsize, vsize);
|
||||
}
|
||||
// On verifie la création du labyrinthe
|
||||
if (lab == NULL) {
|
||||
ERROR("Erreur de création du proto-labyrinthe");
|
||||
}
|
||||
|
||||
// Modification du labyrinthe en fonction du générateur
|
||||
if (gen_maze < 0 || gen_maze >= GEN_SIZE) {
|
||||
free_game(g);
|
||||
ERROR("Générateur de labyrinthe invalide");
|
||||
} else {
|
||||
gen_funs[gen_maze](lab);
|
||||
}
|
||||
|
||||
// Modification du labyrinthe en fonction du générateur d'objets
|
||||
if (gen_obj < 0 || gen_obj >= OBJ_SIZE) {
|
||||
free_game(g);
|
||||
ERROR("Générateur d'objets invalide");
|
||||
} else {
|
||||
obj_funs[gen_obj](lab);
|
||||
}
|
||||
|
||||
// Modification du labyrinthe en fonction du nombre de minotaures
|
||||
if (nb_min < 0) {
|
||||
free_game(g);
|
||||
ERROR("Nombre de minotaures invalide");
|
||||
} else {
|
||||
gen_minotaurs_maze(lab, nb_min);
|
||||
}
|
||||
|
||||
// Modification du labyrinthe en fonction du tressage
|
||||
if (braid < 0 || braid > 100) {
|
||||
free_game(g);
|
||||
ERROR("Taux de tressage invalide");
|
||||
} else {
|
||||
braid_maze(lab, braid);
|
||||
}
|
||||
|
||||
// Initialisation du jeu
|
||||
g->m = lab; // On affecte le labyrinthe
|
||||
g->score = 0;
|
||||
g->nbombs = 0;
|
||||
g->npolys = 0;
|
||||
g->player_alive = true;
|
||||
g->player_dir = rand() % 4; // Le joueur est tourné dans une direction aléatoire
|
||||
g->minotaurs_alive = malloc(sizeof(bool) * g->m->nb_minotaurs);
|
||||
g->minotaurs_dirs = malloc(sizeof(cardinal) * g->m->nb_minotaurs);
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
g->minotaurs_alive[i] = true; // Les minotaures sont tous vivants
|
||||
g->minotaurs_dirs[i] = rand() % 4; // Les minotaures sont tournés dans une direction aléatoire
|
||||
}
|
||||
g->nb_deadends = count_dead_ends(g->m);
|
||||
g->exits = get_exits_maze(g->m);
|
||||
g->turns = 0;
|
||||
g->log = create_history();
|
||||
if (g->log == NULL) {
|
||||
free_game(g);
|
||||
ERROR("Erreur de création de l'historique");
|
||||
}
|
||||
|
||||
if (g == NULL) {
|
||||
ERROR("Le labyrinthe n'a pas été créé");
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
void free_game(game* g) {
|
||||
if (g == NULL) {
|
||||
ERROR("Pointeur null");
|
||||
} else {
|
||||
if (g->m != NULL) {
|
||||
free_maze(g->m);
|
||||
}
|
||||
if (g->minotaurs_alive != NULL) {
|
||||
free(g->minotaurs_alive);
|
||||
}
|
||||
if (g->minotaurs_dirs != NULL) {
|
||||
free(g->minotaurs_dirs);
|
||||
}
|
||||
if (g->log != NULL) {
|
||||
free_history(g->log);
|
||||
}
|
||||
free(g);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************************************/
|
||||
/*+ Implémentation des attaques de minotaures +*/
|
||||
/***********************************************/
|
||||
|
||||
int game_try_kill_player(game* g, cardinal* dir) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste les cases adjacentes au joueur pour les 4 directions
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int adj = get_adj_maze(g->m, g->m->player, i);
|
||||
if (adj != -1 && !has_wall_maze(g->m, g->m->player, i) && has_minotaur_maze(g->m, adj) != -1 && g->minotaurs_alive[has_minotaur_maze(g->m, adj)]) {
|
||||
*dir = (i + 2) % 4;
|
||||
g->player_alive = false;
|
||||
return has_minotaur_maze(g->m, adj);
|
||||
}
|
||||
}
|
||||
// Si on n'a pas trouvé de minotaure adjacent
|
||||
return -1;
|
||||
}
|
||||
|
||||
/***************************/
|
||||
/*+ Traitement des objets +*/
|
||||
/***************************/
|
||||
|
||||
void game_consume_object(game* g, int nb_copie, object obj) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste le type de l'objet
|
||||
switch (obj) {
|
||||
case SMALLT:
|
||||
g->score += nb_copie * VALSMALL;
|
||||
break;
|
||||
case MEDT:
|
||||
g->score += nb_copie * VALMED;
|
||||
break;
|
||||
case LARGET:
|
||||
g->score += nb_copie * VALLARGE;
|
||||
break;
|
||||
case BOMB:
|
||||
g->nbombs += nb_copie;
|
||||
break;
|
||||
case POLY:
|
||||
g->npolys += nb_copie;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (obj != EXIT && obj != NONE) {
|
||||
for (int i = 0; i < nb_copie; i++) {
|
||||
g->m->objects[g->m->player] = NONE;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
object game_treat_object(game* g) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On récupère l'objet de la cellule du joueur
|
||||
object obj = get_object_maze(g->m, g->m->player);
|
||||
// On teste le type de l'objet
|
||||
switch (obj) {
|
||||
case SMALLT:
|
||||
game_consume_object(g, 1, SMALLT);
|
||||
return SMALLT;
|
||||
case MEDT:
|
||||
game_consume_object(g, 1, MEDT);
|
||||
return MEDT;
|
||||
case LARGET:
|
||||
game_consume_object(g, 1, LARGET);
|
||||
return LARGET;
|
||||
case BOMB:
|
||||
game_consume_object(g, 1, BOMB);
|
||||
return BOMB;
|
||||
case POLY:
|
||||
game_consume_object(g, 1, POLY);
|
||||
return POLY;
|
||||
case EXIT:
|
||||
return EXIT;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NONE;
|
||||
}
|
||||
|
||||
/**********************************************************/
|
||||
/*+ Implémentation d'une demande de mouvement du joueur +*/
|
||||
/**********************************************************/
|
||||
|
||||
bool implement_game_move(game* g, move mov, strategy strag) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste si le joueur est vivant
|
||||
if (!g->player_alive) {
|
||||
return false;
|
||||
}
|
||||
// On teste si le mouvement est valide
|
||||
if (!valid_move_maze(g->m, g->m->player, mov)) {
|
||||
g->player_dir = (cardinal)mov;
|
||||
return false;
|
||||
}
|
||||
// SINON on fait le mouvement
|
||||
// On déplace le joueur et on le tourne dans la direction dans laquelle il avance
|
||||
free_occupied_maze(g->m, g->m->player);
|
||||
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)mov);
|
||||
g->player_dir = (cardinal)mov;
|
||||
make_occupied_maze(g->m, g->m->player);
|
||||
|
||||
// On gère les minotaures
|
||||
// On creer le tableau des mouvements des minotaures
|
||||
// pas la peine de l'initaliser à M_WAIT car on va le remplir
|
||||
move* min_move = malloc(sizeof(move) * g->m->nb_minotaurs);
|
||||
// On applique la stratégie des minotaures
|
||||
str_funs[strag](g->m, mov, min_move);
|
||||
// On teste si les minautores peuvent se déplacer
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
if (g->minotaurs_alive[i]) {
|
||||
// Si le minotaure est vivant et qu'on peut le déplacer dans la direction demandée
|
||||
if (valid_move_maze(g->m, g->m->minotaurs[i], min_move[i])) {
|
||||
free_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)min_move[i]);
|
||||
make_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->minotaurs_dirs[i] = (cardinal)min_move[i];
|
||||
}
|
||||
// Sinon on le tourne dans la direction demandée et on mets son mouvements à M_WAIT
|
||||
else {
|
||||
g->minotaurs_dirs[i] = (cardinal)min_move[i];
|
||||
min_move[i] = M_WAIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
// On teste les objets
|
||||
object obj = game_treat_object(g);
|
||||
// On teste si le joueur est attaqué
|
||||
cardinal* dir_player = malloc(sizeof(cardinal));
|
||||
*dir_player = g->player_dir;
|
||||
int min_killer = game_try_kill_player(g, dir_player);
|
||||
if (min_killer != -1) {
|
||||
g->player_alive = false;
|
||||
}
|
||||
// On gère l'historique
|
||||
t_move* history_move = malloc(sizeof(t_move));
|
||||
history_move->obj = obj;
|
||||
history_move->playermove = mov;
|
||||
history_move->minomoves = min_move;
|
||||
history_move->killer = min_killer;
|
||||
// On trouve la direction du minotaure qui a tué le joueur
|
||||
if (min_killer != -1) {
|
||||
for (cardinal i = 0; i < 4; i++) {
|
||||
if (get_adj_maze(g->m, g->m->minotaurs[min_killer], i) == g->m->player) {
|
||||
history_move->dirkill = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
history_move->dirkill = NORTH;
|
||||
}
|
||||
turn new_turn = {T_MOVE, .tmove = history_move};
|
||||
add_entry_history(new_turn, g->log);
|
||||
g->turns++;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
/*+ Implémentation des bombes +*/
|
||||
/*******************************/
|
||||
|
||||
bool game_bomb_wall(game* g) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste si le joueur a une bombe
|
||||
if (g->nbombs > 0 && g->player_alive) {
|
||||
// On teste si on peut détruire le mur
|
||||
if (get_adj_maze(g->m, g->m->player, g->player_dir) != -1 && valid_maze(g->m, get_adj_maze(g->m, g->m->player, g->player_dir)) &&
|
||||
has_wall_maze(g->m, g->m->player, g->player_dir)) {
|
||||
del_wall_maze(g->m, g->m->player, g->player_dir);
|
||||
// On teste si le joueur est attaqué
|
||||
cardinal* dir_player = malloc(sizeof(cardinal));
|
||||
*dir_player = g->player_dir;
|
||||
int min_killer = game_try_kill_player(g, dir_player);
|
||||
if (min_killer != -1) {
|
||||
g->player_alive = false;
|
||||
}
|
||||
g->nbombs--;
|
||||
// On gère l'historique
|
||||
t_bomb* history_move = malloc(sizeof(t_bomb));
|
||||
history_move->bombdir = g->player_dir;
|
||||
history_move->destroyed = true;
|
||||
history_move->killer = game_try_kill_player(g, dir_player);
|
||||
// On trouve la direction du minotaure qui a tué le joueur
|
||||
if (min_killer != -1) {
|
||||
for (cardinal i = 0; i < 4; i++) {
|
||||
if (get_adj_maze(g->m, g->m->minotaurs[min_killer], i) == g->m->player) {
|
||||
history_move->dirkill = i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Sinon on met une direction par défaut
|
||||
history_move->dirkill = NORTH;
|
||||
}
|
||||
turn new_turn = {T_BOMB, .tbomb = history_move};
|
||||
// On ajoute le tour à l'historique
|
||||
add_entry_history(new_turn, g->log);
|
||||
g->turns++;
|
||||
return true;
|
||||
}
|
||||
// Sinon on ne peut pas détruire de mur mais on perd quand même une bombe
|
||||
else {
|
||||
g->nbombs--;
|
||||
// On gère l'historique
|
||||
t_bomb* history_move = malloc(sizeof(t_bomb));
|
||||
history_move->bombdir = g->player_dir;
|
||||
history_move->destroyed = false;
|
||||
history_move->killer = -1;
|
||||
history_move->dirkill = NORTH;
|
||||
// On trouve la direction du minotaure qui a tué le joueur
|
||||
turn new_turn = {T_BOMB, .tbomb = history_move};
|
||||
add_entry_history(new_turn, g->log);
|
||||
g->turns++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/*+ Implémentation des polys d'algo +*/
|
||||
/*************************************/
|
||||
|
||||
bool game_kill_minotaurs(game* g, int portee) {
|
||||
if (g == NULL || g->m == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
if (portee < 0) {
|
||||
ERROR("Portée invalide");
|
||||
}
|
||||
// On teste si le joueur a un poly d'algo
|
||||
if (g->npolys > 0 && g->player_alive) {
|
||||
int nb_min_kill = 0;
|
||||
// On initialise le tableau des minotaures tués pour l'historique
|
||||
bool* min_killed = malloc(sizeof(bool) * g->m->nb_minotaurs);
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
min_killed[i] = false;
|
||||
}
|
||||
// On teste dans les quatres directions
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int cell_dir = g->m->player;
|
||||
int portee_dir = portee;
|
||||
while (portee_dir > 0 && get_adj_maze(g->m, cell_dir, i) != -1) {
|
||||
int num_mino = has_minotaur_maze(g->m, get_adj_maze(g->m, cell_dir, i));
|
||||
if (num_mino != -1 && g->minotaurs_alive[num_mino]) {
|
||||
nb_min_kill++;
|
||||
g->minotaurs_alive[num_mino] = false;
|
||||
min_killed[num_mino] = true;
|
||||
free_occupied_maze(g->m, get_adj_maze(g->m, cell_dir, i));
|
||||
}
|
||||
portee_dir--;
|
||||
cell_dir = get_adj_maze(g->m, cell_dir, i);
|
||||
}
|
||||
}
|
||||
if (nb_min_kill > 0) {
|
||||
g->npolys--;
|
||||
// On gère l'historique
|
||||
turn new_turn = {T_POLY, .minokilled = min_killed};
|
||||
add_entry_history(new_turn, g->log);
|
||||
g->turns++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
/*+ Gestion de l'historique +*/
|
||||
/*****************************/
|
||||
|
||||
bool game_undo(game* g) {
|
||||
if (g == NULL || g->log == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste si l'historique est vide
|
||||
if (sizeprev_history(g->log) == 0) {
|
||||
return false;
|
||||
}
|
||||
// Sinon on annule le dernier tour
|
||||
// On récupère le dernier tour
|
||||
turn* last_turn = last_move_history(g->log);
|
||||
rewind_history(g->log);
|
||||
g->turns--;
|
||||
switch (last_turn->type) {
|
||||
case T_MOVE:
|
||||
// On récupère les caractéristiques du tour
|
||||
t_move* history_move = last_turn->tmove;
|
||||
// On teste si le joueur a été attaqué
|
||||
if (history_move->killer != -1) {
|
||||
g->player_alive = true;
|
||||
}
|
||||
// On replace l'objet consommé
|
||||
if (history_move->obj != NONE) {
|
||||
game_consume_object(g, -1, history_move->obj);
|
||||
g->m->objects[g->m->player] = history_move->obj;
|
||||
}
|
||||
// On deplace le joueur
|
||||
free_occupied_maze(g->m, g->m->player);
|
||||
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)(history_move->playermove + 2) % 4);
|
||||
g->player_dir = (cardinal)((history_move->playermove + 2) % 4);
|
||||
make_occupied_maze(g->m, g->m->player);
|
||||
|
||||
// On gère les déplacements des minotaures
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
if (g->minotaurs_alive[i]) {
|
||||
// Si le minotaure est vivant on annule son déplacement
|
||||
if (history_move->minomoves[i] != M_WAIT) {
|
||||
free_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)(history_move->minomoves[i] + 2) % 4);
|
||||
make_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->minotaurs_dirs[i] = (cardinal)(history_move->minomoves[i] + 2) % 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case T_BOMB:
|
||||
t_bomb* history_bomb = last_turn->tbomb;
|
||||
// Si un mur a été détruit
|
||||
if (history_bomb->destroyed) {
|
||||
// On teste si le joueur a été attaqué
|
||||
if (history_bomb->killer != -1) {
|
||||
g->player_alive = true;
|
||||
}
|
||||
// On replace le mur détruit
|
||||
build_wall_maze(g->m, g->m->player, history_bomb->bombdir);
|
||||
}
|
||||
// On recupère la bombe consommée
|
||||
g->nbombs++;
|
||||
return true;
|
||||
case T_POLY:
|
||||
bool* history_poly = last_turn->minokilled;
|
||||
// On ressucite les minotaures tués
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
if (history_poly[i]) {
|
||||
g->minotaurs_alive[i] = true;
|
||||
make_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool game_redo(game* g) {
|
||||
if (g == NULL || g->log == NULL) {
|
||||
ERROR("Pointeur de jeu null");
|
||||
}
|
||||
// On teste si l'historique est vide
|
||||
if (sizenext_history(g->log) == 0) {
|
||||
return false;
|
||||
}
|
||||
// Sinon on remet le dernier tour annulé
|
||||
// On récupère le dernier tour annulé
|
||||
turn* next_turn = next_move_history(g->log);
|
||||
continue_history(g->log);
|
||||
g->turns++;
|
||||
switch (next_turn->type) {
|
||||
case T_MOVE:
|
||||
// On récupère les caractéristiques du tour
|
||||
t_move* history_move = next_turn->tmove;
|
||||
// On teste si le joueur avait été attaqué
|
||||
if (history_move->killer != -1) {
|
||||
g->player_alive = false;
|
||||
}
|
||||
// On deplace le joueur
|
||||
free_occupied_maze(g->m, g->m->player);
|
||||
g->m->player = get_adj_maze(g->m, g->m->player, (cardinal)(history_move->playermove));
|
||||
g->player_dir = (cardinal)((history_move->playermove));
|
||||
make_occupied_maze(g->m, g->m->player);
|
||||
// On re-recupère l'objet
|
||||
if (history_move->obj != NONE) {
|
||||
game_consume_object(g, 1, history_move->obj);
|
||||
g->m->objects[g->m->player] = NONE;
|
||||
}
|
||||
|
||||
// On gère les déplacements des minotaures
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
if (g->minotaurs_alive[i]) {
|
||||
// Si le minotaure est vivant on refait son déplacement
|
||||
if (history_move->minomoves[i] != M_WAIT) {
|
||||
free_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->m->minotaurs[i] = get_adj_maze(g->m, g->m->minotaurs[i], (cardinal)(history_move->minomoves[i]));
|
||||
make_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
g->minotaurs_dirs[i] = (cardinal)(history_move->minomoves[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
case T_BOMB:
|
||||
t_bomb* history_bomb = next_turn->tbomb;
|
||||
// Si un mur avait été détruit puis reconstruit
|
||||
if (history_bomb->destroyed) {
|
||||
// On teste si le joueur a été attaqué
|
||||
if (history_bomb->killer != -1) {
|
||||
g->player_alive = false;
|
||||
}
|
||||
// On reconstruit le mur
|
||||
del_wall_maze(g->m, g->m->player, history_bomb->bombdir);
|
||||
}
|
||||
return true;
|
||||
case T_POLY:
|
||||
bool* history_poly = next_turn->minokilled;
|
||||
// On tue les minotaures qui avaient été ressucités
|
||||
for (int i = 0; i < g->m->nb_minotaurs; i++) {
|
||||
if (history_poly[i]) {
|
||||
g->minotaurs_alive[i] = false;
|
||||
free_occupied_maze(g->m, g->m->minotaurs[i]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user