Le jeu du morpion en python

Projets

Nous avons réalisé ce projet dans le cadre d’un travail demandé par nos professeurs de NSI, nous avions le choix entre différents projets mais avons choisi le morpion car nous voulions réaliser un jeu pour finir l’année en beauté.

Introduction

Cet article vous présentera le dernier projet de la spécialité NSI que nous avons réalisé avec Bilal L., Corentin K. et Joseph A.

Pour ce dernier projet nous avons décidé de faire le jeu du Morpion sur la calculatrice Numworks en python. Pour cela nous avons dû utiliser différents modules et faire des recherches variées pour savoir comment coder ce jeu. C’est ce que nous allons vous expliquer dans ce compte rendu.

Bonne lecture !

Quelques fonctions basiques mais importantes

Premièrement, nous avons regardé quelques vidéos et sites web pour savoir par où commencer, nous sommes finalement tombés sur la vidéo de « Schraf : Maths-info” (une chaîne YouTube spécialisée en informatique) : “Python – Jeu du type Morpion avec la tortue (Part 1)”.

Dans cette vidéo, il commence par faire la grille donc nous l’avons suivi et avons récupéré le script de celle-ci après l’avoir compris :

H, L =320 , 222
def grille(nb):
      case = min(H,L) // nb
      H_m, L_m = -nb * case / 2, -nb * case /2
      for i in range(1,nb):
        trait(L_m, H_m + case * i, 0, nb * case)
        trait(L_m + case * i, H_m, 90, nb * case)
      return case, H_m, L_m
    grille(3)

La 1ère ligne permet, en fonction de la taille de l’écran de faire les différentes cases demandées par le joueur.

La seconde ligne, elle, permet de tracer les différentes cases avec le bon écart.


Ensuite, grâce à la fonction trait : la grille est tracée.

Une fois la fonction achevée, on l’appelle avec le nombre de case que l’on veut, ici, il est de 3.

Puis, il nous faut le cercle et la croix pour les placer sur la grille, on a donc fait une fonction pour chaque :

def cercle():
        pensize(2)
        setheading(0)
        pendown()
        penup()
        forward(30)
        pendown()
        left(90)
        circle(25)
        setheading(0)
        penup()
        backward(25)
        left(90)
 def croix():
        pensize(2)
        right(45)
        pendown()
        for i in range(4):
            right(90)
            forward(40)
            penup()
            backward(40)
            pendown()
        setheading(90)
        penup()

Au début, nous avons eu un problème avec le cercle car il ne se crée pas directement au centre mais sur les côtés, on a donc dû rajouter à la fonction un forward pour que le centre du cercle se place au centre de la colonne.


Pour que les joueurs puissent comprendre les règles du jeu pour ce qu’il ne connaissent pas ou ne savent pas appuyer sur quelles touches de la calculatrice pour jouer, nous avons décidé de faire deux pages d’accueil pour tout expliquer.

draw_string("Appuyez sur EXE pour continuer",20,4
0,(255,128,0))draw_string("Règles du jeu : \n\n  ·Chaque joueur possèdent un \n  symbole différent.\n  ·Le premier avec 3 symboles\n  sur une ligne gagne.",0,75,(0, 0,0))
while not (keydown(KEY_EXE)):True

Nous avons fait la première page d’accueil qui indique les règles du jeu en utilisant la fonction draw_string qui permet d’écrire du texte de la façon demandée. Ensuite avec le module Ion, il nous suffit d’appuyer sur la touche “EXE” de la calculatrice pour passer à la seconde page d’explication.


Le cœur du morpion

Le déplacement entre les cases

Cela fait, il nous fallait pouvoir déplacer naviguer entre les différentes cases.

On a donc utilisé le module Ion qui est sur la calculatrice Numworks, il permet d’utiliser les touches de la calculatrice pour y relier des actions, ici : se déplacer ou dessiner les croix et cercles.

Nous avons eu beaucoup de mal à utiliser ce module au début mais c’est en regardant un autre code de “Schraf : Maths-info” sur le jeu de la vie que nous avons compris comment il fonctionnait.

Dans un premier temps, il faut utiliser keydown puis mettre la touche que l’on veut utiliser en paramètre.

Par exemple:

if keydown(KEY_ONE):
      goto(-75,-74)
      croix()

Ici, quand la touche 1 de la calculatrice est enfoncée, la tortue se déplace aux coordonnées demandées et se met à dessiner la croix.

Dans l’ordre des choses, il suffit donc que chaque case soit assignée à une touche.

Et à partir de là, on peut dessiner toutes les croix ou des cercles à n’importe quelle case.

Cela nous a permis de voir le début d’un jeu fonctionnel et nous a largement motivés quant à la suite de ce projet !


La vérification de victoire

La vérification permet de vérifier si un des joueurs a gagné, et si oui, lequel. C’est sûrement ce qu’il nous a le plus posé de problème au cours du projet.

D’abord, nous avons dû apprendre à savoir ce qu’est une matrice (une liste de liste) : 

