Initial commit

This commit is contained in:
Antoine Harle 2020-09-28 20:19:35 +02:00
parent ab6c3353e2
commit 13161bcbd7
17 changed files with 1335 additions and 0 deletions

173
LABY Normal file
View file

@ -0,0 +1,173 @@
/*
* ------------------------ *
| |
| -= LabyrinthAPI =- |
| |
* ------------------------ *
Authors: T. Hilaire, J. Brajard
Licence: GPL
Status: beta version
File: labyrinthAPI.h
Contains the client API for the Labyrinth game
*/
#ifndef __API_CLIENT_LABYRINTH__
#define __API_CLIENT_LABYRINTH__
#include "ret_type.h"
typedef enum
{
ROTATE_LINE_LEFT = 0,
ROTATE_LINE_RIGHT = 1,
ROTATE_COLUMN_UP = 2,
ROTATE_COLUMN_DOWN = 3,
MOVE_UP = 4,
MOVE_DOWN = 5,
MOVE_LEFT = 6,
MOVE_RIGHT = 7,
DO_NOTHING = 8
} t_typeMove;
/*
A move is a tuple (type,value):
- type can be ROTATE_LINE_LEFT, ROTATE_LINE_RIGHT, ROTATE_COLUMN_UP,
ROTATE_COLUMN_DOWN, MOVE_LEFT, MOVE_RIGHT, MOVE_UP or MOVE_DOWN
- in case of rotation, the value indicates the number of the line
(or column) to be rotated
*/
typedef struct
{
t_typeMove type; /* type of the move */
int value; /* value associated with the type
(number of the line or the column to rotate)*/
} t_move;
/* -------------------------------------
* Initialize connection with the server
* Quit the program if the connection to the server
* cannot be established
*
* Parameters:
* - serverName: (string) address of the server
* (it could be "localhost" if the server is run in local,
* or "pc4521.polytech.upmc.fr" if the server runs there)
* - port: (int) port number used for the connection
* - name: (string) name of the bot : max 20 characters
* (checked by the server)
*/
void connectToServer( char* serverName, int port, char* name);
/* ----------------------------------
* Close the connection to the server
* to do, because we are polite
*
* Parameters:
* None
*/
void closeConnection();
/* ----------------------------------------------------------------
* Wait for a Game, and retrieve its name and first data
* (typically, array sizes)
*
* Parameters:
* - training: string (max 50 characters) type of the training
* player we want to play with
* (empty string for regular game)
* - labyrinthName: string (max 50 characters),
* corresponds to the game name
* - sizeX, sizeY: sizes of the labyrinth
*
* training is a string like "NAME key1=value1 key2=value1 ..."
* - NAME can be empty. It gives the type of the training player
* - key=value pairs are used for options
* (each training player has its own options)
* invalid keys are ignored, invalid values leads to error
* the following options are common to every training player
* (when NAME is not empty):
* - timeout: allows an define the timeout
* when training (in seconds)
* the NAME could be:
* - "DO_NOTHING" to play against DO_NOTHING player
* (player that does not move)
* - "PLAY_RANDOM" for a player that make random (legal) moves
* (option "rotation=False/True")
*/
void waitForLabyrinth( char* training, char* labyrinthName,
int* sizeX, int* sizeY);
/* -------------------------------------
* Get the labyrinth and tell who starts
* It fills the char* lab with the data of the labyrinth
* 1 if there's a wall, 0 for nothing
*
* Parameters:
* - lab: the array of labyrinth
* (the pointer data MUST HAVE allocated with the right size !!)
*
* Returns 0 if you begin, or 1 if the opponent begins
*/
int getLabyrinth( char* lab);
/* ----------------------
* Get the opponent move
*
* Parameters:
* - move: a move
*
* Returns a return_code
* MOVE_OK for normal move,
* MOVE_WIN for a winning move, -1
* MOVE_LOSE for a losing (or illegal) move
* this code is relative to the opponent (MOVE_WIN if HE wins, ...)
*/
t_return_code getMove( t_move* move );
/* -----------
* Send a move
*
* Parameters:
* - move: a move
*
* Returns a return_code
* MOVE_OK for normal move,
* MOVE_WIN for a winning move, -1
* MOVE_LOSE for a losing (or illegal) move
* this code is relative to your programm (MOVE_WIN if YOU win, ...)
*/
t_return_code sendMove( t_move move );
/* ----------------------
* Display the labyrinth
* in a pretty way (ask the server what to print)
*/
void printLabyrinth();
/* ----------------------------
* Send a comment to the server
*
* Parameters:
* - comment: (string) comment to send to the server (max 100 char.)
*/
void sendComment(char* comment);
#endif

