Puissance 4

Étape 1

Pour ce projet, vous allez concevoir un jeu de Puissance 4 et une IA pour y jouer.

Au Puissance 4, deux joueurs s'affrontent autour d'un plateau de 7 colonnes et 6 lignes. Chacun leur tour, les joueurs choissent une colonne à jouer et y déposent un jeton de leur couleur (rouge pour le joueur 1, jaune pour le joueur 2) à la position la plus basse possible dans la colonne. Le premier joueur qui arrive à aligner 4 jetons en ligne, en colonne ou en diagonale est déclaré gagnant.

Fichiers du projet

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/connect4.

Les fichiers sont les suivants :

Ces quatre fichiers sont à mettre dans votre dossier projets/connect4. Pour cette première étape, nous allons principalement modifier le fichier state.py. Le fichier solver.py sera le sujet des étapes suivantes.

Description

Pour la première étape du projet, vous allez concevoir la classe Board qui permettra de représenter l'état d'un plateau de jeu de Puissance 4. Un squelette de la classe vous est déjà fourni, dans le fichier state.py. Le contenu du fichier est le suivant :

class Board(object):
    def __init__(self, width=7, height=6, connect=4):
        pass

    def get_width(self):
        pass

    def get_height(self):
        pass

    def get_connect(self):
        pass

    def get_next_player(self):
        pass

    def get_token(self, x, y):
        pass

    def free_columns(self):
        pass

    def play(self, column):
        pass
    
    def unplay(self, column):
        pass

Les différentes méthodes sont décrites ci-dessous. Vous êtes libre de la façon dont vous implémentez ces méthodes, pour autant que vous suiviez ce qui est décrit.

__init__

Le constructeur __init__ a trois paramètres en plus de self :

Ces paramètres ont tous une valeur par défaut qui correspond aux valeurs traditionnellement admises au Puissance 4.

get_width

La méthode get_width doit retourner la largeur du plateau de jeu.

get_height

La méthode get_height doit retourner la hauteur du plateau de jeu.

get_connect

La méthode get_connect doit retourner le nombre de jetons à aligner pour gagner.

get_next_player

La méthode get_next_player doit indiquer à qui c'est de tour de jouer un pion. Pour le joueur 1, la valeur 1 est attendue, alors que pour le joueur 2, on attend -1.

Vous pouvez partir du principe que la méthode ne sera appelée que lorsque le jeu n'est pas terminé.

get_token

Retourne le jeton situé à une position précise du tableau. On attend la valeur 1 pour un jeton du premier joueur, la valeur -1 pour un jeton du second joueur, et la valeur 0 pour une case vide. L'argument x indique la colonne (depuis la gauche) et l'argument y la ligne (en partant du bas).

Afin de simplifier l'implémentation de votre fonction play plus bas, et en particulier la vérification de l'existence d'une séquence de jetons gagnante, faites en sortes de retourner None (ou 0) lorsque la position donnée est hors du plateau.

free_columns

La méthode free_columns doit retourner une listes des colonnes qui peuvent être jouées, c'est-à-dire des colonnes qui contiennent un emplacement libre. Chaque colonne sera identifiée par son numéro de colonne (de 0 à self.get_width() - 1).

play

La méthode play doit permettre de jouer le pion d'un joueur dans la colonne indiquée et de passer le tour au joueur suivant.

Si par ce coup le joueur gagne, alors la méthode devra retourner True. La méthode devra retourner False autrement. Pour cela, il faudra vérifier à ce moment s'il existe une ligne, une colonne ou un diagonale de jetons du joueur de longueur au moins self.get_connect().

Conseils d'implémentation

Pour vérifier si un groupe de longueur self.get_connect() jetons de la couleur du joueur existe après l'insertion d'un jeton, il suffit de contrôler les groupes qui contiennent le dernier jeton inséré.

Il y a donc self.get_connect() groupes horizontaux à vérifier, un unique groupe vertical au maximum à vérifier et self.get_connect() groupes pour chacune des deux diagonales à vérifier. Dans chaque groupe, il y a self.get_connect() positions à vérifier.

Il faudra donc utiliser une boucle pour parcourir tous les groupes et, à l'intérieur de cette boucle, utiliser une autre boucle pour parcourir toutes les positions contenues dans le groupe. Il peut être intéressant de séparer le traitement des groupes horizontaux, verticaux, et des deux diagonales.

Vous pouvez utiliser self.get_token afin d'accéder à un token du plateau. Ceci peut être utile afin de ne pas à avoir à ce soucier de savoir si la position est bien à l'intérieur du plateau de jeu.

unplay

La méthode unplay doit retirer le jeton le plus haut de la colonne indiquée et passer le tour à l'autre joueur.

On partira du principe que la colonne dans laquelle le jeton doit être enlevée est la dernière colonne dans laquelle un jeton a été joué.

Essayer votre code

Une fois votre classe définie, vous pourrez tester le bon fonctionnement de votre code en lançant une partie de Puissance 4 entre deux joueurs humains.

Pour cela, il vous suffira simplement d'exécuter le script main.py.