\documentclass{beamer} % Metropolis + barre de progression + numéro de page \usetheme[progressbar=frametitle, numbering=fraction]{metropolis} \setbeamertemplate{frame footer}{\insertsection \hfill\hspace{-4em} \insertshorttitle} % texte footer \setbeamerfont{page number in head/foot}{size=\tiny} % taille police footer \setbeamercolor{footline}{fg=gray} % couleur footer \setbeamertemplate{section in toc}[sections numbered] % enumerate au lieu d'itemize \usepackage[T1]{fontenc} % encodage \usepackage[french]{babel} % langue \usepackage{etoolbox} % on inverse le titre court et le titre long dans le plan \makeatletter \patchcmd{\beamer@section}{{#2}{\the\c@page}}{{#1}{\the\c@page}}{}{} \patchcmd{\beamer@section}{{\the\c@section}{\secname}}{{\the\c@section}{#1}}{}{} \makeatother \usepackage{hyperref} % liens cliquable \usepackage{multicol} % liste sur plusieurs colonnes \usepackage[figurename=]{caption} % nom des images \usepackage{minted} % intégration code \usemintedstyle{emacs} \newminted[pseudocode]{python}{autogobble,linenos,fontsize=\scriptsize,escapeinside=!!} \title[IA pour Othello]{\href{https://jj.up8.site/AA/ProjetsAA.pdf}{Projet} - IA pour le jeu d'Othello} \author{\href{mailto:anri.kennel@etud.univ-paris8.fr}{Anri Kennel} | L3-A} \institute{Algorithmique avancée $\cdot$ Université Paris 8} \date{Année universitaire 2022-2023} \begin{document} \maketitle \begin{frame}[t,plain]{Plan} \tableofcontents \end{frame} \section{Projet} \begin{frame}{Projet} \begin{columns}[onlytextwidth] \def\rcolumn{50mm} % taille colonne de droite \column{\linewidth-\rcolumn-1mm} % colonne de gauche Jeu d'Othello : \begin{itemize} \item Jeu de plateau 8x8 \item<2-> 2 joueurs \item<3-> Prendre en sandwich l'adversaire \end{itemize} \column{\rcolumn} % colonne de droite \only<1>{ \begin{figure} \includegraphics[width=\rcolumn]{../imgs/othello_othellier.png} \caption*{Othellier} \end{figure} } \only<2>{ \begin{figure} \includegraphics[width=\rcolumn]{../imgs/othello_init.png} \caption*{Début du jeu} \end{figure} } \only<3->{ \begin{figure} \includegraphics[width=\rcolumn]{../imgs/othello_premiercoup.png} \caption*{Premier coup} \end{figure} } \end{columns} \end{frame} \section{Implémentation} \subsection*{Othello} \begin{frame}{Jeu d'Othello} \only<1>{ \begin{figure} \includegraphics[width=0.9\textwidth]{../imgs/othello_impl_hh.png} \caption*{Jeu : \texttt{./othello humain humain}} \end{figure} } \only<2->{ \begin{figure} \includegraphics[width=0.9\textwidth]{../imgs/othello_impl_ma.png} \caption*{Jeu : \texttt{./othello minimax alphabeta}} \end{figure} } \end{frame} \begin{frame}[fragile]{Comment ?} \begin{columns}[onlytextwidth] \def\rcolumn{63mm} % taille colonne de droite \column{\linewidth-\rcolumn-1mm} % colonne de gauche \begin{itemize} \item Liste chaînée \item<3-> Coups \item<4-> Propriétés \item<5-> Jeu \end{itemize} \column{\rcolumn} % colonne de droite \begin{overprint} \onslide<1> \begin{figure} \vspace{25mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize,highlightlines={4}]{c} struct joueur { char *nom; int couleur; Liste *liste_jeton; int nb_jeton; }; \end{minted} \caption*{Liste des jetons des joueurs} \end{figure} \onslide<2> \begin{figure} \vspace{27mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize,highlightlines={2}]{c} struct coups { Liste *coups; int taille_liste; }; \end{minted} \caption*{Liste pour les coups possibles} \end{figure} \onslide<3> \begin{figure} \vspace{27mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize]{c} Coups *action_possible_joueur (Jeton *plateau[LONGEUR][LARGEUR], const int couleur); \end{minted} \caption*{Liste pour les coups possibles pour un joueur} \end{figure} \onslide<4> \begin{figure} \vspace{20mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize]{c} /* Une case est soit vide, * soit occupé par un des joueurs, * noir ou blanc */ enum CASE { VIDE = ' ', BLANC = 'B', NOIR = 'N' }; /* Propriété globale du jeu */ enum PLATEAU { LONGEUR = 8, LARGEUR = 8 }; /* Type de joueurs */ enum PLAYER_TYPE { HUMAIN, MINIMAX, ALPHABETA }; \end{minted} \caption*{Propriétés du jeu} \end{figure} \onslide<5> \begin{figure} \vspace{25mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize]{c} /* Gère le coup d'un joueur en faisant les changements nécessaire au jeu * Renvoie 0 en cas de coup illégal */ int jeu_joueur(Jeu *jeu, const int case_i, const int case_j, const int couleur); \end{minted} \caption*{Jeu d'un joueur} \end{figure} \end{overprint} \end{columns} \vspace{-1cm} \onslide<3>{\hspace{3cm}Pour \textbf{tous} les joueurs} \onslide<5>{\hspace{-45mm}Tous les joueurs s'en servent pour jouer} \end{frame} \subsection*{Minimax} \begin{frame}[fragile]{Algorithme minimax} \begin{onlyenv}<3> \begin{pseudocode} def minimax(jeu, profondeur, joueur_actuel, gagnant, resultat): ! !possibilites = recuperation_possibilites(jeu, joueur_actuel) ! !if (possibilites == 0): ! ! joueur_actuel = ennemi(joueur_actuel) ! ! possibilites = recuperation_possibilites(jeu, joueur_actuel) ! ! if (possiblites == 0): ! ! return heuristique(jeu, gagnant) ! !if (joueur_actuel == gagnant): ! ! resultat = -INFINI ! !else: ! ! resultat = +INFINI ! !profondeur = profondeur - 1 ! !resultat_tmp = resultat ! !for (i in possibilites): ! ! copie_jeu = jeu ! ! joue_coup(i, joueur_actuel) ! ! if (profondeur > 0): ! ! minimax(copie_jeu, profondeur, ennemi(joueur_actuel), gagnant, resultat_tmp) ! ! else: ! ! resultat_tmp.score = heuristique(copie_jeu, gagnant) \end{pseudocode} \end{onlyenv} \begin{onlyenv}<4> \vspace{5mm} \begin{pseudocode} ! !# toujours dans la boucle... ! ! if (joueur_actuel == gagnant): # MAX ! ! if (resultat_tmp.score >= score): ! ! resutat.score = resultat_tmp.score ! ! resultat.position = i ! ! else: # MIN ! ! if (resultat_tmp.score <= score): ! ! resultat.score = score ! ! resultat.position = i \end{pseudocode} Notre heuristique ressemble à ceci : \begin{pseudocode} def heuristique(jeu, joueur): ! !res = jeu.J1.nombre_jeton - jeu.J2.nombre_jeton ! !if (jeu.J1 == joueur): ! ! return res ! !return -res \end{pseudocode} \end{onlyenv} \begin{columns}[onlytextwidth] \def\rcolumn{50mm} % taille colonne de droite \column{\linewidth-\rcolumn-1cm} % colonne de gauche \begin{itemize} \item<1-2> Utilises les fonctions déjà définis \item<2> Ressemble à la fonction pour les humains \end{itemize} \column{\rcolumn} % colonne de droite \begin{overprint} \onslide<2> \begin{figure} \vspace{15mm} \begin{minted}[autogobble,linenos,fontsize=\scriptsize]{c} void action_joueur_minimax (Jeu *jeu, const int couleur, const int profondeur); \end{minted} \vspace{1mm} \begin{minted}[autogobble,linenos,firstnumber=last,fontsize=\scriptsize]{c} void action_joueur_humain (Jeu *jeu, const int couleur); \end{minted} \caption*{Définition de minimax comparé à celle pour les humains} \end{figure} \end{overprint} \end{columns} \onslide<2>{\hspace{25mm}$\Rightarrow$ Utilisation de fonctions auxiliaires} \end{frame} \subsection*{Alpha-bêta} \begin{frame}[fragile]{Algorithme alpha-bêta} \begin{onlyenv}<2> \begin{pseudocode} def alphabeta(jeu, profondeur, joueur_actuel, gagnant, resultat, note, qui): ! !possibilites = recuperation_possibilites(jeu, joueur_actuel) ! !if (possibilites == 0): ! ! joueur_actuel = ennemi(joueur_actuel) ! ! possibilites = recuperation_possibilites(jeu, joueur_actuel) ! ! if (possiblites == 0): ! ! return heuristique(jeu, gagnant) ! !if (joueur_actuel == gagnant): ! ! resultat = -INFINI ! !else: ! ! resultat = +INFINI ! !profondeur = profondeur - 1 ! !resultat_tmp = resultat ! !coupure = false ! !for (i in possibilites): ! ! if (coupure): ! ! return resultat_tmp \end{pseudocode} \end{onlyenv} \begin{onlyenv}<3> \begin{pseudocode} ! !# toujours dans la boucle... ! ! copie_jeu = jeu ! ! joue_coup(i, joueur_actuel) ! ! if (profondeur > 0): ! ! alphabeta(copie_jeu, profondeur, ennemi(joueur_actuel), gagnant, resultat_tmp, resultat, joueur_actuel) ! ! else: ! ! resultat_tmp.score = heuristique(copie_jeu, gagnant) ! ! if (joueur_actuel == gagnant): ! ! if (qui == ennemi(gagnant) and score_tmp.score >= note): ! ! coupure = true ! ! resultat = +INFINI ! ! else: ! ! if (resultat_tmp.score >= resultat.score): ! ! resutat.score = resultat_tmp.score ! ! resultat.position = i ! ! if (resultat.score == +INFINI): ! ! coupure = true \end{pseudocode} \end{onlyenv} \begin{onlyenv}<4> \vspace{10mm} \begin{pseudocode} ! !# toujours dans la boucle... ! ! else: ! ! if (qui == gagnant and score_tmp.score <= note): ! ! coupure = true ! ! resultat = -INFINI ! ! else: ! ! if (resultat_tmp.score <= resultat.score): ! ! resutat.score = resultat_tmp.score ! ! resultat.position = i ! ! if (resultat.score == -INFINI): ! ! coupure = true \end{pseudocode} Avec la même heuristique que minimax \end{onlyenv} \begin{itemize} \item<1> Ressemble à minimax, seule différence : \begin{itemize} \item argument \texttt{note} : score précédent \item argument \texttt{qui} : joueur à qui la note appartient \end{itemize} \end{itemize} \end{frame} \section{Comparaison} \begin{frame}[fragile]{Comparaison d'efficacité} \only<3> { \vspace{25mm} \begin{itemize} \item À profondeur égale: \begin{itemize} \item même taux de victoire \item alpha-bêta beaucoup plus rapide \end{itemize} \end{itemize} En temps raisonnable, minimax peut aller jusqu'à une profondeur de 5 alors qu'alpha-bêta peut aller jusqu'à 8.\\ $\Rightarrow$ Avantage pour alpha-bêta } \begin{columns}[onlytextwidth] \def\rcolumn{60mm} % taille colonne de droite \column{\linewidth-\rcolumn+1mm} % colonne de gauche \begin{itemize} \item<1-2> Implémentation dans \texttt{test.c}. \item<2> Vitesse et victoires \end{itemize} \column{\rcolumn-5mm} % colonne de droite \begin{overprint} \onslide<1> \begin{figure} \includegraphics[width=\rcolumn]{../imgs/othello_impl_tests.png} \caption*{Tests : \texttt{./othello --test}} \end{figure} \onslide<2> \vspace{15mm} \begin{figure} \begin{minted}[autogobble,linenos,fontsize=\scriptsize]{c} void run_tests(void) { speed_test(6, 8); winrate_test(5, 7); } \end{minted} \caption*{Fonction lançant les tests} \end{figure} \end{overprint} \end{columns} \end{frame} \appendix \section{\hspace{3cm} Merci} \end{document}