|
|
@ -17,6 +17,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
enum bool {false, true}; |
|
|
|
enum validation_movement_t {neighbour_valid, jump, jump_valid, invalid}; |
|
|
|
enum direction_t { left, right, up_left, up_right, down_left, down_right }; |
|
|
|
enum api_function_t {ia_lib_init, ia_start_match, ia_start_game, ia_end_game , ia_end_match, ia_next_move}; |
|
|
|
|
|
|
@ -51,9 +52,9 @@ enum bool ia_call_function(const struct player_t player, const enum api_function |
|
|
|
unsigned int a; int b; enum hole_t c; |
|
|
|
void *d, *e; |
|
|
|
if(!player.ia_lib_p) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fputs("the player is not a strategy.\n",stderr); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
va_start(ap, result); |
|
|
@ -101,9 +102,9 @@ enum bool ia_call_function(const struct player_t player, const enum api_function |
|
|
|
} |
|
|
|
res = true; |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr,"function \"%s\" not found in strategy. (%s)\n", function_name, error); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
res = false; |
|
|
|
} |
|
|
|
va_end(ap); |
|
|
@ -130,8 +131,6 @@ ssize_t move_calculation(const size_t index, const enum direction_t move) { |
|
|
|
block -= 2; |
|
|
|
offset = index - index_lines[line]; |
|
|
|
|
|
|
|
/* printf("line %d, offset %d, block %d\n", line, offset,block); */ |
|
|
|
|
|
|
|
switch(move) { |
|
|
|
case left: |
|
|
|
return offset==0?-1:index-1; |
|
|
@ -184,90 +183,89 @@ enum bool search(const size_t *tab, const size_t length, const size_t value) { |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
enum bool valid_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) { |
|
|
|
enum validation_movement_t valid_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 |
|
|
|
/* 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) { |
|
|
|
#ifdef debug |
|
|
|
fputs("vérification de ne pas stationner sur une branche\n", stderr); |
|
|
|
#endif |
|
|
|
/* 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,previous_move.end_pos)) |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
return jump_valid; |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "=== validation de %d → %d===\n", move.start_pos, move.end_pos); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
|
|
|
|
if(move.start_pos < 0 || move.end_pos < 0 || move.start_pos > 120 || move.end_pos > 120) |
|
|
|
return false; |
|
|
|
return invalid; |
|
|
|
|
|
|
|
/* on vérifie que la case appartient au joueur */ |
|
|
|
if(game.board[move.start_pos] != player.branch ) |
|
|
|
{ |
|
|
|
#ifdef debug |
|
|
|
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 false; |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* si ce n'est pas le premier mouvement, on peut rester sur place */ |
|
|
|
if(previous_move.start_pos != -1 && previous_move.end_pos != -1 && move.start_pos == move.end_pos) |
|
|
|
return true; |
|
|
|
return jump; |
|
|
|
|
|
|
|
/* on vérifie que la case de destination est libre */ |
|
|
|
if(game.board[move.end_pos] != none) { |
|
|
|
#ifdef debug |
|
|
|
/* if(game.board[move.end_pos] != none) { |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "la case %d de destination n'est pas libre\n", move.end_pos); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
*/ |
|
|
|
|
|
|
|
/* 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 |
|
|
|
#ifdef debug |
|
|
|
fputs("le pion déplacé n'est pas le même qu'au mouvement précédent\n", stderr); |
|
|
|
#endif |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/* si c'est le dernier mouvement, on ne stationne pas sur une branche */ |
|
|
|
if(last_move) { |
|
|
|
#ifdef debug |
|
|
|
fputs("vérification de ne pas stationner sur une branche\n", stderr); |
|
|
|
#endif |
|
|
|
/* 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,move.end_pos)) |
|
|
|
return false; |
|
|
|
} |
|
|
|
#endif |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
/* on regarde autour */ |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fputs("on regarde les voisins\n", stderr); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
j = 0; |
|
|
|
do { |
|
|
|
if( (dest = move_calculation( (size_t) move.start_pos, j)) != -1 ) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "%d → %zu (j=%zu) ?\n", move.start_pos, dest, j); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
switch(((dest == move.end_pos)?1:0)+((game.board[dest] == none)?2:0)) { |
|
|
|
case 0: /*on veut pas y aller mais la place est occupée. peut etre qu'on veut faire le saut */ |
|
|
|
if((dest2 = move_calculation(dest,j)) != -1) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "%zu → %zu (j=%zu) ?\n", dest, dest2, j); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
switch(((dest2 == move.end_pos)?1:0)+((game.board[dest2] == none)?2:0)) { |
|
|
|
case 1: /* on veut y aller mais la place est occupée */ return false; |
|
|
|
case 3: /* on veut y aller et la place est libre */ return true; |
|
|
|
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 jump; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
case 1: /*on veut y aller mais la place est occupée*/ |
|
|
|
return false; |
|
|
|
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 && last_move ); |
|
|
|
return (previous_move.start_pos == -1 && previous_move.end_pos == -1)?neighbour_valid:invalid; |
|
|
|
} |
|
|
|
} |
|
|
|
} while(++j < 6); |
|
|
|
|
|
|
|
return false; |
|
|
|
return invalid; |
|
|
|
} |
|
|
|
|
|
|
|
enum bool winner(const struct player_t player, const size_t start_position[6][10], const struct game_state_t game) { |
|
|
@ -308,11 +306,10 @@ void save(const char *filename, const struct player_t *player_state, const int n |
|
|
|
fputs("\n", file); |
|
|
|
fclose(file); |
|
|
|
} |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
else |
|
|
|
fprintf(stderr, "cannot open file \"%s\"\n", filename); |
|
|
|
#endif |
|
|
|
printf("→ %d \n", nb_game_end); |
|
|
|
#endif |
|
|
|
} |
|
|
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
@ -329,6 +326,7 @@ int main(int argc, char** argv) { |
|
|
|
int nb_game, nb_player, nb_game_end, nb_player_end; |
|
|
|
int i, j, k; |
|
|
|
char *buffer; |
|
|
|
enum validation_movement_t validation_movement; |
|
|
|
|
|
|
|
/* heure de début du match et tableaux pour stocker les gagnants et la durée des parties */ |
|
|
|
time_t time_start_match, *duration_games; |
|
|
@ -368,14 +366,14 @@ int main(int argc, char** argv) { |
|
|
|
/* on choisit de placer un joueur réel ou une stratégie */ |
|
|
|
if( (rand()%(nb_player-i)) < (argc-j) ) { |
|
|
|
/* on ajoute une stratégie */ |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr,"strategy %s (%d)\n", argv[j], i); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
player_state[i].ia_lib_p = dlopen(argv[j], RTLD_LAZY); |
|
|
|
if( (buffer = (char*) dlerror()) != NULL ) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr,"error while loading %s : %s (%d)\n", argv[j], buffer, i); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
/* échec du chargement, on décharge toutes les stratégies précédement chargées */ |
|
|
|
for( j=0 ; j<i ; j++ ) |
|
|
|
if( player_state[j].ia_lib_p ) |
|
|
@ -387,38 +385,37 @@ int main(int argc, char** argv) { |
|
|
|
j++; |
|
|
|
} else { |
|
|
|
/* on ajoute un joueur réel */ |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr,"real player (%d)\n", i); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
player_state[i].ia_lib_p = NULL; |
|
|
|
} |
|
|
|
/* on vérifie le nom */ |
|
|
|
if(player_state[i].name[49] != '\0') { |
|
|
|
#ifdef debug |
|
|
|
/* petite vérification sur le nom */ |
|
|
|
#ifdef debug |
|
|
|
if(player_state[i].name[49] != '\0') |
|
|
|
fprintf(stderr,"warning : the length of the player's name %d must be to 49 characters maximum.\n", i); |
|
|
|
#endif |
|
|
|
} else |
|
|
|
player_state[i].name[49] = '\0'; |
|
|
|
#endif |
|
|
|
player_state[i].name[49] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
/* on initialise les tableaux pour stocker les gagnants et la durée de chaque partie */ |
|
|
|
if((winner_games = (int*) malloc(nb_game*sizeof(int))) == NULL) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fputs("malloc error\n", stderr); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
return 6; |
|
|
|
} |
|
|
|
if((duration_games = (time_t*) malloc(nb_game*sizeof(time_t))) == NULL) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fputs("malloc error\n", stderr); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
return 6; |
|
|
|
} |
|
|
|
|
|
|
|
/* ouverture de la fenêtre graphique */ |
|
|
|
puts("(GUI) Opening window"); |
|
|
|
struct gui_resource_t gui_res = display_start(gui_res); |
|
|
|
/* dlsym inutile à cause du bug dlsym sdl (il faut trouver une meilleure solution) */ |
|
|
|
/* dlsym inutile, sert à contourner le bug dlsym sdl sur openbsd */ |
|
|
|
dlsym(NULL,""); |
|
|
|
dlerror(); |
|
|
|
|
|
|
@ -435,9 +432,9 @@ int main(int argc, char** argv) { |
|
|
|
|
|
|
|
int quit = 0; |
|
|
|
for( nb_game_end = 0 ; nb_game_end < nb_game && !quit ; nb_game_end++ ) { |
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr,"%d %s left\n", nb_game, nb_game>1?"games":"game"); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
duration_games[nb_game_end] = time(NULL); |
|
|
|
winner_games[nb_game_end] = -1; |
|
|
|
|
|
|
@ -468,20 +465,14 @@ int main(int argc, char** argv) { |
|
|
|
free(buffer); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
for(i=0;i<121; i++) |
|
|
|
if(game_state.board[i]) |
|
|
|
printf("%d %d\n",i, game_state.board[i]); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* chaque joueur joue */ |
|
|
|
i = 0; |
|
|
|
nb_player_end = 0; |
|
|
|
while(nb_player_end < nb_player-1 && !quit) { |
|
|
|
|
|
|
|
#ifdef debug |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "joueur %d (%s)\n", i, player_state[i].name); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
game_state_copy = game_state; |
|
|
|
previous_movement.start_pos=-1; previous_movement.end_pos=-1; |
|
|
|
first_move = 1; |
|
|
@ -490,32 +481,24 @@ int main(int argc, char** argv) { |
|
|
|
game_state_ia_copy = game_state_copy; |
|
|
|
/* on suppose qu'on a une stratégie */ |
|
|
|
ia_call_function(player_state[i], ia_next_move, &next_move, &game_state_ia_copy, first_move, &movement); |
|
|
|
/* on cherche à valider le coup */ |
|
|
|
printf("(GUI) Moving pawn %d → hole %d\n", movement.start_pos, movement.end_pos); |
|
|
|
if(movement.start_pos != movement.end_pos && movement.start_pos >= 0 && movement.end_pos >= 0 && movement.start_pos < 121 && movement.end_pos < 121) |
|
|
|
/* on effectue le mouvement à l'écran */ |
|
|
|
validation_movement = valid_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 |
|
|
|
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) |
|
|
|
quit += display_animove_pawn(gui_res, game_state_copy, player_state[i].branch, movement.start_pos, movement.end_pos); |
|
|
|
if(valid_move(movement, previous_movement, player_state[i], game_state_copy, start_position, !next_move)) { |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "mouvement (%d,%d) valide\n", movement.start_pos, movement.end_pos); |
|
|
|
#endif |
|
|
|
/* on effectue le mouvement */ |
|
|
|
game_state_copy.board[movement.start_pos]=none; |
|
|
|
game_state_copy.board[movement.end_pos]=player_state[i].branch; |
|
|
|
if(next_move) |
|
|
|
previous_movement=movement; |
|
|
|
else { |
|
|
|
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; |
|
|
|
ia_call_function(player_state[i], ia_end_game, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
#ifdef debug |
|
|
|
/* on cherche à valider le coup */ |
|
|
|
if(validation_movement == invalid) { |
|
|
|
#ifdef debug |
|
|
|
fprintf(stderr, "mouvement (%d,%d) invalide\n",movement.start_pos, movement.end_pos); |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
if( (buffer = (char*) malloc( 28 *sizeof(char) ) ) == NULL) |
|
|
|
display_animsg(gui_res, game_state, player_state[i].branch, "Coup non valide", 1000); |
|
|
|
else { |
|
|
@ -527,8 +510,7 @@ int main(int argc, char** argv) { |
|
|
|
nb_player_end++; |
|
|
|
puts("perdu"); |
|
|
|
/* on enlève les pions du joueur */ |
|
|
|
j=0; |
|
|
|
k=0; |
|
|
|
j=0; k=0; |
|
|
|
do { |
|
|
|
if(game_state.board[j] == player_state[i].branch) { |
|
|
|
game_state.board[j] = none; |
|
|
@ -537,10 +519,31 @@ int main(int argc, char** argv) { |
|
|
|
} while(++j < 121 && k < 10); |
|
|
|
ia_call_function(player_state[i], ia_end_game, NULL); |
|
|
|
} |
|
|
|
next_move=0; |
|
|
|
} |
|
|
|
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; |
|
|
|
ia_call_function(player_state[i], ia_end_game, NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
first_move=0; |
|
|
|
} while(next_move && !quit); |
|
|
|
} while(validation_movement == jump && nb_player_end < nb_player-1 && !quit); |
|
|
|
/* on sélectionne le joueur suivant */ |
|
|
|
j=i; |
|
|
|
do { |
|
|
@ -584,3 +587,4 @@ int main(int argc, char** argv) { |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|