6
Notes Normal file
View file

@ -0,0 +1,6 @@
ssh -Y 3408017@pc57.polytech.upmc.fr
"PLAY_RANDOM" for a player that make random (legal) moves
* (option "rotate=False/True")
Position n'as pas besoin d'avoir une allocation mémoire (malloc) en tant que structure ?

Binary file not shown.

111
Patchs/Patch Astaromove.txt Normal file
View file

@ -0,0 +1,111 @@
SUGGESTIONS DE PATCH
FONCTION.C
l.242 : soucis potentiel avec la circularité du bidule labyrinthe pour le calcul de l'heuristique, du chemin...
(l.273) : première condition du while superflue ?
l.283 : traiter séparemment le cas où il n'y qu'un élément dans l'openlist :
...
//Suppression de la case d'openList
temp_list=openList;
if temp_list->suiv == NULL //S'il n'y qu'un seul element, t'es sur duquel faut supprimer
openList == NULL
while(temp_list->suiv!=temp){
temp_list=temp_list->suiv;
}
temp_list->suiv=temp->suiv;
free(temp);
...
(l.280) : pour eviter de creer une autre structure et faire un free de l'ancienne ou pourrait faire (a mettre apres le retrait de temp de l'openlist) :
...
while(temp_list->suiv!=temp){
temp_list=temp_list->suiv;
}
temp_list->suiv=temp->suiv;
//Transfert de la case de openList vers closedList
temp->suiv = closedList;
closedList = temp;
...
(l.407) : tableau de int pour itinéraire plus simple, a changer :
...
//Création de l'itinéraire
temp_case=&c;
for(i=0;i<nb_move;i++){
temp_pos=temp_case->pos;
temp_case=temp_case->prec;
n = move_pos(temp_case->pos,temp_pos);
itineraire[i]= n;
}
itineraire[i]=0;
}
...
CHANGER
int move_pos(Position Ini, Position Fin){ //Donne le mouvement pour aller de Ini a Fin
int m;
int dx, dy;
dx=Fin.x-Ini.x;
if(dx!=0){
if(dx==1){
m = 7;
}
else{
m = 6;
}
}
dy=Fin.y-Ini.y;
if(dy!=0){
if(dy==1){
m = 5;
}
else{
m = 4;
}
}
else{
m = 8;
}
return m;
}
...
CHANGER
void free_itineraire(int* itineraire)
(l.414) : On ne compte pas la case de départ comme un move
while (temp_case->suiv != NULL){ //On détermine combien de mouvement seront nécessaire
temp_case=temp_case->prec;
nb_move++;
}
Du coup on peut supprimer l.428.
FONCTION.H
(l.32) : structure lourde pour la mémoire, utilisation d'un pointeur ? :
...
//Déclaration Liste chainée de Case
typedef struct element Element;
struct element{
Case* c;
Element* suiv;
};
typedef Element* ListeC;
...

35
Patchs/patch random.txt Normal file
View file

@ -0,0 +1,35 @@
#define CV(x,y,size_x) x + y*size_x
void rotation_lab(char* labData, t_move move, int size_x, int size_y){ //Modifie le labyrinthe en cas de rotation (POSSIBILITE : Placer les lignes de codes des if dans pos_suivante)
int i, temp;
if(move.type==ROTATE_LINE_LEFT){
temp=labData[CV(i,move.value,size_x)]; // On garde en mémoire le terme du tableau qui va passer de l'autre côté du labyrinthe avec la rotation (Ici, le 1er terme)
for(i=0;i<size_x-1;i++){ //On parcours la ligne en question en échangeant les termes vers la gauche
labData[CV(i,move.value,size_x)]=labData[CV(i+1,move.value,size_x)];
}
labData[CV(size_x-1,move.value,size_x)]=temp; // On place le terme a la fin de la ligne
}
if(move.type==ROTATE_LINE_RIGHT){
temp=labData[CV(size_x-1,move.value,size_x)]; //On garde en mémoire le dernier terme de la ligne
for(i=size_x-1;i>0;i--){//On parcours la ligne en sens inverse en échangeant les termes vers la droite
labData[CV(i,move.value,size_x)]=labData[CV(i-1,move.value,size_x)];
}
labData[CV(0,move.value,size_x)]=temp; //On place le terme au début de la ligne
}
if(move.type==ROTATE_COLUMN_UP){
temp=labData[move.value]; //On garde en mémoire le 1er terme de la colonne
for(i=0;i<size_y-1;i++){ //On parcours la colonne de haut en bas en échangeant les terme vers le haut
labData[CV(move.value, i, size_x)]=labData[CV(move.value, i+1, size_x)];
}
labData[CV(move.value,size_y-1,size_x)]=temp; //On place le terme la fin de la colonne
}
if(move.type==ROTATE_COLUMN_DOWN){
temp=labData[CV(move.value, size_y-1, size_x)]; //On garde en mémoire le dernier terme de la colonne
for(i=size_y-1;i>0;i--){ //On parcours la colonne de bas en haut en échangeant vers le bas
labData[CV(move.value,i,size_x)]=labData[CV(move.value,i-1,size-x)];
}
labData[CV(move.value,0,size_x)]=temp; //On place le terme au début de la colonne
}
}

