Robobyrinthe/astar.c

299 lines
8.4 KiB
C
Raw Permalink Normal View History

2020-09-28 20:19:35 +02:00
#include "fonction.h"
t_move** Astar(Position pos1, Position tresor, char* labData, int size_x, int size_y){ //Trouve le chemin le plus rapide vers le trésor
//Initialisation des variables et structures
int i;
ListeC closedList=NULL, openList=NULL, temp_list, min_list;
Position voisins[4], cp;
Case D; //Case de départ de l'A*
t_move** itineraire=NULL;
//Initialisation de la case de départ
(D.pos).x=pos1.x;
(D.pos).y=pos1.y;
D.cost=0;
D.prev=estimation_distance(D.pos, tresor, size_x,size_y);
D.prec=NULL; //Indicateur Case de départ
//Initialisation de l'openList
openList=ajout_case(D,openList);
//Algorithme A*
while(openList!=NULL){
//Reinitialisation des variables
min_list=NULL;
temp_list=openList;
//Recherche de la case proposant la plus faible estimation
while(temp_list!=NULL){
if(min_list==NULL ||((min_list->c).prev) > ((temp_list->c).prev)){
min_list=temp_list;
}
temp_list=temp_list->suiv;
}
//Retrait de la case d'openList
temp_list=openList;
if(temp_list==min_list){ //Si on supprime le premier element
openList=min_list->suiv;
}
else{
while(temp_list->suiv!=min_list){ //Si on supprime un des élément restant
temp_list=temp_list->suiv;
}
temp_list->suiv=min_list->suiv;
}
//Transfert de la case de openList en tete de closedList
min_list->suiv = closedList;
closedList = min_list;
cp = (closedList->c).pos; //Case considérée = permiere case de closedList
//Verification case tresor et sortie de boucle si c'est le cas
if(verif_positions(cp,tresor)){ //Si on est arrivé au trésor
itineraire= chemin(closedList->c);
break;
}
//Determination des voisins sinon
voisins[0].x=cp.x+1;
voisins[0].y=cp.y;
ajust_pos(voisins, size_x, size_y);
voisins[1].x=cp.x-1;
voisins[1].y=cp.y;
ajust_pos(voisins+1, size_x, size_y);
voisins[2].x=cp.x;
voisins[2].y=cp.y+1;
ajust_pos(voisins+2, size_x, size_y);
voisins[3].x=cp.x;
voisins[3].y=cp.y-1;
ajust_pos(voisins+3, size_x, size_y);
//Verification si les voisins n'ont pas déja ete evaluées (dans openList ou closedList) ou qu'il ne soit pas des murs
verif_voisins(voisins, openList);
verif_voisins(voisins, closedList);
verif_voisins_mur(voisins, labData, size_x);
//Ajout des voisins à openList
for(i=0;i<4;i++){
if((voisins[i]).x!=-1){ //si elle n'as pas déja été evaluée et quelle n'est pas un mur
D = newCase(&(closedList->c), (voisins[i]).x, (voisins[i]).y, tresor, size_x, size_y);
openList=ajout_case(D,openList);
}
}
}
//Liberation de memoire lorsque que l'itineraire est determine
free_liste(openList);
free_liste(closedList);
return itineraire;
}
void Astaromove(t_move* move, t_move** itineraire, Position pos1, Position tresor, char* labData, int size_x, int size_y){ //Joue sans rotation pour aller le plus rapidement possible au trésor
//S'il n'y a pas eu de rotations, pas besoin de recalculer l'itinéraire
if((itineraire==NULL)||(move->type==ROTATE_LINE_LEFT)||(move->type==ROTATE_LINE_RIGHT)||(move->type==ROTATE_COLUMN_UP)||(move->type==ROTATE_COLUMN_DOWN)){
//Suppression de l'ancien itinéraire
free_itineraire(itineraire);
itineraire = NULL;
itineraire= Astar(pos1, tresor, labData, size_x, size_y);
}
//Envoie du move
if(itineraire==NULL){ //Pas de solution trouvé
move->type=DO_NOTHING;
move->value=0;
printf("\n Pas de chemin trouvé : STAND BY\n");
}
else{
move->type=(itineraire[0])->type;
move->value=0;
//Suppression du move dans itineraire
free(*itineraire);
itineraire=&(itineraire[1]);
}
#ifdef DEBUG
printf("Move type :%d\n",move->type);
printf("Move Value: %d",move->value);
#endif
}
int estimation_distance(Position J, Position P, int sizeX, int sizeY){
int dx, dy;
dx = fabs(P.x - J.x); //Différence selon les colonnes
dy = fabs(P.y - J.y); //Différence selon les lignes
if (dx > sizeX/2) {dx = sizeX - dx;} //Si c'est mieux de passer de l'autre côté d'un mur gauche-droite
if (dy > sizeY/2) {dy = sizeY - dy;} //Si c'est mieux de passer de l'autre côté d'un mur haut-bas
return dx + dy;
}
Case newCase(Case* c, int x, int y, Position tresor, int sizeX, int sizeY){ //Initialise une case voisine à c par ces coordonées (x,y)
Case v; //case voisine de c
(v.pos).x=x;
(v.pos).y=y;
#ifdef DEBUG
if(estimation_distance(c->pos,v.pos,sizeX,sizeY)!=1){
printf("\n newCase Error : cases non voisines :(%d,%d) -> (%d,%d)\n",(c->pos).x,(c->pos).y,(v.pos).x,(v.pos).y);
printf("Esti : %d\n",estimation_distance(c->pos,v.pos,sizeX,sizeY));
}
#endif
v.cost = c->cost+1;
v.prev=v.cost+estimation_distance(v.pos, tresor,sizeX,sizeY);
v.prec=c;
return v;
}
ListeC ajout_case(Case c, ListeC liste){ //Ajoute c en début de liste
ListeC nliste;
nliste=(ListeC)malloc(sizeof(Element)); // Allocation mémoire?
nliste->c=c;
nliste->suiv=liste;
return nliste;
}
void verif_voisins(Position* voisins, ListeC liste){ //Modifie voisins pour qu'il ne reste que des cases non évaluées qui ne soit pas des murs
int i;
ListeC temp_list=liste;
while(temp_list!=NULL){
for(i=0;i<4;i++){
if(verif_positions(voisins[i],(temp_list->c).pos)){
voisins[i].x=-1;
}
}
temp_list=temp_list->suiv;
}
}
void verif_voisins_mur(Position* voisins, char* labData, int size_x){ //Modifie voisins pour qu'il ne reste que des cases qui ne sont pas des murs
int i;
for(i=0;i<4;i++){
if(test_case(voisins[i], labData, size_x)==0){
voisins[i].x=-1;
}
}
}
int verif_positions (Position P1, Position P2){ //retourne 1 si P1 et P2 ont les mêmes coordonées, 0 sinon
if((P1.x==P2.x)&&(P1.y==P2.y)){
return 1;
}
else{
return 0;
}
}
t_move** chemin(Case c){ //donne l'itinéraire depuis le départ pour aller jusqu'à c
Case* temp_case=&c;
Position temp_pos;
int i, nb_move=0;
t_move** itineraire;
while (temp_case != NULL){ //On détermine combien de mouvement seront nécessaires
temp_case=temp_case->prec;
nb_move++;
}
itineraire=(t_move**)malloc((nb_move)*sizeof(t_move*));
//Création de l'itinéraire
temp_case=&c;
itineraire[nb_move-1]=NULL;//Fin de l'itinéraire
for(i=nb_move-2;i>=0;i--){//Construction décroissante car on part du trésor pour arriver au départ
temp_pos=temp_case->pos;
temp_case=temp_case->prec;
itineraire[i]= move_pos(temp_case->pos,temp_pos);
}
return itineraire;
}
t_move* move_pos(Position Ini, Position Fin){ //Donne le mouvement pour aller de Ini a Fin
//MOVE_UP = 4, MOVE_DOWN = 5, MOVE_LEFT = 6, MOVE_RIGHT = 7, DO_NOTHING = 8
int dx, dy;
t_move* pmove=(t_move*)malloc(sizeof(t_move));
dx=Fin.x-Ini.x;
dy=Fin.y-Ini.y;
if(dx!=0){
if(dx==1||dx<0){
pmove->type=7;
}
if(dx==-1||dx>1){
pmove->type=6;
}
}
if(dy!=0){
if(dy==1||dy<0){
pmove->type=5;
}
if(dy==-1||dy>1){
pmove->type=4;
}
}
if(dx==0&&dy==0){
pmove->type= 8;
}
pmove->value=0;
return pmove;
}
void free_itineraire(t_move** itineraire){
//Cas ou itineraire n'est pas defini
if(itineraire == NULL) {return;}
int i=0;
t_move* temp=itineraire[0];
while(temp!=NULL){
free(temp);
temp=itineraire[i];
i++;
}
free(itineraire);
}
void free_liste(ListeC liste){
//Cas ou Liste n'est pas defini
if(liste == NULL) {return;}
ListeC temp = liste, suivant = NULL;
while(temp->suiv!=NULL){
suivant = temp->suiv;
free(temp);
temp=suivant;
}
free(temp);
}