|
|
@ -9,6 +9,9 @@ |
|
|
|
#include <SDL/SDL.h> |
|
|
|
#include "gui.h" |
|
|
|
|
|
|
|
#define STACK_TYPE size_t |
|
|
|
#include "stack.h" |
|
|
|
|
|
|
|
#define start_pos startPos |
|
|
|
#define end_pos endPos |
|
|
|
|
|
|
@ -153,7 +156,7 @@ ssize_t move_calculation(const size_t index, const enum direction_t move) { |
|
|
|
else |
|
|
|
return index_lines[line+1]+offset-(block%2)+(line==3?4:0)+(line==8?1:0)+(line==12?-5:0); |
|
|
|
case down_right: |
|
|
|
if(line == 16 || (block%2==1 && index+1 == index_lines[line+1]) || (line == 12 && ( offset < 4 || offset > 7 ) ) ) |
|
|
|
if(line == 16 || (block%2==1 && index+1 == index_lines[line+1] && index != 64) || (line == 12 && ( offset < 4 || offset > 7 ) ) ) |
|
|
|
return -1; |
|
|
|
else |
|
|
|
return index_lines[line+1]+offset-((block%2)-1)+(line==3?4:0)+(line==8?1:0)+(line==12?-5:0); |
|
|
@ -186,39 +189,35 @@ int nb_possible_move(const struct game_state_t game, const struct player_t playe |
|
|
|
if(game.board[i] == player.branch) { |
|
|
|
j++; |
|
|
|
/* on regarde si on peut faire un déplacement */ |
|
|
|
#ifdef debug |
|
|
|
fputs("on regarde les voisins\n", stderr); |
|
|
|
#endif |
|
|
|
k = 0; |
|
|
|
do { |
|
|
|
if( (dest = move_calculation( (size_t) i, k)) != -1 ) { |
|
|
|
if(game.board[dest] == none) |
|
|
|
res++; |
|
|
|
else |
|
|
|
if(((dest2 = move_calculation(dest,j)) != -1) && (game.board[dest2] == none)) |
|
|
|
if(((dest2 = move_calculation(dest,k)) != -1) && (game.board[dest2] == none)) |
|
|
|
res++; |
|
|
|
} |
|
|
|
} while(++k < 6); |
|
|
|
} |
|
|
|
} while(++i < 121 && j < 10); |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "%d cases voisines atteignables pour le joueurs\n", res); |
|
|
|
#endif |
|
|
|
return res; |
|
|
|
} |
|
|
|
enum bool pawn_on_branch(const struct player_t player, const size_t index, const size_t start_position[6][10]) { |
|
|
|
size_t j; |
|
|
|
/* ne pas faire les branches de départ et d'arrivée */ |
|
|
|
for(j = (((player.branch-1)%3)+1)%6; j!=((player.branch-1)%3) ; j=(j+(j==((player.branch-1)%3)+2?2:1))%6 ) |
|
|
|
if(search(start_position[j],10,index)) |
|
|
|
if(search(start_position[j],10,index)) { |
|
|
|
#ifdef debug |
|
|
|
fputs("arret sur la branche d'un autre joueur\n", stderr); |
|
|
|
#endif |
|
|
|
return true; |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
size_t* must_move(const struct player_t player, const struct game_state_t game) { |
|
|
|
ssize_t res[10], i; |
|
|
|
for(i=0 ; i<10 ; res[i++]=-1); |
|
|
|
/* on regarde les pions du joueur en face */ |
|
|
|
|
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
int distance_to_branch(const size_t branch, const size_t index) { |
|
|
|
const size_t index_lines[] = {0, 1, 3, 6, 10, 23, 35, 46, 56, 65, 75, 86, 98, 111, 115, 118, 120}; |
|
|
|
const size_t coord_branch[6][2] = {{0, 0}, {4, 12}, {12, 12}, {16, 0}, {12, 0}, {4, 0}}; |
|
|
@ -251,13 +250,121 @@ int distance_to_branch(const size_t branch, const size_t index) { |
|
|
|
return res; |
|
|
|
} |
|
|
|
|
|
|
|
void must_move(const struct player_t player, const struct game_state_t game, const size_t start_position[6][10]) { |
|
|
|
ssize_t dest, dest2; |
|
|
|
int distance, distance1; |
|
|
|
size_t i, j, start_hole, player_pawn, hole; |
|
|
|
enum bool tried[121], pawn_to_move[121]; |
|
|
|
struct stack_cell_t *stack; |
|
|
|
enum bool must_move; |
|
|
|
|
|
|
|
for(i=0 ; i<121 ; pawn_to_move[i++]=false); |
|
|
|
|
|
|
|
must_move = true; |
|
|
|
stack = NULL; |
|
|
|
|
|
|
|
/* on regarde sur le plateau les pions du joueur d'en face */ |
|
|
|
hole = 0; |
|
|
|
player_pawn = 0; |
|
|
|
do { |
|
|
|
if(game.board[hole] == ((player.branch+2)%6)+1) { |
|
|
|
player_pawn++; |
|
|
|
distance = distance_to_branch(player.branch, hole); |
|
|
|
for(i=0 ; i<121 ; tried[i++]=false); |
|
|
|
|
|
|
|
/* on regarde là ou on peut aller en un mouvement */ |
|
|
|
j=0; |
|
|
|
do { |
|
|
|
if( (dest = move_calculation( (size_t) hole, j)) != -1) { |
|
|
|
distance1 = distance_to_branch(player.branch, dest); |
|
|
|
if(game.board[dest] == none && distance1 < distance) |
|
|
|
must_move = false; /* on a un coup qui prorgresse */ |
|
|
|
if(game.board[dest] == player.branch && search(start_position[player.branch-1],10,dest) && distance1 < distance) { |
|
|
|
pawn_to_move[dest] = true; /* on aurait un coup qui progresse si on déplace le pion sur dest */ |
|
|
|
} |
|
|
|
if(game.board[dest] != none) { |
|
|
|
if((dest2 = move_calculation(dest,j)) != -1) { |
|
|
|
distance1 = distance_to_branch(player.branch, dest2); |
|
|
|
if(game.board[dest2] == none && distance1 < distance) |
|
|
|
must_move = false; /* on a un coup qui prorgresse */ |
|
|
|
else if(game.board[dest2] == player.branch && search(start_position[player.branch-1],10,dest2) && distance1 < distance) |
|
|
|
pawn_to_move[dest] = true; /* on aurait un coup qui progresse si on déplace le pion sur dest2 */ |
|
|
|
stack_push(&stack, (size_t) dest2); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} while(++j < 6 && must_move); |
|
|
|
tried[hole] = true; |
|
|
|
|
|
|
|
/* pour tous les sauts, peut on en faire d'autres ? */ |
|
|
|
while(stack && must_move) { |
|
|
|
start_hole = *(stack_pop(&stack)); |
|
|
|
if(!tried[start_hole]) { |
|
|
|
j = 0; |
|
|
|
do { |
|
|
|
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) |
|
|
|
must_move = false; /* on a un coup qui prorgresse */ |
|
|
|
else if(game.board[dest2] == player.branch && search(start_position[player.branch-1],10,dest2) && distance1 < distance) |
|
|
|
pawn_to_move[dest] = true; /* on aurait un coup qui progresse si on déplace le pion sur dest2 */ |
|
|
|
stack_push(&stack, (size_t) dest2); |
|
|
|
} |
|
|
|
} while(++j < 6); |
|
|
|
tried[start_hole] = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* on vide la pile */ |
|
|
|
if(!must_move) { |
|
|
|
while(stack) |
|
|
|
stack_pop(&stack); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
}while(++hole < 121 && player_pawn < 10 && must_move); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(must_move) { |
|
|
|
puts("can go :"); |
|
|
|
for(i=0;i<121;i++) |
|
|
|
if(pawn_to_move[i]) |
|
|
|
printf("%d ", i); |
|
|
|
puts(""); |
|
|
|
} else { |
|
|
|
puts("n'importe quel coup est autorisé"); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
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) { |
|
|
|
size_t j; |
|
|
|
ssize_t dest, dest2; |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "=== validation de %d → %d===\n", move.start_pos, move.end_pos); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* si c'est le dernier mouvement et le premier, on vérifie que le joueur est bloqué */ |
|
|
|
if(last_move && previous_move.start_pos == -1 && previous_move.end_pos == -1) |
|
|
|
return (nb_possible_move(game, player)==0)?neighbour_valid:invalid; |
|
|
|
if(last_move && previous_move.start_pos == -1 && previous_move.end_pos == -1) { |
|
|
|
#ifdef debug |
|
|
|
fputs("vérification si le joueur a retourné 0 pour next_move. On vérifie si il est bloqué\n", stderr); |
|
|
|
#endif |
|
|
|
if(nb_possible_move(game, player)==0) { |
|
|
|
#ifdef debug |
|
|
|
fputs("le joueur est effectivement bloqué\n", stderr); |
|
|
|
#endif |
|
|
|
return jump_valid; |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
fputs("le joueur pouvait faire un mouvement\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
// return (nb_possible_move(game, player)==0)?jump_valid:invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* si c'est le dernier mouvement, on ne stationne pas sur une branche */ |
|
|
|
if(last_move && previous_move.start_pos != -1 && previous_move.end_pos != -1) { |
|
|
@ -267,19 +374,19 @@ enum validation_movement_t valid_move(const int start_pos_first_move, const stru |
|
|
|
return (pawn_on_branch(player, previous_move.end_pos, start_position) || (start_pos_first_move == previous_move.end_pos && ! allow_to_returning_to_the_starting_point_in_a_round ))?invalid:jump_valid; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "=== validation de %d → %d===\n", move.start_pos, move.end_pos); |
|
|
|
#endif |
|
|
|
|
|
|
|
if(move.start_pos < 0 || move.end_pos < 0 || move.start_pos > 120 || move.end_pos > 120) |
|
|
|
if(move.start_pos < 0 || move.end_pos < 0 || move.start_pos > 120 || move.end_pos > 120) { |
|
|
|
#ifdef debug |
|
|
|
fputs("l'indice de la case n'est pas compris entre 0 et 120\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* on vérifie que la case appartient au joueur */ |
|
|
|
if(game.board[move.start_pos] != player.branch ) { |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "la case %d n'appartient pas au joueur\n",move.start_pos); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "la case %d n'appartient pas au joueur\n",move.start_pos); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* si ce n'est pas le premier mouvement, on peut rester sur place */ |
|
|
@ -297,10 +404,10 @@ enum validation_movement_t valid_move(const int start_pos_first_move, const stru |
|
|
|
|
|
|
|
/* on vérifie le collage si ce n'est pas le premier mouvement */ |
|
|
|
if(previous_move.start_pos != -1 && previous_move.end_pos != -1 && move.start_pos != previous_move.end_pos) { |
|
|
|
#ifdef debug |
|
|
|
fputs("le pion déplacé n'est pas le même qu'au mouvement précédent\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
#ifdef debug |
|
|
|
fputs("le pion déplacé n'est pas le même qu'au mouvement précédent\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* on regarde autour */ |
|
|
@ -328,10 +435,37 @@ enum validation_movement_t valid_move(const int start_pos_first_move, const stru |
|
|
|
case 1: /*on veut y aller mais la place est occupée (déjà traité plus haut) */ |
|
|
|
return invalid; |
|
|
|
case 3: /*on veut y aller et la place est libre*/ |
|
|
|
return (previous_move.start_pos == -1 && previous_move.end_pos == -1 && !pawn_on_branch(player, move.end_pos, start_position) && !last_move)?neighbour_valid:invalid; |
|
|
|
if(previous_move.start_pos == -1 && previous_move.end_pos == -1) { |
|
|
|
if(!pawn_on_branch(player, move.end_pos, start_position)) { |
|
|
|
if(!last_move) { |
|
|
|
return neighbour_valid; |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
fputs("next_move doit etre à 1\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
fputs("la case voisine est sur une branche de l'étoile\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
fputs("on ne peut atteindre un voisin que sur le premier mouvement\n", stderr); |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
// return (previous_move.start_pos == -1 && previous_move.end_pos == -1 && !pawn_on_branch(player, move.end_pos, start_position) && !last_move)?neighbour_valid:invalid; |
|
|
|
} |
|
|
|
} |
|
|
|
} while(++j < 6); |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "%d ne fait pas partie des voisins\n", move.end_pos); |
|
|
|
#endif |
|
|
|
|
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
@ -364,7 +498,7 @@ void save(const char *filename, const struct player_t *player_state, const int n |
|
|
|
else |
|
|
|
fprintf(file, "partie %d (%ld second%s) : ", i+1, (long int)(duration[i]), ((duration[i]%60)>1?"s":"")); |
|
|
|
if(winner[i] >= 0 && winner[i] < nb_player) |
|
|
|
fprintf(file, "gagnée par le joueur %s (%s)\n", couleurs[winner[i]], player_state[winner[i]].name); |
|
|
|
fprintf(file, "gagnée par le joueur %s (%s)\n", couleurs[(player_state[winner[i]].branch)-1], player_state[winner[i]].name); |
|
|
|
else |
|
|
|
fputs("aucun joueur n'a gagné\n", file); |
|
|
|
} |
|
|
@ -428,8 +562,10 @@ int main(int argc, char **argv) { |
|
|
|
/* on charge les IA et on initialise les joueurs « réels » */ |
|
|
|
j = 3; |
|
|
|
for( i = 0; i < nb_player ; i++ ) { |
|
|
|
/* on associe une branche à chaque joueur */ |
|
|
|
player_state[i].branch = star_branch(nb_player, i); |
|
|
|
/* on prépare pour le nom */ |
|
|
|
snprintf(player_state[i].name,50,"joueur %s", couleurs[i]); |
|
|
|
snprintf(player_state[i].name,50,"joueur %s", couleurs[(player_state[i].branch)-1]); |
|
|
|
player_state[i].name[49] = '\0'; |
|
|
|
/* on choisit de placer un joueur réel ou une stratégie */ |
|
|
|
if( (rand()%(nb_player-i)) < (argc-j) ) { |
|
|
@ -461,7 +597,7 @@ int main(int argc, char **argv) { |
|
|
|
/* petite vérification sur le nom */ |
|
|
|
#ifdef debug |
|
|
|
if(player_state[i].name[49] != '\0') |
|
|
|
fprintf(stderr,"attention : la longueur du nom du joueur %s doit être inférieur à 49 caractères.\n", couleurs[i]); |
|
|
|
fprintf(stderr,"attention : la longueur du nom du joueur %s doit être inférieur à 49 caractères.\n", couleurs[(player_state[i].branch)-1]); |
|
|
|
#endif |
|
|
|
player_state[i].name[49] = '\0'; |
|
|
|
} |
|
|
@ -488,8 +624,6 @@ int main(int argc, char **argv) { |
|
|
|
dlerror(); |
|
|
|
|
|
|
|
for( i=0 ; i < nb_player ; i++ ) { |
|
|
|
/* on associe une branche à chaque joueur */ |
|
|
|
player_state[i].branch = star_branch(nb_player, i); |
|
|
|
/* appel de start_match pour les joueurs présents */ |
|
|
|
if( player_state[i].ia_lib_p ) |
|
|
|
ia_call_function(player_state[i], ia_start_match, NULL, nb_player, player_state[i].branch); |
|
|
@ -539,7 +673,7 @@ int main(int argc, char **argv) { |
|
|
|
while(nb_player_end < nb_player-1 && !quit) { |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "joueur %s (%d) (%s)\n", couleurs[i], i, player_state[i].name); |
|
|
|
fprintf(stderr, "joueur %s (%d) (%s)\n", couleurs[(player_state[i].branch)-1], i, player_state[i].name); |
|
|
|
#endif |
|
|
|
game_state_copy = game_state; |
|
|
|
previous_movement.start_pos=-1; previous_movement.end_pos=-1; |
|
|
@ -548,6 +682,9 @@ int main(int argc, char **argv) { |
|
|
|
movement.start_pos=-1; movement.end_pos=-1; |
|
|
|
game_state_ia_copy = game_state_copy; |
|
|
|
/* on suppose qu'on a une stratégie */ |
|
|
|
if(strcmp(player_state[i].name,"test")==0) { |
|
|
|
must_move(player_state[i],game_state_ia_copy, start_position); |
|
|
|
} |
|
|
|
ia_call_function(player_state[i], ia_next_move, &next_move, &game_state_ia_copy, first_move, &movement); |
|
|
|
printf("(GUI) Moving pawn %d → hole %d\n", movement.start_pos, movement.end_pos); |
|
|
|
if(first_move) |
|
|
|