Binary file not shown.

24
Test/main.c Normal file
View file

@ -0,0 +1,24 @@
#include <stdio.h>
typedef struct position{
int x;
int y;
} Position;
int main (){
Position p1,p2;
p1.x = 1;
p1.y = 2;
p2 = p1;
p2.x = 3;
printf("p1.x = %d\np1.y = %d\np2.x = %d\np2.y = %d\n", p1.x,p1.y,p2.x,p2.y);
return 0;
}

37
Test/test.c Normal file
View file

@ -0,0 +1,37 @@
//Fait un move aléatoire
#include <time.h>
#include <stdlib.h>
//Choisit un type de mouvement aléatoire et une ligne/colonne aléatoire si rotation
void random_move(t_move* move, int size_x, int size_y){
srand(time(NULL));
int n1, n2;
n1 = rand()%9;
move->type = n1; //Choisit une type de move aléatoire
move->value = 0;
if (n1==2 || n1==3){ //Cas où on bouge une colonne, il y a size_x colonnes
n2 = rand()%size_x;
move->value = n2; //Choisit une colonne aléatoire à bouger
}
else if (n1==0 || n1==1){ //Cas où on bouge une ligne, il y a size_y lignes
n2 = rand()%size_y;
move->value = n2; //Choisit une ligne aléatoire à bouger
}
}
//Convertit une position en deux dimensions en une position en une dimension (pour manipuler labData)
int convert(Position pos, int size_x){
return pos->x + pos->y * (size_x + 1);
}
//Renvoie 1 si la case en bonne, renvoie 0 si la case n'est pas bonne
int test_case(Position pos, char* labData, int size_x){
if (labData[convert(pos, size_x)] == 1){return 0;}
else {return 1;}
}

298
astar.c Normal file
View file

@ -0,0 +1,298 @@
#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);
}

BIN
enonce.pdf Normal file

Binary file not shown.

187
fonction.c Normal file
View file

