Pour ce premier projet de la semaine, vous allez concevoir un jeu de Morpion ainsi qu'une intelligence artificielle pour ce jeu.
Le Morpion est un jeu où deux joueurs s'affrontent autour d'une grille de dimensions 3 par 3. Chacun leur tour, les joueurs doivent poser un jeton dans une case libre du plateau. Les jetons du premier joueur sont représentés par des croix, alors que ceux du deuxième joueur sont représentés par des cercles. Le premier joueur qui arrive à aligner trois de ses jetons en ligne, en colonne ou en diagonale est déclaré gagnant.

Pour ce projet, un ensemble de fichiers vous est fourni. Cliquez sur le lien ci-dessous pour les télécharger.
Télécharger les fichiers du projet.
Une fois l'archive téléchargée, ouvrez-la et déplacez les fichiers sur votre espace de stockage persistant dans le dossier projets/tictactoe.
Les fichiers sont les suivants :
main.py : Le script à exécuter pour lancer le jeu du Morpion.solver.py : Le fichier qui contient les fonctions pour jouer de manière automatique au Morpion.state.py : Le fichier qui contient les fonctions pour manipuler l'état d'un jeu de Morpion.ui.py : Le fichier qui contient le code de l'interface graphique proposée pour jouer.Ces quatres fichiers sont à mettre dans votre dossier projets/tictactoe. Pour cette première étape, nous allons principalement modifier le fichier state.py.
Le fichier solver.py sera le sujet de la deuxième étape.
Pour la premier étape, vous allez coder les règles du jeu du Morpion.
Pour cela, vous aurez ces fonctions à implémenter dans le fichier state.py :
empty_board qui retourne un nouveau plateau vide.token_at qui indique quel jeton est placé à une position donnée du plateau.is_board_full qui indique si un plateau est totalement rempli ou non.free_cells qui retourne la liste des positions libres du plateau.play qui place un jeton dans le plateau et indique si le coup a résulté en une victoire.unplay qui enlève un jeton du plateau.Avant de se lancer dans l'implémentation de ces fonctions, il est important de réflechir à comment représenter l'état d'un jeu de Morpion, et en particulier l'état du plateau de jeu.
Le jeu du morpion se joue autour d'un plateau de 3 lignes et 3 colonnes. Chacune des cases du plateau peut soit être vide, soit contenir un jeton de joueur (soit une croix, soit un cercle). Pour concevoir un programme qui permet de jouer au Morpion, il nous faudra trouver un moyen de représenter de tels plateaux en Python.
Remarque: Vous êtes totalement libres de la représentation que vous utiliserez pour le plateau de jeu tant que vous pouvez implémenter les fonctions décrites plus haut. Cependant, dans cette section, nous vous présentons une façon de procéder que vous pouvez adopter.
Pour représenter un plateau de jeu de morpion, il est possible d'utiliser une liste de listes. Chacune des listes représente une colonne du plateau qui contiendra trois valeurs, une pour chaque case.
Dans chaque case du plateau, on utilisera la valeur 0 pour indiquer une case vide, la valeur 1 pour indiquer une case occupée par un jeton du premier joueur (croix) et la valeur -1 pour une case occupée par le deuxième joueur (cercle).
Les cases du plateau de jeu ont toute une position selon un système de coordonnées. La case en haut à gauche est en position 0, 0, celle au milieu en haut est 1, 0, jusqu'à la position en bas à droite qui est 2, 2.

Ci-dessous vous trouverez la description des fonctions à implémenter.
empty_boardComme première fonction, implémenter la fonction empty_board. La fonction doit retourner une valeur qui représente un plateau vide.
def empty_board():
passSelon la représentation suggérée, il s'agira d'une liste de trois colonne, chaque colonne étant une liste de trois 0.
token_atLa deuxième fonction à implémenter est la fonction token_at. La fonction a trois paramètres :
board, le plateau de jeu.x l'abscisse de la case.y l'ordonnée de la case.La fonction doit retourner :
0 si la case est vide.1 si la case est occupée par le premier joueur (croix).-1 si la case est occupée par le deuxième joueur (cercle).def token_at(board, x, y):
passSuivant la représentation du plateau choisie, cette fonction sera plus ou moins triviale à implémenter.
is_board_fullLa troisième fonction à implémenter est is_board_full.
La fonction a un unique paramètre qui représente le plateau de jeu.
La fonction doit retourner True si le plateau est totalement rempli et False s'il reste au moins une case de vide.
def is_board_full(board):
passPour cela, il vous faudra parcourir les différentes cases du plateau et indiquez si le tableau est totalement rempli ou non.
free_cellsLa fonction suivante à implémenter est free_cells.
La fonction a un unique paramètre, board, pour le plateau de jeu.
La fonction doit retourner une liste des positions des cases vides du plateau.
Chaque position sera représentée par un tuple (x, y) où x est l'abscisse de la position et y l'ordonnée.
def free_cells(board):
passPour cela, il vous faudra créer une liste de cases vides, initialement vide, puis parcourir les différentes cases du plateau et ajouter au fur et à mesure les cases à la liste.
playLa fonction suivante est la fonction play.
Cette fonction est la plus complexe à implémenter pour cette étape.
La fonction a quatre paramètres :
board, le plateau de jeu.x, l'abscisse de la case.y, l'ordonnée de la case.player, 1 pour le premier joueur, -1 pour le second.On partira du principe que la case choisie est vide et qu'il n'y a pas encore de gagnant.
La fonction doit mettre à jour le plateau de jeu et vérifier si le coup amène à une victoire du joueur. Pour cela, il faut vérifier si par ce coup le joueur arrive à aligner trois jetons sur la même ligne, la même colonne, ou la même diagonale.
def play(board, x, y, player):
passunplayLa dernière fonction à implémenter est unplay.
La fonction a trois paramètres :
board, le plateau de jeu.x, l'abscisse de la case.y, l'ordonnée de la case.La fonction doit modifier le plateau afin d'enlever le jeton à la position indiquée. Bien que cela ne soit pas une action valide au Morpion, nous pourrons faire usage de cette fonction dans la prochaine étape, lorsque nous implémenterons une intelligence artificielle pour le Morpion.
Une fois les quelques fonctions ci-dessus implémentées, vous devriez pouvoir lancer une partie de Morpion en exécutant le script main.py dans le dossier du projet.
Par défaut, un jeu se lance dans une nouvelle fenêtre avec les coups des deux joueurs entrés par le biais de l'interface graphique. Il suffit de cliquer sur une case pour y jouer un coup.
Dans ce même fichier, vous pouvez modifier l'appel à la fonction start_ui pour changer le comportement des joueurs.
La fonction start_ui prend deux argument, un par joueur.
L'argument indique la façon de jouer du joueur.
L'argument None sert à indiquer qu'il n'y a pas de fonction pour déterminer les coups à jouer, c'est donc à l'utilisateur de les rentrer.
En changeant None par random_move, vous indiquez que les coups du joueur en question seront aléatoires.
Par exemple, pour que le joueur 1 joue de manière aléatoire contre un joueur 2 controlé par l'utilisateur, on aura:
if __name__ == '__main__':
start_ui(random_move, None)En plus de None et random_move, il est possible d'utiliser la valeur best_move. Cependant, la fonction best_move n'est pas encore implémentée. Cela sera votre travail pour l'étape suivante du projet !