Browse Source

Merge branch 'master' of ssh://ssh.confais.org/git/dames_chinoises

master
Stéphane 8 years ago
parent
commit
ffaaab2181
3 changed files with 123 additions and 92 deletions
  1. +4
    -4
      arbitre.c
  2. +80
    -70
      main.c
  3. +39
    -18
      readme

+ 4
- 4
arbitre.c View File

@ -188,7 +188,7 @@ enum bool must_move(const struct player_t player, const struct game_state_t game
if( (dest = move_calculation( (size_t) hole, j)) != -1) {
distance1 = distance_to_branch(player.branch, dest);
if(game.board[dest] == none && distance1 < distance && !pawn_on_branch(((player.branch+2)%6)+1,dest,start_position)) {
printf("coup qui progresse : %lu (%d) %lu (%d)\n", hole, distance, dest, distance1);
printf("coup qui progresse : %lu (%d) %lu (%d)\n", (long unsigned int)hole, distance, (long unsigned int)dest, distance1);
must_move = false; /* on a un coup qui progresse */
}
if(game.board[dest] == player.branch && search(start_position[player.branch-1],10,dest) && distance1 < distance) {
@ -198,7 +198,7 @@ enum bool must_move(const struct player_t player, const struct game_state_t game
if((dest2 = move_calculation(dest,j)) != -1) {
distance1 = distance_to_branch(player.branch, dest2);
if(game.board[dest2] == none && distance1 < distance && !pawn_on_branch(((player.branch+2)%6)+1,dest2,start_position)) {
printf("coup qui progresse : %lu (%d) %lu (%d)\n", hole, distance, dest2, distance1);
printf("coup qui progresse : %lu (%d) %lu (%d)\n", (long unsigned int)hole, distance, (long unsigned int)dest2, distance1);
must_move = false; /* on a un coup qui progresse */
}
else if(game.board[dest2] == player.branch && search(start_position[player.branch-1],10,dest2) && distance1 < distance)
@ -219,7 +219,7 @@ enum bool must_move(const struct player_t player, const struct game_state_t game
if( (dest = move_calculation(start_hole, j)) != -1 && game.board[dest] != none && (dest2 = move_calculation(dest,j)) != -1) {
distance1 = distance_to_branch(player.branch, dest2);
if(game.board[dest2] == none && distance1 < distance && !pawn_on_branch(((player.branch+2)%6)+1,dest2,start_position)) {
printf("coup qui progresse : %lu (%d) %lu (%d)\n", hole, distance, dest2, distance1);
printf("coup qui progresse : %lu (%d) %lu (%d)\n", (long unsigned int)hole, distance, (long unsigned int)dest2, distance1);
must_move = false; /* on a un coup qui progresse */
}
else if(game.board[dest2] == player.branch && search(start_position[player.branch-1],10,dest2) && distance1 < distance)
@ -253,7 +253,7 @@ enum bool must_move(const struct player_t player, const struct game_state_t game
for(hole=0, player_pawn=0;hole<121 && player_pawn < 10;hole++)
if(pawn_to_move[hole]) {
#ifdef debug
fprintf(stderr, "%lu ", hole);
fprintf(stderr, "%lu ", (long unsigned int)hole);
#endif
res[player_pawn++]=hole; /* le tableau est trié donc on pourra faire une recherche dichotomique */
}


+ 80
- 70
main.c View File

@ -291,86 +291,96 @@ int main(int argc, char **argv) {
#endif
game_state_copy = game_state;
previous_movement.start_pos=-1; previous_movement.end_pos=-1;
start_pos_first_move = -1;
first_move = 1;
do { /* on demande la suite de coup */
movement.start_pos=-1; movement.end_pos=-1;
start_pos_first_move = -1;
game_state_ia_copy = game_state_copy;
/* si on a une stratégie */
if( player_state[i].ia_lib_p )
if( player_state[i].ia_lib_p ) {
movement.start_pos=-1; movement.end_pos=-1;
game_state_ia_copy = game_state_copy;
ia_call_function(player_state[i], ia_next_move, &next_move, &game_state_ia_copy, first_move, &movement);
else
/* on a un joueur réel */
quit += display_usermove_pawn(&gui_res, &game_state_ia_copy, player_state[i].branch, player_state[i].name, &movement, &next_move);
if(!quit) {
printf("(GUI) Moving pawn %d → hole %d\n", movement.start_pos, movement.end_pos);
if(first_move)
start_pos_first_move = movement.start_pos; /* on retient le point de départ pour éviter les coups qui reviendraient là où on est parti */
/* on cherche à valider le coup */
validation_movement = valid_move(start_pos_first_move, movement, previous_movement, player_state[i], game_state_copy, start_position, !next_move);
#ifdef debug
switch(validation_movement) {
case invalid: fputs("validation → invalide\n", stderr); break;
case jump: fputs("validation → jump\n", stderr); break;
case neighbour_valid: fputs("validation → voisin\n", stderr); break;
case jump_valid: fputs("validation → commit jump\n", stderr); break;
}
#endif
/* on effectue le mouvement à l'écran */
if(validation_movement != jump_valid && movement.start_pos != movement.end_pos && movement.start_pos >= 0 && movement.end_pos >= 0 && movement.start_pos < 121 && movement.end_pos < 121 && player_state[i].ia_lib_p)
quit += display_animove_pawn(&gui_res, game_state_copy, player_state[i].branch, player_state[i].name, movement.start_pos, movement.end_pos);
/* on regarde le résultat de la validation */
if(validation_movement == invalid) {
if(!quit) {
printf("(GUI) Moving pawn %d → hole %d\n", movement.start_pos, movement.end_pos);
if(first_move)
start_pos_first_move = movement.start_pos; /* on retient le point de départ pour éviter les coups qui reviendraient là où on est parti */
/* on cherche à valider le coup */
validation_movement = valid_move(start_pos_first_move, movement, previous_movement, player_state[i], game_state_copy, start_position, !next_move);
#ifdef debug
fprintf(stderr, "mouvement (%d,%d) invalide\n",movement.start_pos, movement.end_pos);
#endif
if( (buffer = (char*) malloc( 28 *sizeof(char) ) ) == NULL)
display_animsg(&gui_res, &game_state, player_state[i].branch, player_state[i].name, "Coup non valide", 1000);
else {
snprintf(buffer, 28, "Coup non valide (%d erreur%s)", player_state[i].error+1, (player_state[i].error+1>1)?"s":"");
display_animsg(&gui_res, &game_state, player_state[i].branch, player_state[i].name, buffer, 1500);
free(buffer);
}
if(++(player_state[i].error)==3) {
nb_player_end++;
puts("perdu");
/* on enlève les pions du joueur */
j=0; k=0;
do {
if(game_state.board[j] == player_state[i].branch) {
game_state.board[j] = none;
k++;
}
} while(++j < 121 && k < 10);
if( player_state[i].ia_lib_p )
ia_call_function(player_state[i], ia_end_game, NULL);
switch(validation_movement) {
case invalid: fputs("validation → invalide\n", stderr); break;
case jump: fputs("validation → jump\n", stderr); break;
case neighbour_valid: fputs("validation → voisin\n", stderr); break;
case jump_valid: fputs("validation → commit jump\n", stderr); break;
}
}
if(validation_movement == jump || validation_movement == neighbour_valid) {
/* on effectue le mouvement */
#ifdef debug
fprintf(stderr, "mouvement (%d,%d) valide\n",movement.start_pos, movement.end_pos);
#endif
game_state_copy.board[movement.start_pos]=none;
game_state_copy.board[movement.end_pos]=player_state[i].branch;
previous_movement=movement;
}
if(validation_movement == jump_valid || validation_movement == neighbour_valid) {
/* commit */
#ifdef debug
fputs("commit\n",stderr);
#endif
game_state=game_state_copy; /* commit */
if(winner(player_state[i], start_position, game_state)) {
nb_player_end=nb_player /* la partie se termine */;
puts("le joueur a gagné");
winner_games[nb_game_end] = i;
if( player_state[i].ia_lib_p )
ia_call_function(player_state[i], ia_end_game, NULL);
/* on effectue le mouvement à l'écran */
if(validation_movement != jump_valid && movement.start_pos != movement.end_pos && movement.start_pos >= 0 && movement.end_pos >= 0 && movement.start_pos < 121 && movement.end_pos < 121 && player_state[i].ia_lib_p)
quit += display_animove_pawn(&gui_res, game_state_copy, player_state[i].branch, player_state[i].name, movement.start_pos, movement.end_pos);
/* on regarde le résultat de la validation */
if(validation_movement == invalid) {
#ifdef debug
fprintf(stderr, "mouvement (%d,%d) invalide\n",movement.start_pos, movement.end_pos);
#endif
if( (buffer = (char*) malloc( 28 *sizeof(char) ) ) == NULL)
display_animsg(&gui_res, &game_state_copy, player_state[i].branch, player_state[i].name, "Coup non valide", 1000);
else {
snprintf(buffer, 28, "Coup non valide (%d erreur%s)", player_state[i].error+1, (player_state[i].error+1>1)?"s":"");
display_animsg(&gui_res, &game_state_copy, player_state[i].branch, player_state[i].name, buffer, 1500);
free(buffer);
}
if(++(player_state[i].error)==3) {
nb_player_end++;
puts("perdu");
/* on enlève les pions du joueur */
j=0; k=0;
do {
if(game_state.board[j] == player_state[i].branch) {
game_state.board[j] = none;
k++;
}
} while(++j < 121 && k < 10);
if( player_state[i].ia_lib_p )
ia_call_function(player_state[i], ia_end_game, NULL);
}
}
}
first_move=0;
} else {
/* on a un joueur réel, on demande un coup tant qu'il n'est pas valide */
do {
movement.start_pos=-1; movement.end_pos=-1;
game_state_ia_copy = game_state_copy;
quit += display_usermove_pawn(&gui_res, &game_state_ia_copy, player_state[i].branch, player_state[i].name, &movement, &next_move);
if(first_move)
start_pos_first_move = movement.start_pos; /* on retient le point de départ pour éviter les coups qui reviendraient là où on est parti */
validation_movement = valid_move(start_pos_first_move, movement, previous_movement, player_state[i], game_state_copy, start_position, !next_move);
if(validation_movement == invalid && !quit)
display_animsg(&gui_res, &game_state_copy, player_state[i].branch, player_state[i].name, "Coup non valide, réessayer", 1000);
} while(validation_movement == invalid && !quit);
}
if(validation_movement == jump || validation_movement == neighbour_valid) {
/* on effectue le mouvement */
#ifdef debug
fprintf(stderr, "mouvement (%d,%d) valide\n",movement.start_pos, movement.end_pos);
#endif
game_state_copy.board[movement.start_pos]=none;
game_state_copy.board[movement.end_pos]=player_state[i].branch;
previous_movement=movement;
}
if(validation_movement == jump_valid || validation_movement == neighbour_valid) {
/* commit */
#ifdef debug
fputs("commit\n",stderr);
#endif
game_state=game_state_copy; /* commit */
if(winner(player_state[i], start_position, game_state)) {
nb_player_end=nb_player /* la partie se termine */;
puts("le joueur a gagné");
winner_games[nb_game_end] = i;
if( player_state[i].ia_lib_p )
ia_call_function(player_state[i], ia_end_game, NULL);
}
}
first_move=0;
} while(validation_movement == jump && nb_player_end < nb_player-1 && !quit);
/* on sélectionne le joueur suivant */
j=i;


+ 39
- 18
readme View File

@ -1,4 +1,24 @@
Explications sur le fonctionnement du programme
## Compilation du projet
Dépendances : SDL, sdl_image, sdl_gfx, sdl_ttf
Lancer make pour compiler.
main est l'exécutable du binôme ayant réalisé la partie graphique
ai/ai.so est la bibliothèque du binôme stratégie
## Présentation de l'interface
La syntaxe est la suivante : ./main <nombre de parties> <nombre de joueurs> [<./bibliothèque.so> …]
Si moins de bibliothèques que de joueurs sont spécifiées, des joueurs réels complèteront le nombre.
Attention : pour utiliser une même bibliothèque plusieurs fois, effectuer des copies du fichier .so.
Lors du jeu, les joueurs réels valideront la fin de leur suite de sauts par un clic droit.
Une démonstration de toutes les fonctions de l'interface est disponible : lancer ./guidemo
## Explications sur le fonctionnement du programme arbitre
define
======
@ -23,14 +43,14 @@ fonction « char_to_int »
========================
La fonction « enum bool char_to_int(char *argv, int *nombre) » permet de convertir un nombre contenu dans une chaîne de
caractères en un entier. La fonction retourne « true » si la conversion a réussie et « false » si la conversion a échouée.
caractères en un entier. La fonction retourne « true » si la conversion a réussi et « false » si la conversion a échoué.
Le nombre converti est stocké à l'adresse pointée par le paramètre « nombre ».
fonction « number_length »
==========================
La fonction « unsigned int number_length(int n) » retourne le nombre de caractères nécessaires pour convertir ce nombre en
une chaîne de caractères. Ainsi number_length(-100) retourne 4.
une chaîne de caractères en base 10. Ainsi number_length(-100) retourne 4.
fonction « ia_call_function »
=============================
@ -44,7 +64,7 @@ Les arguments suivants sont les arguments attendus par la fonction de la straté
La fonction va d'abord affecter à la variable « function_name » la chaîne de caractères correspondant au nom de la fonction à
appeler. Ce nom est déduit de la valeur du paramètre « api_function ».
Ensuite on essaie de récupérer un pointeur vers la fonction en question grâce à l'utilisation de « dlsym ». Si cela échoue la
Ensuite on essaie de récupérer un pointeur vers la fonction en question grâce à l'utilisation de « dlsym ». Si cela échoue, la
fonction « ia_call_function » retourne « false » et se termine. Sinon, selon la fonction demandée, on lit éventuellement les
paramètres avec « va_arg() ». Enfin on appelle la fonction de la stratégie.
@ -52,10 +72,11 @@ paramètres avec « va_arg() ». Enfin on appelle la fonction de la stratégie.
fonction « star_branch »
========================
La fonction « size_t star_branch(const unsigned int nb_player, const size_t index) » permet de déterminer sur quelle branche de
La fonction « enum hole_t star_branch(const unsigned int nb_player, const size_t index) » permet de déterminer sur quelle branche de
l'étoile doit se trouver la position de départ d'un joueur donné.
On numérote chaque branche de l'étoile :
/ \
____/ 1 \____
\ 6 2 /
@ -68,14 +89,13 @@ ____/ 1 \____
Ainsi quand le nombre de joueurs est égal à 2, le joueur 0 doit être placé sur la branche 1 et le joueur 1 sur la branche 4.
On a donc dans ce cas « star_branch(2,0) = 0 » et « star_branch(2,1) = 3 ».
Avec trois joueurs, on place les joueurs sur les branches 1, 3 et 5
Avec quatre joueurs, on les place sur les branches 1, 2, 4 et 5
Avec trois joueurs, on place les joueurs sur les branches 1, 3 et 5.
Avec quatre joueurs, on les place sur les branches 1, 2, 4 et 5.
Avec six joueurs, on utilise chaque branche.
fonction « move_calculation »
=============================
La fonction « ssize_t move_calculation(const size_t index, const enum direction_t move) » permet de déterminer l'indice du
voisin d'une case sur le plateau.
@ -88,6 +108,7 @@ voisin à gauche).
La fonction va d'abord déterminer sur quelle ligne se trouve la case dont on cherche le voisin ainsi que sa position sur la
ligne (offset). La fonction détermine aussi dans quel « bloc » de l'étoile, la case se trouve.
Les blocs sont définis comme ceci :
/ \
____/ \____ bloc 0
----------------------
@ -172,7 +193,7 @@ triangle d'aile, mais pas d'y stationner. »
fonction « distance_to_branch »
===============================
La fonction « int distance_to_branch(const enum hole_t branch, const size_t index) » permet d'évaluer la distance entre deux cases du plateau. La distance est calculée comme le nombre de lignes séparant les deux cases plusS la différence d'indice sur la ligne .
La fonction « int distance_to_branch(const enum hole_t branch, const size_t index) » permet d'évaluer la distance entre deux cases du plateau. La distance est calculée comme le nombre de lignes séparant les deux cases plus la différence d'indice sur la ligne .
Cependant comme les lignes n'ont pas toutes la même longueur, on accentue le décalage sur les lignes ayant peu d'éléments.
fonction « must_move »
@ -183,7 +204,7 @@ atteindre le joueur d'en face en un coup (composé de plusieurs mouvement). Si i
resté dans sa branche de départ, alors le joueur bloque le joueur en face de lui. Il doit donc sortir de sa branche de départ.
must_move retourne vrai si le joueur doit sortir de sa branche avec res qui correspond à la liste des pions qui gênent, sinon must_move retourne faux.
Cette fonction est utilisée dans la fonction « valid_move » afin de vérifier la règle « Un pion doit obligatoirement quitter son triangle de départ quand le joueur situé vis-à-vis n'a plus, comme seul coup lui permettant de progresser, que la rentrée : on doit
alors laisser la place libre, même si on a un meilleur autre coup.(Il est interdit de bloquer un autre joueur.) »
alors laisser la place libre, même si on a un meilleur autre coup. (Il est interdit de bloquer un autre joueur.) »
fonction « valid_move »
=======================
@ -191,18 +212,18 @@ fonction « valid_move »
La fonction « enum validation_movement_t valid_move(const int start_pos_first_move, const struct move_t move, const struct move_t previous_move, const struct player_t player, const struct game_state_t game, const size_t start_position[6][10], const enum bool
last_move) » permet de vérifier si le coup « move » est un coup valide ou non.
Le paramètre « fist_move » est le point de départ du premier mouvement d'un coup.
Le paramètre « first_move » est le point de départ du premier mouvement d'un coup.
Le paramètre « move » est le mouvement dont on veut vérifier la validité
Le paramètre « previous_move » est le mouvement précédent. Cela permet ainsi de vérifier que pendant un même tour, on ne déplace qu'un seul pion. Si c'est le premier mouvement d'un tour, ce mouvement doit comporter (-1,-1).
Le paramètre « player » est le joueur qui effectue le déplacement. Cela permet de vérifier que le joueur déplace un pion qui lui appartient
Le paramètre « game » est le plateau du jeu
Le paramètre « player » est le joueur qui effectue le déplacement. Cela permet de vérifier que le joueur déplace un pion qui lui appartient.
Le paramètre « game » est le plateau du jeu.
Le paramètre « start_position » est un tableau qui contient les indices des cases formant les branches de l'étoile.
Le paramètre « last_move » permet d'indiquer qu'il s'agit du dernier mouvement d'un tour. Ces deux derniers paramètres permettent de vérifier que le joueur ne s'arrête pas sur une branche de l'étoile.
La fonction retourne « jump », « jump_valid », « neighbour_valid » ou « invalid ».
La fonction va d'abord vérifier si le joueur n'est pas bloqué. Si le joueur est bloqué alors si il a mis n'importe quoi dans « move » et que « next_move » a retourné 0, on considère qu'il passe son tour.
Ensuite on vérifie que le joueur ne bloque pas le joueur en face de lui. Si il peut le bloquer, on regarde que le pion qu'il déplace est bien un pion qui gène (retourné par must_move). Si ce n'est pas le cas, le mouvement est invalide.
Ensuite on vérifie que le joueur ne bloque pas le joueur en face de lui. Si il peut le bloquer, on regarde que le pion qu'il déplace est bien un pion qui gêne (retourné par must_move). Si ce n'est pas le cas, le mouvement est invalide.
Ensuite, si c'est le dernier mouvement alors on vérifie que le joueur n'est pas stationné sur une branche. Si c'est bon, on retourne « jump_valid ». Ce retour permet à la fonction main de ne pas tenir compte du coup.
Ensuite on vérifie que la case du début du mouvement comporte bien un pion appartenant au joueur.
@ -211,9 +232,9 @@ Si ce n'est pas le premier mouvement d'un tour, on vérifie que la case au dépa
Ensuite, si il s'agit du dernier mouvement d'un tour, on vérifie que la case de la fin du mouvement ne corresponde pas à la branche d'un joueur.
Ensuite on regarde chaque case située autour de la case au départ du mouvement. On a trois cas :
Si la case est vide et que c'est là qu'on veut aller, le coup est autorisé
Si la case est occupée et que c'est là qu'on veut aller, le coup est invalide
Si la case est occupée et que ce n'est pas la qu'on veut aller, on refait ce test (uniquement les deux conditions précédentes )avec la case située après le
Si la case est vide et que c'est là qu'on veut aller, le coup est autorisé.
Si la case est occupée et que c'est là qu'on veut aller, le coup est invalide.
Si la case est occupée et que ce n'est pas la qu'on veut aller, on refait ce test (uniquement les deux conditions précédentes) avec la case située après le
pion voisin.
Une fois qu'on a regardé tous les voisins, si on n'a satisfait aucune condition, on considère naturellement que le coup est invalide.
@ -244,4 +265,4 @@ fonction « main »
=================
La fonction main gère le déroulement de la partie.
La partie s'arrete si un seul joueur gagne ou si tous les joueurs sauf un ont perdus (un joueur ne va pas jouer tout seul).
La partie s'arrête si un seul joueur gagne ou si tous les joueurs sauf un ont perdu (un joueur ne va pas jouer tout seul).

Loading…
Cancel
Save