@ -0,0 +1,187 @@
#include "fonction.h"
void defmove(t_move* move){
int a;
printf("\n Déplacement - ROTATE_LINE_LEFT = 0, ROTATE_LINE_RIGHT = 1, ROTATE_COLUMN_UP = 2, ROTATE_COLUMN_DOWN = 3, MOVE_UP = 4, MOVE_DOWN = 5, MOVE_LEFT = 6, MOVE_RIGHT = 7, DO_NOTHING = 8\n");
scanf(" %d", &a);
move->type = a;
if(move->type <= 3){
printf("Indice de ligne/colonne à rotater ; le (0,0) est en haut à gauche : ");
scanf(" %d", &(move->value));
}
else {move->value=0;}
}
void print_labdata(char* labData, int size_x, int size_y){ //Affiche la structure du labyrinthe en binaire
int i;
printf("\n");
for(i=0; i<(size_x * size_y); i++){
if(labData[i]==0){ printf(" "); }
else{ printf("@ "); }
if ((i+1)%size_x == 0){printf("\n");}
}
}
void init_info(Position* J1, Position* J2, Position* Tresor, int* En1, int* En2, int player, int size_x, int size_y){ //Initialise les infos du labyrinthe de tout les éléments (J1 : Nous / J2 : Adversaire)
if(player==0){ //On commence
J1->x=0;
J1->y=size_y/2;
J2->x=size_x-1;
J2->y=size_y/2;
*En2=2;
}
else{ //L'adversaire commence
J2->x=0;
J2->y=size_y/2;
J1->x=size_x-1;
J1->y=size_y/2;
*En1=2;
}
//Position trésor
Tresor->x=size_x/2;
Tresor->y=size_y/2;
}
void info_suivante(t_move move, Position* pos1, Position* pos2, Position* tresor, int* E, char* labData, int size_x, int size_y){ //Actualise les infos du labyrinthe (pos1 = joueur actif)
switch(move.type){
case ROTATE_LINE_LEFT:
rotation_pos(pos1, move);
rotation_pos(pos2, move);
rotation_pos(tresor, move);
rotation_lab(labData, move, size_x, size_y);
(*E)-=5;
break;
case ROTATE_LINE_RIGHT:
rotation_pos(pos1, move);
rotation_pos(pos2, move);
rotation_pos(tresor, move);
rotation_lab(labData, move, size_x, size_y);
(*E)-=5;
break;
case ROTATE_COLUMN_UP:
rotation_pos(pos1, move);
rotation_pos(pos2, move);
rotation_pos(tresor, move);
rotation_lab(labData, move, size_x, size_y);
(*E)-=5;
break;
case ROTATE_COLUMN_DOWN:
rotation_pos(pos1, move);
rotation_pos(pos2, move);
rotation_pos(tresor, move);
rotation_lab(labData, move, size_x, size_y);
(*E)-=5;
break;
case MOVE_UP:
pos1->y-=1;
(*E)++;
break;
case MOVE_DOWN:
pos1->y+=1;
(*E)++;
break;
case MOVE_LEFT:
pos1->x-=1;
(*E)++;
break;
case MOVE_RIGHT:
pos1->x+=1;
(*E)++;
break;
case DO_NOTHING:
(*E)++;
break;
}
ajust_pos(pos1, size_x, size_y);
ajust_pos(pos2, size_x, size_y);
ajust_pos(tresor, size_x, size_y);
}
//Ajuste la position de pos pour les depassement d'extrémités
void ajust_pos(Position* pos, int size_x, int size_y){
if(pos->y<0){ pos->y=size_y-1; } //Limite haute du labyrinthe, on passe a l'autre extremité
if(pos->y>=size_y){ pos->y=0; } //Limite basse du labyrinthe, on passe a l'autre extremité
if(pos->x<0){ pos->x=size_x-1; } //Limite gauche du labyrinthe, on passe a l'autre extremité
if(pos->x>=size_x){ pos->x=0; } // Limite droite du labyrinthe, on passe a l'autre extremité
}
void rotation_pos(Position* pos, t_move move){ //Déplace l'élément en pos s'il se situe sur une rotation
if(move.value==pos->x){ //Si notre élement en pos se situe sur un mouvement d'une colonne
if(move.type==ROTATE_COLUMN_UP){ pos->y-=1; }
if(move.type==ROTATE_COLUMN_DOWN){ pos->y+=1; }
}
if(move.value==pos->y){ //Si notre élement en pos se situe sur un mouvement d'une ligne
if(move.type==ROTATE_LINE_LEFT){ pos->x-=1; }
if(move.type==ROTATE_LINE_RIGHT){ pos->x+=1; }
}
}
void rotation_lab(char* labData, t_move move, int size_x, int size_y){ //Modifie le labyrinthe en cas de rotation (POSSIBILITE : Placer les lignes de codes des if dans pos_suivante)
int i, temp;
if(move.type==ROTATE_LINE_LEFT){
temp=labData[(move.value*size_x)]; // On garde en mémoire le terme du tableau qui va passer de l'autre côté du labyrinthe avec la rotation (Ici, le 1er terme)
for(i=0;i<size_x-1;i++){ //On parcours la ligne en question en échangeant les termes vers la gauche
labData[(move.value*size_x)+i]=labData[(move.value*size_x)+i+1];
}
labData[((move.value+1)*size_x)-1]=temp; // On place le terme a la fin de la ligne
}
if(move.type==ROTATE_LINE_RIGHT){
temp=labData[((move.value+1)*size_x)-1]; //On garde en mémoire le dernier terme de la ligne
for(i=size_x-1;i>0;i--){//On parcours la ligne en sens inverse en échangeant les termes vers la droite
labData[(move.value*size_x)+i]=labData[(move.value*size_x)+i-1];
}
labData[(move.value*size_x)]=temp; //On place le terme au début de la ligne
}
if(move.type==ROTATE_COLUMN_UP){
temp=labData[move.value]; //On garde en mémoire le 1er terme de la colonne
for(i=1;i<size_y-1;i++){ //On parcours la colonne de haut en bas en échangeant les terme vers le haut
labData[move.value+size_x*(i-1)]=labData[move.value+size_x*i];
}
labData[size_x*(size_y-1)+move.value]=temp; //On place le terme la fin de la colonne
}
if(move.type==ROTATE_COLUMN_DOWN){
temp=labData[size_x*(size_y-1)+move.value]; //On garde en mémoire le dernier terme de la colonne
for(i=size_y-1;i>0;i--){ //On parcours la colonne de bas en haut en échangeant vers le bas
labData[move.value+size_x*i]=labData[move.value+size_x*(i-1)];
}
labData[move.value]=temp; //On place le terme au début de la colonne
}
}
//Convertit une position en deux dimensions en une position en une dimension (pour manipuler labData)
int convert(Position pos, int size_x){
return pos.x + pos.y * size_x;
}
//Renvoie 1 si la case est libre, renvoie 0 si la case n'est pas libre
int test_case(Position pos, char* labData, int size_x){ //Il faut bien mettre size_x c-a-d longueur d'une ligne c-a-d nombre de colonnes
if (labData[convert(pos, size_x)] == 1){return 0;}
else {return 1;}
}

