/* Détermine si le joueur 'joueur' peut jouer (renvoie vrai) ou non (renvoie faux) */ int peut_jouer(othello *jeu, char joueur){ int i,j; for(i=0;i<TAILLE;i++) for(j=0;j<TAILLE;j++) if(coup_possible(jeu, joueur, i,j)) return 1; return 0; }
int possible (struct Partie partie) { int i, j; for(i = 0; i < 8; i++) // Teste toutes les cases du plateau for(j = 0; j < 8; j++) { struct Vector coord; coord.X = i; coord.Y = j; if(coup_possible(partie, coord)) // Si au moins une case peux être jouée, alors le joueur courant peux jouer return 1; } return 0; // Sinon, il doit passer son tour }
/* Fonction permettant de faire jouer un joueur humain - saisie des coordonnées tant qu'elles sont invalides - jouer le coup */ int humain_joue_un_coup(othello* jeu, char joueur){ int i, j, ok=0; if(!peut_jouer(jeu, joueur)){ return 0; } do{ printf("Joueur J%d [%c]:\n", joueur==J1?1:2, joueur); printf("ligne: "); scanf("%d", &i); printf("colonne: "); scanf("%d", &j); if(!case_libre(jeu, i, j)) printf("La case est occupée, recommencez ...\n"); else if(!(ok=coup_possible(jeu, joueur, i, j))) printf("Vous ne pouvez pas jouer ici, recommencez ...\n"); } while(!ok); jouer_un_coup(jeu, joueur, i, j); return 1; }
/* Fonction min-max permettant de déterminer ou jouer - le meilleur coup est stocké dans *ti et *tj - joueur est le joueur devant joue le meilleur coup - joueur_actif est le joueur jouant le tour actuel - depth = profondeur actuelle dans l'arbre de recherche - max-depth = profondeur maximale, la récursion s'arrête si on l'atteind */ int min_max(othello* jeu, char joueur, char joueur_actif, int nb_coups, int*ti, int*tj, int depth, int max_depth){ int meilleur_score =-1; int cur_score; int i, j; typedef struct coord_meilleur_coup{ int ligne; int colonne;} coord_MC; //structure des coordonnées d'un meilleur coup int compteur_mc= 0; //compteur de meilleur coup coord_MC tab[TAILLE*TAILLE]; /* tableau stockant chaque meilleur coup possible */ /* Si la partie est finie ou si on a atteind la profondeur maximale -> on renvoie le score du plateau */ if(partie_finie(nb_coups, 0)||depth == max_depth){ meilleur_score = score(jeu, joueur_actif, depth, nb_coups); } else { //on parcours toutes les positions for(i=0; i<TAILLE; i++){ for(j=0; j<TAILLE; j++){ //si on a un coup possible on renvoi le meilleur coup a jouer if(coup_possible(jeu, joueur_actif, i, j)){ empiler(*jeu); jouer_un_coup(jeu, joueur_actif, i, j); cur_score = min_max(jeu, joueur, adversaire(joueur_actif), nb_coups+1, ti, tj, depth+1, max_depth); depiler(jeu); if(joueur_actif == joueur){ meilleur_score = -1000; if(cur_score > meilleur_score){ meilleur_score = cur_score; *ti = i; *tj = j; tab[compteur_mc].ligne = i; tab[compteur_mc].colonne = j; } compteur_mc++; } if(joueur_actif == adversaire(joueur)){ meilleur_score = 1000; if(cur_score < meilleur_score){ meilleur_score = cur_score; *ti = i; *tj = j; tab[compteur_mc].ligne = i; tab[compteur_mc].colonne = j; } compteur_mc++; } } //endif coup_possible() } } if(compteur_mc > 0){ int al = rand()%compteur_mc; *ti = tab[al].ligne; *tj = tab[al].colonne; } else{ *ti =-1; *tj =-1; } } /* pour tous les coups possibles sauvegarder le jeu (empiler) jouer ce coup score = appel récursif de min_max avec les paramètres mis à jour restaurer le jeu (dépiler) Si c'est à nous de jouer -> conserver le score max et le coup correspondant Si c'est à l'adversaire de jouer -> conserver le score min et le coup correspondant S'il y a au moins 1 meilleur coup possible mettre le coup correspondant dans ti et tj Amélioration : choisir aléatoirement un coup parmis les meilleurs possibles Sinon mettre -1,-1 dans ti et tj renvoyer le score */ return meilleur_score; }