298 lines
8.4 KiB
C
298 lines
8.4 KiB
C
#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);
|
|
}
|
|
|
|
|