71
fonction.h Normal file
View file

@ -0,0 +1,71 @@
#ifndef __FONCTION_H__
#define __FONCTION_H__
#include <stdio.h>
#include <stdlib.h>
#include "labyrinthAPI.h"
#include <time.h>
#include <math.h>
#include <string.h>
//#define DEBUG
//DEFMOVE
typedef struct position{
int x;
int y;
} Position;
void defmove(t_move * move); //Fonction de mouvement manuel
void print_labdata(char* labData, int size_x, int size_y); //Affiche la structure du labyrinthe en binaire
void init_info(Position* J1, Position* J2, Position* Tresor, int* En1, int* En2, int player, int size_x, int size_y); //Initialise les infos du labyrinthe de tout les éléments (J1 : Nous / J2 : Adversaire)
void info_suivante(t_move move, Position* pos1, Position* pos2, Position* tresor, int* E, char* labData, int size_x, int size_y); //Actualise les infos du labyrinthe (pos1 = joueur actif)
void ajust_pos(Position* pos, int size_x, int size_y); //Ajuste la position de pos pour les depassement d'extrémités
void rotation_pos(Position* pos, t_move move); //Déplace l'élément en pos s'il se situe sur une rotation
void rotation_lab(char* labData, t_move move, int size_x, int size_y); //Modifie le labyrinthe en cas de rotation (POSSIBILITE : Placer les lignes de codes des if dans pos_suivante)
//RANDOM
void randomove(t_move* move, Position pos1, int E, char* labData, int size_x, int size_y); //Joue aléatoirement et légalement
int convert(Position pos, int size_x); //Convertit une position en deux dimensions en une position en une dimension (pour manipuler labData)
int test_case(Position pos, char* labData, int size_x); //Il faut bien mettre size_x c-a-d longueur d'une ligne c-a-d nombre de colonnes //Renvoie 1 si la case est libre, renvoie 0 si la case n'est pas libre
//ASTAR
typedef struct cases Case;
struct cases{
Position pos; //Case actuelle
int cost; //Coût du départ à cette position
int prev; //Prevision du coût total, du départ au tresor en passant par cette position
Case* prec; //Case d'où on vient
};
typedef struct element Element;
struct element{
Case c;
Element* suiv;
};
typedef Element* ListeC;
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
t_move** Astar(Position pos1, Position tresor, char* labData, int size_x, int size_y); // Trouve le chemin le plus rapide jusqu'au tresor
int estimation_distance(Position J, Position P, int sizeX, int sizeY); //Estimation de l'heuristique
Case newCase(Case* c, int x, int y, Position tresor,int sizeX, int sizeY); //Initialise une case voisine à c par ces coordonées
ListeC ajout_case(Case c, ListeC liste); //Ajoute c en début de liste
void verif_voisins(Position* voisins, ListeC liste); //Modifie voisins pour qu'il ne reste que des cases non évaluées
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 verif_positions (Position P1, Position P2); //retourne 1 si P1 et P2 ont les mêmes coordonées, 0 sinon
t_move** chemin(Case c); //donne l'itinéraire depuis le départ pour aller jusqu'à c
t_move* move_pos(Position Ini, Position Fin); //Donne le mouvement pour aller de Ini a Fin
void free_itineraire(t_move** itineraire); //Libere un tableau de move
void free_liste(ListeC liste); //Libere une liste d'Element
//SMART
void smartmove(t_move* move, t_move** actions, int E1, Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y); //Joue avec une stratégie pour gagner !
void smartRotate(t_move* movef, int E1, Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y); //Cherche la rotation la plus avantageuse avec une amplitude de recherche de varX, varY
int astarCompare(Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y); //Retourne le nombre de coup d'avance sur l'adversaire (pos1 = Joueur Actif)
int nbcoup(t_move** itineraire);//Détermine le nombre de coup necessaire pour faire l'itineraire
void reset_info(Position p1, Position* pt1, Position p2, Position* pt2, Position pt, Position* ptt, char* labData, char** labTest); //Remet les infos du labyrinthe avant un test de rotation
int update_move(t_move* movef, t_move move, int avance, int temp); //Change le move retenu si le move propose est plus interessant
#endif

