skizzle/docs/rapports/rapport-initial-delabre/parts/go.tex

220 lines
9.8 KiB
TeX

%%%%%%%%%%
% Macros %
%%%%%%%%%%
% Dessine une pierre en X, Y de la couleur donnée
% (doit être utilisé dans un environnement TikZ)
\newcommand{\fillstone}[3]{
\draw [fill=#3] (#1,#2) circle (.4);
}
%%%%%%%%%%
% Source %
%%%%%%%%%%
\chapter{Jeu de go}
Joué en occident depuis le XIX siècle, le jeu de go est originaire
d'Asie et vieux de plusieurs milliers d'années. La société étasunienne
de Go le décrit comme \flqq~le plus ancien jeu toujours joué sous
sa forme originale.~\frqq~\cite{ggo-aga}
Comme les échecs, le jeu de go est déterminé, à information complète
et parfaite~: à tout moment tous les joueurs ont la même information
à disposition pour décider de leur coup et il n'y a pas de hasard.~\cite{game-theory-wiki}
Malgré la simplicité apparente du jeu, le nombre de combinaisons possibles
s'élève à plus de $10^{600},$ ce qui en fait l'un des objectifs non-atteints
les plus anciens en matière de recherche en intelligence artificielle.
Le programme \emph{AlphaGo} de \emph{Google} tentera en mars prochain de rivaliser
avec le meilleur joueur de go au monde, Lee Sedol.~\cite{ggo-ai,ggo-compqueens}
\section{Principes}
\subsection{Matériel}
Le jeu se joue sur un plateau de $18 \times 18$ cases (soit
$19 \times 19$ intersections) appelé \emph{goban.} Deux joueurs
s'affrontent en posant à tour de rôle des pierres blanches
et noires.
\subsection{Règles}
Lorsqu'un joueur doit jouer, il peut soit poser une pierre
de sa couleur sur une des intersections du \emph{goban,} soit passer son tour.
Si les deux joueurs passent successivement, la partie est terminée.~\cite{ggo-ffg}
\begin{wrapfigure}[12]{r}{0.35\linewidth}
\centering
\input{./figures/go-ex-1}
\caption{La chaîne blanche sera capturée par la pose d'une pierre noire en~(1)}
\label{fig:go-ex-1}
\end{wrapfigure}
On définit une chaîne comme étant une zone de pierres
interconnectées horizontalement ou verticalement (mais pas
diagonalement). Les \emph{libertés} d'une telle chaîne
sont le nombre d'intersections vides autour d'elles (horizontalement,
verticalement, mais pas diagonalement).
Si, en plaçant une pierre, un joueur supprime la dernière
liberté d'une chaîne adverse, la chaîne en question est capturée
et retirée du plateau, comme montré en figure \ref{fig:go-ex-1}.
Un joueur peut placer sa pierre n'importe où sur le
\emph{goban,} pour peu que cela ne supprime pas toutes les libertés
d'une de ses chaînes et que cela ne répète pas une position précédente du jeu.
\subsection{Fin du jeu}
À la fin de la partie, c'est-à-dire après que les deux joueurs
ont passé leur tour, on décompte les points. Chaque pierre
présente sur le \emph{goban} rapporte un point, ainsi que chaque
intersection vide à l'intérieur du territoire d'un joueur.
Un territoire d'un joueur est défini comme étant une zone inoccupée du plateau,
séparée du reste uniquement par des pierres de la couleur attribuée à ce joueur.
La figure \ref{fig:go-ex-2} montre des exemples de territoires.
\begin{figure}[h!]
\centering
\input{./figures/go-ex-2}
\caption{Un territoire du joueur attribué aux blancs en~(1) et un territoire du joueur attribué aux noirs en~(2)}
\label{fig:go-ex-2}
\end{figure}
\section{Modélisation}
Seules les $19 \times 19$ intersections de la grille sont utilisées,
pas les cases. On pourra donc utiliser un tableau de tableaux de taille
$19 \times 19.$ À tout moment, chaque case peut soit être vide, soit
occupée par une pierre noire, soit occupée par une pierre blanche.
On optera donc pour un tableau de tableaux d'entiers, en représentant
par $0$ l'état vide, $1$ la présence d'une pierre noire et $2$ la
présence d'une pierre blanche.
On maintiendra en tout temps une liste des chaînes actives, avec une
liste des intersections occupées par ces chaînes et le nombre de leurs libertés.
Après chaque coup, la grille sera hachée et le résultat sera ajouté
dans une liste appelée la liste des positions précédentes.
\section{Algorithmes}
\begin{description}
\item[Initialisation] Allocation d'une grille de taille
$19 \times 19,$ initialisée à $0$.
\item[Placement d'une pierre] Étant donnés une position et
la couleur de la pierre à placer.
\begin{enumerate}
\item Si la pierre se situe en dehors de la grille, le coup est invalide.
Terminer l'algorithme.
\item Faire une copie de la grille et de la liste des chaînes. Dans le
reste de l'algorithme, on opérera uniquement sur ces copies, sauf mention contraire.
\item À la position choisie dans la grille, affecter l'entier correspondant
à la couleur du joueur (1 ou 2).
\item Hacher la grille et comparer l'empreinte à la liste des positions
précédentes. S'il y a correspondance, le coup reproduit un état de jeu déjà
atteint, donc le coup est invalide. Terminer l'algorithme.
\item Identifier toutes les chaînes voisines horizontalement et
verticalement à la pierre placée. Mettre à jour les libertés et
les pierres composant ces chaînes.
\item Si une chaîne voisine de la couleur adverse n'a plus aucune
liberté, effacer toutes ses pierres dans la grille et supprimer la
chaîne de la liste des chaînes. Mettre à jour les libertés des
chaînes voisines.
\item Si une chaîne voisine de la couleur du joueur jouant le coup
n'a plus aucune liberté, le coup est invalide. Terminer
l'algorithme.
\item Appliquer les grilles copiées dans les grilles originales.
\item Ajouter l'empreinte de la grille à la liste des positions
précédentes.
\end{enumerate}
\item[Décompte des points] On initialise deux compteurs pour les points
du joueur attribué aux noirs et les points du joueur attribué aux blancs.
Pour parcourir les territoires des joueurs on utilise une variante de
l'algorithme de remplissage par diffusion.~\cite{ggo-algofloodfill}
\begin{enumerate}
\item Parcourir la grille et attribuer un point par pierre placée à chaque joueur.
\item Créer une grille $G$ de même taille que la grille de jeu, initialisée à 0.
\item Pour chaque case $C$ dans la grille de $(0,0)$ à $(18,18)$, si la case n'est
pas vide ou si $G[C] = 1,$ passer à la case suivante, sinon~:
\begin{enumerate}
\item initialiser une liste $L$ contenant uniquement $C$~;
\item initialiser un compteur $cases$ à 0~;
\item initialiser une variable $couleur$ vide~;
\item tant que la liste $L$ n'est pas vide, faire~:
\begin{enumerate}
\item prendre $D$ la première case de $L$~;
\item supprimer le premier élément de $L$~;
\item si la case $D$ est vide, passer $G[D]$ à 1,
ajouter les cases au nord, au sud, à l'est et à l'ouest de $D$ dans $L$ si
elles ne sont pas telles que $G[X] = 1,$ et incrémenter $cases$~;
\item sinon, si $couleur$ est vide, $couleur := couleur(D)$~;
\item sinon, si $couleur \neq couleur(D), couleur := mixte$~;
\end{enumerate}
\item si $couleur = noir,$ ajouter $cases$ points au joueur attribué
aux pierres noires. Si $couleur = blanc,$ ajouter $cases$ points
au joueur attribué aux pierres blanches.
\end{enumerate}
\end{enumerate}
\item[Affichage] La grille sera parcourue case par case. Chaque valeur
différente de 0 provoquera le placement d'un pion sur l'intersection
correspondante de la couleur correspondante. Le programme devra
être réceptif aux clics sur la grille et appeler l'algorithme de placement
d'un pion en conséquence.
\end{description}
\section{Spécifications}
\subsection{Version initiale}
On choisira le langage C++, qui possède les structures requises dans
la section précédente, et est enseigné dans le cursus. Il n'y a pas de difficulté
algorithmique particulière qui justifie le choix d'un langage différent,
sachant que le choix d'un tel langage pourrait ralentir le développement.
On préfèrera un affichage fenêtré au vu des nombreuses interactions
qui seront facilitées par l'usage de la souris. On proposera une
grille de taille fixe $19 \times 19.$
Les deux joueurs utiliseront la même fenêtre, plaçant leur
pierre à tour de rôle.
Les types standards, comme
\texttt{std::vector} ou \texttt{std::unordered\_map}, seront utilisés
pour représenter les structures abordées dans la section traitant
de la modélisation.
\subsection{Améliorations possibles}
Une interface plus travaillée pourra être proposée avec un
choix parmi différentes tailles standard de grille telles que
$9 \times 9$ et $13 \times 13.$
Les joueurs pourront s'affronter en réseau.
\section{Organisation}
L'implémentation des algorithmes
demandera de la documentation sur les hachages, les
tableaux associatifs et autres structures abordées ci-avant.
Il y a deux algorithmes principaux~: le décompte des points
et le placement d'une pierre. On consacrera à la mise au point
des algorithmes initiaux et à leur perfection 40 heures au total.
Pendant le développement des algorithmes, le fenêtrage
pourra être conçu avec l'interface de choix des grilles
et de présentation des résultats. On pourra y consacrer
10 heures.
La mise en réseau du jeu se fera lorsque les algorithmes
seront suffisamment robustes. Elle nécessitera de la
documentation sur les \emph{sockets} avec la SFML. On
pourra y consacrer 15 heures.
La rédaction du rapport s'effectuera en continu pendant la création du jeu.
La figure~\ref{fig:go-gantt} présente un diagramme de Gantt résumant
la répartition du travail.
\begin{figure}[h!]
\centering
\input{./figures/go-gantt}
\caption{Développement du jeu de go sur 40 heures}
\label{fig:go-gantt}
\end{figure}