# ########################################################################### # Projet : Tic Tac Toe (jeu du Morpion) # Version 1 : version manuelle pour 2 joueurs humains # Programmeurs : Fancely, Daryl et Hans # Mai 2026 # nsi.gecif.net # ########################################################################### # Importation des modules: import turtle import random # paramètre du jeu class Jeu: """ La classe jeu gère toute la logique du morpion Elle permet de : - détecter les clics du joueur - transformer les coordonnées (x,y) en case de la grille - Vérifie si une case est libre - placer le symbole(X ou O) - alterner entre les joueurs - dessiner les symboles dans la grille - détecter les lignes gagnantes et afficher un message de félicicitation""" def __init__(self, grille): self.grille = grille self.score_X = 0 self.score_O = 0 self.partie_finie = False self.ligne = self.grille.longueur self.colonne = self.grille.largeur # Turtle spécial messages self.message = turtle.Turtle() self.message.hideturtle() self.message.penup() # Turtle spécial score self.score = turtle.Turtle() self.score.hideturtle() self.score.penup() self.t = turtle.Turtle() self.t.hideturtle() self.t.speed(0) # Joueur actuel self.joueur = "X" # bibliothèque de félicitations self.encouragement= [" bien joué !!!"," quel maitrise !!!", " c'est du génie !!!", "c'est presque de la triche", " trop fort !!!", " Jolie !!!!"," Excellent", " Ohh oui !!!!!!"," trop top fort" ] random.shuffle(self.encouragement) # Grille modulable #self.etat = [[""]*self.ligne]*self.colonne self.etat = [] for i in range(self.ligne): liste=[] for j in range(self.colonne): liste.append("") self.etat.append(liste) """self.etat = [ ["","",""], ["","",""], ["","",""] ]""" #print(self.etat==[[""]*self.ligne]*self.colonne) def case_pleine(self): self.message.clear() self.message.goto(-140, self.grille.y_depart + self.grille.largeur * self.grille.taille + 40) self.message.color("red") self.message.write("Vous devez jouer dans les cases vides", font=("Arial", 11, "bold")) def afficher_score(self): self.score.speed(0) self.score.clear() self.score.goto(-340,230) self.score.color("red") self.score.write("Score X :%d" %self.score_X, font=("Arial",15,"bold")) self.score.goto(280,230) self.score.color("blue") self.score.write("Score O :%d" %self.score_O, font=("Arial",15,"bold")) def clic(self, x, y): self.message.clear() taille = self.grille.taille if self.partie_finie: if self.ligne== 3: self.message.goto(-130,-self.grille.y_depart + self.grille.largeur * self.grille.taille - 660) else: self.message.goto(-130,-self.grille.y_depart + self.grille.largeur * self.grille.taille - 720) self.message.color("red") self.message.write("La partie est finie il faut recommencer", font=("Arial",11,"bold")) return col = int((x - self.grille.x_depart) // taille) # coordonné permettant de cliquer dans les cases de la grille tracée lig = int((y - self.grille.y_depart) // taille) # coordonné permettant de cliquer dans les cases de la grille tracée if 0 <= col < self.colonne and 0 <= lig < self.ligne: # Remplace une case libre par les symbols if self.etat[lig][col] == "": self.etat[lig][col] = self.joueur self.dessiner_symbole(lig, col) # Change de joueur self.joueur = "O" if self.joueur == "X" else "X" else: self.case_pleine() else: self.message.clear() self.message.goto(-140,self.grille.y_depart + self.grille.largeur * self.grille.taille + 40) self.message.color("red") self.message.write("Il faut jouer dans le tableau pas ailleurs !!! ", font=("Arial", 11, "bold")) # ################################################################# # génération autmatisée des conditions de victoires # ################################################################# # TABLEAU gagnant: c'est un tableau avec toute les combinaison gagnantes quelque soit la grille tableau_gagnant= [] # ligne gagnante for i in range(self.ligne): ligne_gagnante=[] for j in range(self.ligne): ligne_gagnante.append((i,j)) tableau_gagnant.append(ligne_gagnante) # colonnes gagnantes for i in range(self.ligne): colonne_gagnante= [] for j in range(self.ligne): colonne_gagnante.append((j,i)) tableau_gagnant.append(colonne_gagnante) # diagonale gagnante 1 diag_1=[] for i in range(self.ligne): diag_1.append((i,i)) tableau_gagnant.append(diag_1) # diagonale gagnante 2 diag_2=[] for i in range(self.ligne): diag_2.append((i,(self.ligne-1)-i)) tableau_gagnant.append(diag_2) # détections de coups gagnants gagnant = False for coups in tableau_gagnant: # pour toute les combinaisant gagnante possible coup_gagnant = [ self.etat[l][c] for l, c in coups] # recherche le coup gagnant dans la partie en cours if coup_gagnant[0] != "" and coup_gagnant.count(coup_gagnant[0]) == self.ligne: # si la ligne n'est pas vide et que le meme motifs se répète 3* gagnant = True self.partie_finie = True # choisi un message pour féliciter le joueur félicitations= random.choice(self.encouragement) self.t.penup() self.t.goto(-100,self.grille.y_depart + self.grille.largeur * self.grille.taille + 40) self.t.color("yellow","black") self.t.begin_fill() self.t.pendown() for i in range(2): self.t.pensize(4) self.t.fd(220) self.t.lt(90) self.t.fd(50) self.t.lt(90) self.t.end_fill() self.t.penup() self.t.goto(-74, self.grille.y_depart + self.grille.largeur * self.grille.taille + 55) self.t.color("yellow") self.t.write(félicitations, font=("Arial", 11, "bold")) self.t.penup() # ajoute le score: if coup_gagnant[0] == "X": self.score_X += 1 if coup_gagnant[0] == "O": self.score_O += 1 self.afficher_score() #_________________________________________________# #______________ Si il y a égalité_________________ # CORRECTION : vérification HORS de la boucle for, et seulement si pas de gagnant if not gagnant: plateau_plein = True for ligne in self.etat: if "" in ligne: plateau_plein = False break # dès qu'une case est vide, inutile de continuer if plateau_plein: self.partie_finie = True self.message.clear() self.message.goto(-48, self.grille.y_depart + self.grille.largeur * self.grille.taille + 40) self.message.color("orange") self.message.write("Match nul !!!", font=("Arial", 13, "bold")) # Dessine le symbole X ou O def dessiner_symbole(self, lig, col): taille= self.grille.taille marge = taille * 0.3 x = self.grille.x_depart + col * taille + taille / 2 y = self.grille.y_depart + lig * taille + taille / 2 if self.etat[lig][col] == "X": self.t.color("red") self.t.pensize(7) # diagonale 1 self.t.penup() self.t.goto(x - marge, y - marge) self.t.pendown() self.t.goto(x + marge, y + marge) # diagonale 2 self.t.penup() self.t.goto(x - marge, y + marge) self.t.pendown() self.t.goto(x + marge, y - marge) self.t.penup() else: self.t.color("blue") self.t.pensize(7) self.t.penup() self.t.goto(x, y - marge) self.t.pendown() self.t.circle(marge) self.t.penup() # efface les symboles: def efface_symbole(self): global grille self.t.clear() self.t.penup() self.etat = [] for i in range(self.ligne): liste=[] for j in range(self.colonne): liste.append("") self.etat.append(liste) self.partie_finie = False self.message.clear() # Configuration des composants du Jeu: ###################### # Grille du Jeu ###################### class Grille: " l'objet de la classe Grille possède deux attributs: la longueur et la largeur de celle çi" "en plus de la taille des case qui est déja prédéfii à 100 pixel" "permettant ainsi de creer une liste de dimension variable" def __init__ (self,longueur,largeur): self.longueur= longueur self.largeur= largeur self.t= turtle.Turtle() self.t.hideturtle() self.t.speed(0) turtle.tracer(0) if self.longueur == 3: self.taille = 100 elif self.longueur == 4: self.taille = 80 elif self.longueur == 5: self.taille = 65 elif self.longueur == 6: self.taille = 55 #self.y_depart = -(self.largeur * self.taille) + 150 largeur_pixels = self.longueur * self.taille hauteur_pixels = self.largeur * self.taille self.x_depart = -largeur_pixels / 2 self.y_depart = -hauteur_pixels / 2 def case(self): "la méthode case la classe grille permet de dessiner un carré de 100 pixel" self.t.pensize(6) self.t.color("yellow","lightgreen") self.t.begin_fill() for i in range(4): self.t.fd(self.taille) self.t.lt(90) self.t.end_fill() def trace_colonne(self,x): " la méthode trace_colonne de la classe Grille attend en paramètre:" " le nombre de case (x) qu'elle doit dessiner horizontalement pour faire une colonne" for i in range(x): self.case() # trace une case self.t.fd(self.taille) # se met en possition pour la prochaine case def centrer_la_grille(self): " la méthode centrer_la_grille permet d'initialiser la position du crayon avant " "de dessiner" self.t.penup() # lève le crayon pour ne pas tracer pour rien self.t.goto(self.x_depart,self.y_depart) # positionne le crayon pour absice x et ordonné y self.t.pendown() # descend le crayon def dessiner_grille(self): " la méthode dessiner_grille permet de dessiner la grille en appelant toute" " les méthodes de la classe" self.centrer_la_grille() # centre la grille x_depart , hauteur_depart = self.t.position() # garde en mémoire les coordonnées de la première case for l in range(self.largeur): # selon la valeure de la largeur la boucle superpose les colonne horizontale self.trace_colonne(self.longueur) # colonne horizontale self.t.penup()# lève le crayon self.t.goto(x_depart, hauteur_depart + (l+1)*self.taille) # positionne le crayon juste au dessus de la première case self.t.pendown()# descend le crayon # méthode qui efface la grille: def effacer_grille(self): self.t.clear() jeu.efface_symbole() # ########################## # TITRE # ######################### def afficher_titre(): message.penup() message.goto(-130,280) message.pencolor("yellow") message.write("Morpion - cliquez pour jouer", font=("Arial", 15, "bold")) message.penup() message.goto(-112,260) message.pencolor("yellow") message.write("Pour recommencer appuyez sur la touche r", font=("Arial", 8, "bold")) def recommencer(): "remet tout ce qui est affiché dans la fenetre à zéro" message.clear() message.penup() grille.effacer_grille() afficher_titre() grille.dessiner_grille() information() def quitter(): turtle.bye() def information(): message.penup() message.goto(-205,-280) message.write("A chaque fois que vous recommencez c'est le joueur 2 qui a la main",font=("Arial", 10, "bold")) # ############################################ # Paramètre du jeu: # ############################################ message= turtle.Turtle() message.hideturtle() turtle.title("Tic Tac Toe") fenetre = turtle.getscreen() fenetre.getcanvas().winfo_toplevel().iconbitmap("xo.ico") turtle.setup(800,600) turtle.colormode(255) turtle.hideturtle() turtle.bgcolor('darkgreen') # couleur d'arrière plan afficher_titre() information() # #################################################### # Programme principale: # ################################################### dimension = int(turtle.numinput("Niveau de grille"," entrez une taille entre 3 et 6")) if dimension<3 or dimension>6: message.hideturtle() message.penup() message.goto(-310,0) message.pencolor("orange") message.write("Désolé seul les grilles 3x3,4x4,5x5 et 6x6 sont autorisées", font =("Arial",18,"bold")) else: grille= Grille(dimension,dimension) grille.dessiner_grille() jeu = Jeu(grille) jeu.afficher_score() turtle.onscreenclick(jeu.clic) turtle.onkey(recommencer,"r") turtle.hideturtle() message.hideturtle() turtle.onkey(quitter,"q") turtle.listen() turtle.done()