34
makefile Normal file
View file

@ -0,0 +1,34 @@
# Modèle de fichier Makefile pour le fichier template.c
LIBDIR = /home/sasl/encad/brajard/projet/CGS_lib
# options de compilation
CC = gcc
CCFLAGS = -Wall -I $(LIBDIR)/include
LIBS = -L $(LIBDIR)/lib
LDFLAGS = -lm -lcgs
# fichiers du projet
SRC = template.c fonction.c random.c astar.c smartstar.c
OBJ = $(SRC:.c=.o)
EXEC = template
# règle initiale
all: $(EXEC)
# dépendance des .h
template.o:
# règles de compilation
%.o: %.c
$(CC) $(CCFLAGS) -o $@ -c $<
# règles d'édition de liens
$(EXEC): $(OBJ)
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
# règles supplémentaires
clean:
rm -f *.o
rmproper:
rm -f $(EXEC) *.o

34
makefile (1) Normal file
View file

@ -0,0 +1,34 @@
# Modèle de fichier Makefile pour le fichier template.c
LIBDIR = /home/sasl/encad/brajard/projet/CGS_lib
# options de compilation
CC = gcc
CCFLAGS = -Wall -I $(LIBDIR)/include
LIBS = -L $(LIBDIR)/lib
LDFLAGS = -lm -lcgs
# fichiers du projet
SRC = template.c fonction.c random.c astar.c smartstar.c
OBJ = $(SRC:.c=.o)
EXEC = template
# règle initiale
all: $(EXEC)
# dépendance des .h
template.o:
# règles de compilation
%.o: %.c
$(CC) $(CCFLAGS) -o $@ -c $<
# règles d'édition de liens
$(EXEC): $(OBJ)
$(CC) -o $@ $^ $(LIBS) $(LDFLAGS)
# règles supplémentaires
clean:
rm -f *.o
rmproper:
rm -f $(EXEC) *.o

58
random.c Normal file
View file

@ -0,0 +1,58 @@
#include "fonction.h"
void randomove(t_move* move, Position pos1, int E, char* labData, int size_x, int size_y){ //Joue aléatoirement et légalement
int tabM[] ={-1, -1, -1, -1, -1, -1, -1, -1, 1};
int i;
Position postemp;
srand(time(NULL));
//Validité de la rotation
if(E>4){ // Suffisament d'energie pour une rotation
for(i=0;i<4;i++){ tabM[i]=1; }
}
//Validité des cases voisines
postemp = pos1; //UP
postemp.y-=1;
ajust_pos(&postemp, size_x, size_y);//Calcul de la position haut
if (test_case(postemp, labData, size_x) == 1) {tabM[4] = 1;} //Test validité position haut
postemp = pos1; //DOWN
postemp.y+=1;
ajust_pos(&postemp, size_x, size_y);
if (test_case(postemp, labData, size_x) == 1) {tabM[5] = 1;}
postemp = pos1; //LEFT
postemp.x-=1;
ajust_pos(&postemp, size_x, size_y);
if (test_case(postemp, labData, size_x) == 1) {tabM[6] = 1;}
postemp = pos1; //RIGHT
postemp.x+=1;
ajust_pos(&postemp, size_x, size_y);
if (test_case(postemp, labData, size_x) == 1) {tabM[7] = 1;}
//Aléatoire
do {
i = rand()%9;
}while (tabM[i]!=1);
move->type=i; //Type de mouvement aléatoire
if(move->type<2){ //Si rotation Ligne
i = rand()%size_y;
move->value=i;
}
else if (move->type<4){ //Si rotation Colonne
i = rand()%size_x;
move->value=i;
}
#ifdef DEBUG
printf("Move type :%d\n",move->type);
printf("Move Value: %d",move->value);
#endif
}

139
smartstar.c Normal file
View file