matrice = [[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']]

On peut la percevoir comme une grille en 3×3, comme celle du morpion pour faciliter l’explication : 

matrice = [[' ', ' ', ' '],
           [' ', ' ', ' '],
           [' ', ' ', ' ']]

C’est une liste de listes où chaque liste contient 3 éléments, ici vides.

Comme dit plus haut, on doit percevoir cette matrice comme la grille du morpion, pour en quelque sorte les “relier” : 

if j == 1:
      if keydown(KEY_ONE) and matrice[0][0] == " ":
            indice = 0
            goto(-75,-74)
            croix()
            matrice[0][0] = j
            j = 2
            verification_croix()

Dans la ligne « matrice[0][0] = j », on associe le 1er emplacement de la 1ère liste de la matrice à j, donc à 1 (ce même nombre renvoie à l’utilisation de la croix).

On associe alors indirectement la case en haut à gauche à la croix, puis on lance la fonction verification_croix.

def verification_croix():
    for i in range (3):
        if matrice[i][0] == matrice[i][1] == matrice[i][2] == 1:
            victoire_croix()
    for i in range(3):
        if matrice[0][i] == matrice[1][i] == matrice[2][i] == 1:
            victoire_croix()
    if matrice[0][0] == matrice[1][1] == matrice[2][2] == 1:
        victoire_croix()
    if matrice[0][2] == matrice[1][1] == matrice[2][0] == 1:
        victoire_croix()

Dans cette fonction qui vérifie si le joueur croix a gagné, on vérifie pour les 8 combinaisons gagnantes du morpion si les emplacements de listes de la matrice correspondants (donc de la grille) sont égaux à 1 (donc à la croix).

Si c’est effectivement le cas, on lance la fonction victoire_croix qui affiche un écran de victoire bien mérité pour le joueur croix.


Difficultés rencontrées

Lors de la conception du jeu, nous sommes tombés sur plusieurs pépins.

Bien sûr, nous avons dû les surmonter, cependant, il y a eu de l’apprentissage mais également du bricolage.

On peut prendre l’exemple de la 1ère tentative de vérification qui était quelque peu fatiguée : 

def verification_cercle():
    if get_pixel(-75,-74) and get_pixel(0,-74) and get_pixel(75,-74) = (254, 254, 254):
        victoire_cercle()
    elif get_pixel(-75,-0) and get_pixel(0,0) and get_pixel(75,0) = (254, 254, 254):
        victoire_cercle()
    elif get_pixel(-75,-74) and get_pixel(0,74) and get_pixel(75,74) = (254, 254, 254):
        victoire_cercle()

On utilise la couleur du milieu de la croix et du cercle pour vérifier si la combinaison est gagnante.

La croix possède un pixel noir en son milieu et le cercle fait quelques aller-retours en son milieu en une couleur quasi-blanche (en RBG) afin de la différencier du fond blanc.

À l’aide de la méthode get_pixel(), on récupère la couleur d’un pixel à une coordonnée précise et on la compare à une valeur fixe, ici (254,254,254), du quasi-blanc. 

Si 3 pixels de la même et de cases à combinaison gagnante sont alignés, l’écran de victoire du joueur concerné s’affiche.
Cependant, rien ne se passait quand une combinaison gagnante apparaissait, on a donc décidé de changer d’approche malgré la tristesse de ne pas pouvoir exploiter cette méthode de pure ingéniosité…

Ensuite l’un des autres problèmes majeurs était de lier la matrice à la grille.


En effet, lors de la conception du jeu, nous voulions au début faire déplacement libre sur la matrice avant d’appuyer sur un 2ème bouton pour valider la case dans laquelle on veut jouer.


Nous avons donc décidé d’enlever le déplacement libre, c’est-à-dire que dès que l’on clique sur un chiffre, une croix ou un rond se met directement à l’emplacement voulu, cela nous a permis de pouvoir relier la matrice à la grille plus facilement:

if keydown(KEY_ONE) and matrice[0][0] == " ":
  goto(-75,-74)
  croix()
  matrice[0][0] = j
  j = 2
  verification_croix()
if keydown(KEY_TWO) and matrice[0][1] == " ":
  goto(0,-74)
  croix()
  matrice[0][1] = j
  j = 2
  verification_croix()

Comme on peut le voir sur le script ci-dessus, la matrice et la grille sont constamment liées.

Conclusion

Ainsi, nous avons l’immense fierté d’avoir conçu ce jeu vidéo sur la calculatrice, nous avons pu en apprendre plus sur le python et les différents modules qu’il possède qui nous étaient alors inconnus jusqu’à présent.

Au début de la conception de ce jeu vidéo, le travail nous paraissait immense et nous n’avions aucune idée d’où commencer ni de quoi faire, des problèmes ont été rencontrés mais nous avons pu trouver des solutions en codant, testant, en faisant des erreurs, nous corrigeant et en s’améliorant.


Le jeu

Avec relancement de partie (cliquer sur EXE à la fin d’une partie) mais avec un bug : lamhassni-bilal/morpion.py — Python — NumWorks

Sans relancement : corentin-katic84/morpion.py — Python — NumWorks

Sources

Chaîne YouTube de Schraf : Maths-info : https://youtube.com/@Schraf

Article Calculatrice Numworks : https://nsi.xyz/tutoriels/programmer-en-python-et-porter-son-code-sur-la-numworks/

Aide à la programmation : https://nsi.xyz/projets/un-menu-en-python-pour-les-jeux-sur-la-numworks/ ; https://www.codingame.com/playgrounds/48392etteur