@ -0,0 +1,139 @@
#include "fonction.h"
void smartmove(t_move* move, t_move** actions, int E1, Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y){ //Joue avec une stratégie pour gagner !
if(astarCompare(pos1,pos2,tresor,labData,size_x,size_y)<1 && E1>=5){
smartRotate(move,E1,pos1,pos2,tresor,labData,size_x,size_y);
}
if(move->type==8){
Astaromove(move, actions, pos1, tresor, labData, size_x, size_y);
}
}
//NOTE : SI aucun move avantageux trouvé, on change var de facon a faire des recherches sur tout le labyrinthe
void smartRotate(t_move* movef, int E1, Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y){ //Cherche la rotation la plus avantageuse avec une amplitude de recherche de varX, varY
char* labTest; //Labyrinthe temporaire
t_move test_move;
Position ptest1, ptest2, ptestt;
int avance=0,temp=0,i=0,varX=3,varY=3; //var indique la largeur des recherches autour du tresor
//Initialisation
movef->type=8;
movef->value=0;
labTest = strdup(labData); //Malloc
//Evaluations des lignes
for(i=tresor.y-varY; i<tresor.y+varY; i++){
//Rotation vers la gauche
test_move.type=0;
test_move.value=i;
info_suivante(test_move, &ptest1, &ptest2, &ptestt, &E1, labTest, size_x, size_y);
//Calcul de l'avantage de la rotation
temp = astarCompare(ptest1, ptest2, ptestt, labTest, size_x, size_y);
avance = update_move(movef, test_move, avance, temp); //Changement du move final si necessaire
reset_info(pos1, &ptest1, pos2, &ptest2, tresor, &ptestt, labData, &labTest); //Reinitialisation
//Rotation vers la droite
test_move.type=1;
test_move.value=i;
info_suivante(test_move, &ptest1, &ptest2, &ptestt, &E1, labTest, size_x, size_y);
//Calcul de l'avantage de la rotation
temp = astarCompare(ptest1, ptest2, ptestt, labTest, size_x, size_y);
avance = update_move(movef, test_move, avance, temp); //Changement du move final si necessaire
reset_info(pos1, &ptest1, pos2, &ptest2, tresor, &ptestt, labData, &labTest); //Reinitialisation
}
//Evaluations des colonnes
for(i=tresor.x-varX; i<tresor.x+varX; i++){
//Rotation vers le haut
test_move.type=2;
test_move.value=i;
info_suivante(test_move, &ptest1, &ptest2, &ptestt, &E1, labTest, size_x, size_y);
//Calcul de l'avantage de la rotation
temp = astarCompare(ptest1, ptest2, ptestt, labTest, size_x, size_y);
avance = update_move(movef, test_move, avance, temp); //Changement du move final si necessaire
reset_info(pos1, &ptest1, pos2, &ptest2, tresor, &ptestt, labData, &labTest); //Reinitialisation
//Rotation vers le bas
test_move.type=3;
test_move.value=i;
info_suivante(test_move, &ptest1, &ptest2, &ptestt, &E1, labTest, size_x, size_y);
//Calcul de l'avantage de la rotation
temp = astarCompare(ptest1, ptest2, ptestt, labTest, size_x, size_y);
avance = update_move(movef, test_move, avance, temp); //Changement du move final si necessaire
reset_info(pos1, &ptest1, pos2, &ptest2, tresor, &ptestt, labData, &labTest); //Reinitialisation
}
//Free
free(labTest);
}
int astarCompare(Position pos1, Position pos2, Position tresor, char* labData, int size_x, int size_y){ //Retourne le nombre de coup d'avance sur l'adversaire (pos1 = Joueur Actif)
t_move** itineraire1 = NULL;
t_move** itineraire2 = NULL;
int nbcoup1, nbcoup2;
//Estimation des itineraires des joueurs
itineraire1 = Astar(pos1, tresor, labData, size_x, size_y);
itineraire2 = Astar(pos2, tresor, labData, size_x, size_y);
//Estimation du nombre de coup jusqu'au tresor
nbcoup1 = nbcoup(itineraire1);
nbcoup2 = nbcoup(itineraire2);
//Free
free_itineraire(itineraire1);
free_itineraire(itineraire2);
return nbcoup2 - nbcoup1; //Plus c'est positif, plus c'est a notre avantage
}
int nbcoup(t_move** itineraire){//Détermine le nombre de coup necessaire pour faire l'itineraire
int i=0;
if (itineraire[i]!=NULL){
while (itineraire[i]!=NULL){i++;}
i++; //On compte le move de rang 0
}
return i;
}
void reset_info(Position p1, Position* pt1, Position p2, Position* pt2, Position pt, Position* ptt, char* labData, char** labTest){ //Remet les infos du labyrinthe avant un test de rotation
*pt1 = p1;
*pt2 = p2;
*ptt = pt;
strcpy(*labTest, labData);
}
int update_move(t_move* movef, t_move move, int avance, int temp){ //Change le move retenu si le move propose est plus interessant
if(temp>avance){ //Si la rotation est plus intéressante, on la garde
movef->type = move.type;
movef->value = move.value;
return temp;
}
else{
return avance;
}
}

128
template.c Normal file
View file

@ -0,0 +1,128 @@
//
// TEMPLATE
//
//
// Permet de jouer un seul tour (en ne faisant rien s'il commence ou en
// réceptionnant le coup de l'adversaire s'il ne commence pas)
// et termine le jeu.
// Ce programme vous sert de base pour construire votre propre programme
#include <stdio.h>
#include <stdlib.h>
#include "labyrinthAPI.h"
#include <unistd.h>
#include "fonction.h"
extern int debug; /* hack to enable debug messages */
int main()
{
char labName[50]; /* name of the labyrinth */
char* labData; /* data of the labyrinth */
t_return_code ret = MOVE_OK; /* indicates the status of the previous move */
t_move move; /* a move */
t_move** itineraire=NULL;
int player, mode;
int sizeX,sizeY;
int En_M, En_Y; //Energie Me & You
Position Me, You, Tresor;
#ifdef DEBUG
int debug_counter=0;
#endif
/* connection to the server */
connectToServer( "pc4023.polytech.upmc.fr", 1234, "TrumpvsMexico");
/* wait for a game, and retrieve informations about it */
waitForLabyrinth( "ASTAR timeout=100", labName, &sizeX, &sizeY);
labData = (char*) malloc( sizeX * sizeY );
player = getLabyrinth( labData);
//Initialisation des Positions
init_info(&Me, &You, &Tresor, &En_M, &En_Y, player, sizeX, sizeY);
#ifdef DEBUG
print_labdata(labData, sizeX, sizeY);
printf("\nTrump : (%d,%d)", Me.x, Me.y);
printf("\nMexico : (%d,%d)\n", You.x, You.y);
#endif
printf("\nMode de Jeu : 0.Passif / 1.Manuel / 2.Random / 3.Astaromove / 4.Smartmove\n");
scanf(" %d",&mode);
sendComment("We will build a great WALL");
while(ret==MOVE_OK){
/* display the labyrinth */
printLabyrinth();
//print_labdata(labData, sizeX, sizeY);
if (player==1) /* The opponent plays */
{
ret = getMove( &move);
info_suivante(move, &You, &Me, &Tresor, &En_Y, labData, sizeX, sizeY); //Modification des positions
//sendComment("The WALL got 10 feets higher !");
}
else
{
if(mode==0){
move.type=8;
move.value=0;
}
if(mode==1){
defmove(&move);
}
if(mode==2){
randomove(&move, Me, En_M, labData, sizeX, sizeY);
}
if(mode==3){
Astaromove(&move, itineraire, Me, Tresor, labData, sizeX, sizeY);
}
if(mode==4){
move.type=8;
move.value=0;
smartmove(&move, itineraire, En_M, Me, You, Tresor, labData, sizeX, sizeY);
}
ret = sendMove(move);
info_suivante(move, &Me, &You, &Tresor, &En_M, labData, sizeX, sizeY); //Modification des positions
}
#ifdef DEBUG
//Test
print_labdata(labData, sizeX, sizeY);
printf("\nLes Gentils: (%d,%d)", Me.x, Me.y);
printf("\nLes Méchants: (%d,%d)", You.x, You.y);
printf("\nEnergie Gentils : %d\nEnergie Méchants : %d\n\n\n", En_M, En_Y);
if(debug_counter==0){
printf("\nCombien de tour avant prochaine pause :");
scanf(" %d",&debug_counter);
}
debug_counter--;
#endif
if ((player ==1 && ret == MOVE_WIN) || (player==0 && ret == MOVE_LOSE))
printf("No rage N00B\n");
if ((player ==0 && ret == MOVE_WIN) || (player==1 && ret == MOVE_LOSE))
printf("GG WP\n");
player = (player+1)%2;//Changement de joueur
}
/* we do not forget to free the allocated array */
free(labData);
free_itineraire(itineraire);
/* end the connection, because we are polite */
closeConnection();
return EXIT_SUCCESS;
}