python projets

Identification

Infoforall

15 - Choix d'un sujet


Cette page vous présente plusieurs projets qu'il faudra réaliser en groupe de 2 ou 3 élèves.

Prérequis : l'activité précente : Projet avec tkinter

Logiciel nécessaire pour l'activité : Python 3 : Thonny, IDLE ...

1 - Puissance 4

Un plateau 4 sur 4.

Description des variables

  • Le plateau est codé via les valeurs contenues dans la matrice codes_data. Par exemple :
    • 0 pour VIDE
    • 1 pour PION JOUEUR 1
    • 2 pour PION JOUEUR 2
  • Un tableau nommé infos_data :
    • L'index 0 encode le joueur actif : 1, 2 ou -1 pour signaler aucun joueur par exemple.
    • L'index 1 encode l'état du jeu : 0 (inactif), 1 (en cours), 2 (fini : l'un des joueurs a gagné)
  • La fenêtre de l'application se nomme ihm et la matrice contenant les widgets du plateau refs_ihm.
  • 3 constantes contiennent les couleurs voulues pour les cases :
    • COULEUR_VIDE
    • COULEUR_1
    • COULEUR_2

Répartition des variables et fonctions entre IHM et DONNEES

Description du projet Puissance 4

Un clic sur l'un des Labels lance la fonction événementielle evt_demarrage :

  1. elle demande à la partie DONNEES d'initialiser les données à l'aide de la fonction initialisation_data (qui vide toutes les cases de la matrice du plateau, donne la main au joueur 1 et signale qu'une partie est en cours).
  2. ensuite, elle met à jour l'affichage avec actualiser_ihm.

Sur un clic sur une case, on lance evt_clic_case :

  • on envoie la demande à la partie DONNEES avec la fonction coup_valide_data : si cette fonction renvoie True, on met à jour l'affichage avec actualiser_ihm
  • Si la fonction répond par la négative : on ne fait rien

IHM vers DONNEES : initialisation_data et coup_valide_data sont donc les deux fonctions disponibles pour la communication IHM vers DONNEES.

DONNEES vers IHM : pas de changement prévu : creer_matrice_ihm et actualiser_ihm.

Qu'est que l'affichage ? Au moins :

  1. Le plateau
  2. Le bouton "Démarrer"
  3. Une zone de communication pour noter "Cliquez sur Démarrer", "Au joueur 1" ou encore "Le joueur 2 a gagné !"
  4. Le plateau : 6 de haut et 7 de large.

Votre travail

  1. Lancer le code de base
  2. Se familiariser avec le code
  3. Vous répartir les fonctions à réaliser qui permettront de rajouter des fonctionnalités au fur et à mesure :
    • joueur_suivant_data(infos) : facile
    • jeu_en_cours_data(infos) : facile
    • initialisation_data(codes, infos) : moyen
    • trouver_ligne_data(colonne, codes) : moyen à difficile en fonction de l'automatisation que vous voulez insérer.
    • coup_valide_data(colonne, codes, infos) : Difficile. Il s'agit surtout d'utiliser la documentation pour comprendre comment utiliser les fonctions même sans savoir comment elles fonctionnent à l'interne.
    • partie_gagnee_data(codes, infos) : Difficile. Le plus facile est de créer un string par concaténation des contenues des cases d'une ligne, d'une colonne ou d'une diagonale. Ensuite, on peut facilement tester si on trouve une séquence '1111' ou '2222' avec une expression du type if '1111' in maChaine :. La partie en ligne ou en colonne est plutôt abordable. La partie diagonale en automatisation va vous demander plus de réflexion poussée. Mais c'est faisable si vous aimez les casse-têtes !

Quelques remarques

L'erreur typique

Pour tester la fin du jeu, attention à bien faire la différence entre ces deux expressions : elles ne retournent pas le même résultat !

1 2 3 4
if '1111' in somme or '2222' in somme : pass if '1111' or '2222' in somme : pass

Si vous êtes en train de créer la fonction testant la fin du jeu, qu'elle ne fonctionne pas, et que vos tests ressemblent à l'une des versions ci-dessus, il faudra comprendre pourquoi les deux versions ne sont pas équivalentes.

Faciliter la lecture du code : les conventions de nommage prises dans le code fourni
  1. fenetre pour ihm
  2. codes pour codes_data
  3. infos pour infos_data
  4. refs pour refs_ihm
  5. w_comm pour w_comm_ihm
  6. w_start_ihm pour w_start

De la même façon, une référence de widgets contenues dans la matrice refs_ihm sera stockée dans w_case.

Code de base

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
# Etat initial du projet Puissance 4 # - - - - - - - - - - # 1 - Importations - # - - - - - - - - - - import tkinter as tk # - - - - - - - - - - - - - - - - - - - - - - - - # 2 - Les variables globales et les constantes - # - - - - - - - - - - - - - - - - - - - - - - - - # informations : infos_data = [-1,0] # Index 0 : contiendra le joueur actif : -1 (aucun), 1 , 2 ... # Index 1 : Etat de la partie : 0 - Partie non démarrée, 1 - Partie en cours, 2 - Partie gagnée # cases_data : matrice encodant le contenu des cases, "0" par défault codes_data = [ [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0], ] COULEUR_VIDE = '#BBBBBB' COULEUR_1 = '#FFFF00' COULEUR_2 = '#FF0000' # - - - - - - - - - - - - - - - - - # 3 A - Fonctions événementielles - # - - - - - - - - - - - - - - - - - def evt_demarrage(event) : '''Envoie la demande d'initialisation des données et affiche le résultat :: param event(Event) :: l'objet événement à gérer :: return (None) :: "procédure" Python ''' # Récupération des variables globales codes = codes_data # Matrice encodant le contenu des cases infos = infos_data # Informations générales sur le jeu en cours refs = refs_ihm # Matrice des références des widgets-cases w_comm = w_comm_ihm # Rérérence du texte de communication initialisation_data(codes, infos) # Remise à zéro des données actualiser_ihm(codes, infos, refs, w_comm) # Affichage des modifications def evt_clic_case(event) : '''Récupère ligne et colonne du wdiget et lance l'appel à ********************** :: param event(Event) :: l'objet événement à gérer :: return (None) :: "procédure" Python ''' # Récupération des informations sur l'événement w_case = event.widget ligne = w_case.ligne colonne = w_case.colonne # Récupération des variables globales codes = codes_data # Matrice encodant le contenu des cases infos = infos_data # Informations générales sur le jeu en cours refs = refs_ihm # Matrice des références des widgets-cases w_comm = w_comm_ihm # Rérérence du texte de communication # Envoi des informations vers les données et affichage actualisé éventuel if coup_valide_data(colonne, codes, infos) : actualiser_ihm(codes, infos, refs, w_comm) # Affichage des modifications # - - - - - - - - - - - - - - - - - - - - - # 3 B - Fonctions qui agissent sur l'IHM - # - - - - - - - - - - - - - - - - - - - - - def configurer_la_fenetre(fenetre) : '''Procédure gérant les paramètres de la fenêtre reçue en paramètre :: param fenetre(tkinter.Tk) :: la référence d'une fenêtre de classe Tk :: return (None) :: "procédure" Python ''' fenetre.geometry("1200x600") fenetre.title("Puissance 4") fenetre.configure(bg="black") def creer_matrice_ihm(codes) : '''Renvoie une matrice ayant les mêmes dimensions que donnees mais contenant None :: param codes(list(list)) :: la matrice dont on veut copier les dimensions :: return (list(list)) :: matrice ayant les dimensions d'entrée, contenant None ''' lignes = len(codes) colonnes = len(codes[0]) return [ [None for colonne in range(colonnes)] for ligne in range(lignes) ] def creer_cases_ihm(fenetre, refs): '''Procédure qui crée les cases graphiques et place leurs références dans la matrice fournie :: param fenetre(tkinter.Tk) :: la référence d'une fenêtre de classe Tk :: param refs(list(list)) :: la référence d'une matrice destinée à recevoir les réferences :: return (None) :: "procédure" Python :: Effet de bord :: modifie refs ''' lignes = len(refs) # Nombre de lignes dans la matrice fournie colonnes = len(refs[0]) # Nombre colonnes dans la matrice fournie for ligne in range(lignes) : for colonne in range(colonnes) : # Calcul du numéro et des positions à appliquer numero = colonne + ligne * colonnes px = 20 + colonne * 75 # position x en pixels py = 120 + ligne * 70 # position y en pixels # Création du widget (et rajout d'attributs utiles pour notre jeu) w_case = tk.Label(fenetre, text=numero, fg="white", bg='grey', width=8, height=4) w_case.numero = numero w_case.colonne = colonne w_case.ligne = ligne # Affichage et placement du widget w_case.place(x=px, y=py) # On mémorise la référence du widget dans la matrice refs[ligne][colonne] = w_case def creer_texte_ihm (fenetre, communication, px, py, fond, texte) : '''Fonction qui crée la zone de texte et renvoie sa référence''' w_texte = tk.Label(fenetre, text=communication, fg=texte, bg=fond, width=20, height=3) w_texte.place(x=px, y=py) return w_texte def actualiser_ihm(codes, infos, refs, w_comm) : '''Modifie les widgets pour refléter les données du plateau de jeu :: param codes (list(list)) :: matrice contenant les données des cases :: param infos (list) :: tableau contenant les données annexes :: param refs (list(list)) :: matrice contenant les références des widgets :: param w_comm (Label) :: référence d'un objet Label destiné à afficher les messages :: return (None) :: "procédure" Python ''' # Gestion des cases lignes = len(codes) colonnes = len(codes[0]) for ligne in range(lignes) : for colonne in range(colonnes) : w_case = refs[ligne][colonne] # On stocke car on va l'utiliser plusieurs fois if codes[ligne][colonne] == 0 : w_case.configure(bg=COULEUR_VIDE) w_case.configure(text="") elif codes[ligne][colonne] == 1 : w_case.configure(bg=COULEUR_1) w_case.configure(text="1") elif codes[ligne][colonne] == 2 : w_case.configure(bg=COULEUR_2) w_case.configure(text="2") # Gestion du texte if infos[1] == 0 : # Partie non démarrée w_comm.configure(text="Appuyer sur le bouton !") elif infos[1] == 1 and infos[0] == 1 : w_comm.configure(text="Au tour du joueur 1") elif infos[1] == 1 and infos[0] == 2 : w_comm.configure(text="Au tour du joueur 2") elif infos[1] == 2 and infos[0] == 1 : w_comm.configure(text="Joueur 1 gagne !") elif infos[1] == 2 and infos[0] == 2 : w_comm.configure(text="Joueur 2 gagne !") else : w_comm.configure(text="Configuration étrange...") # - - - - - - - - - - - - - - - - - - - - - - - - # 3 C - Fonctions qui agissent sur les données - # - - - - - - - - - - - - - - - - - - - - - - - - def initialisation_data(codes, infos) : '''Replace les valeurs initiales dans les données : joueur 1, partie en cours et 0 dans les cases :: param codes (list(list)) :: matrice contenant les données des cases :: param infos (list) :: tableau contenant les données annexes :: return (None) :: "procédure" Python ''' pass def coup_valide_data(colonne, codes, infos) : '''Si le coup sur cette colonne est possible, modifie la matrice code et renvoie True. Sinon False :: param colonne(int) :: numéro de la colonne choisi pour ce coup :: param codes (list(list)) :: matrice contenant les données des cases :: param infos (list) :: tableau contenant les données annexes :: return (bool) :: Renvoie True si le joueur peut choisir cette case ''' if jeu_en_cours_data(infos) : # Si le jeu a bien démarré ligne = trouver_ligne_data(colonne, codes) # Quelle ligne pour le joueur infos[0] ? if ligne >= 0 : # Le coup est possible et va entrainer une modification de la grille pass # On place le numéro du joueur sur la case # Si la partie est gagné, on lance gestion_fin_data # Sinon on règle les données pour passer au joueur suivant return True return False def trouver_ligne_data(colonne, codes) : '''Renvoie la ligne de la case vide possible sur cette colonne, -1 si tout est plein :: param colonne(int) :: un numéro valide de colonne :: param codes (list(list)) :: matrice contenant les données des cases :: return (bool) :: Renvoie True si le joueur peut choisir cette case ''' return 0 def joueur_suivant_data(infos) : '''Renvoie le numéro du joueur suivant : 1 si 0 ou 2, 2 si 1... :: param infos(list) :: le tableau des informations diverses dont infos[0] :: return (int) :: le numéro du joueur suivant ''' return 2 def partie_gagnee_data(codes, infos) : '''Renvoie True si unjoueur a gagné la partie :: param codes (list(list)) :: matrice contenant les données des cases :: param infos(list) :: le tableau des informations diverses dont infos[0] :: return (bool) :: True si la partie est finie ''' # Victoire en ligne # Victoire en colonne # Victoire en diagonale haut gauche - bas droite # Victoire en diagonale bas gauche - haut droite return False def jeu_en_cours_data(infos) : '''Renvoie True si infos[1] vaut 1. Sinon False :: param infos(list) :: tableau d'informations diverses :: return (bool) :: True si infos[1] vaut 1, False sinon ''' return True def gestion_fin_data(codes, infos) : '''Modifie les données pour préparer la fin de partie :: param codes (list(list)) :: matrice contenant les données des cases :: param infos(list) :: le tableau des informations diverses dont infos[0] :: return (None) :: "Procédure" Python ''' infos[1] = 2 # - - - - - - - - - - - - - # 4 - Programme principal - # - - - - - - - - - - - - - if __name__ == '__main__' : # A - Activation des tests sur les fonctions du module import doctest doctest.testmod() # B - Création d'une fenêtre graphique maitre qu'on nomme ihm ihm = tk.Tk() configurer_la_fenetre(ihm) # C - Création de widgets refs_ihm = creer_matrice_ihm(codes_data) # Création de la variable de stockage creer_cases_ihm(ihm, refs_ihm) # Création effective et stockage des widgets w_comm_ihm = creer_texte_ihm(ihm, "I'm talking to you !", 20, 60, '#111111', '#DDDDDD') w_start_ihm = creer_texte_ihm(ihm, "Nouveau jeu ? Cliquez", 20, 10, '#EEEE88', '#333333') actualiser_ihm(codes_data, infos_data, refs_ihm, w_comm_ihm) # Mise à jour de l'affichage # D - Création des surveillance par le gestionnaire d'événements for ligne in range(len(refs_ihm)) : for colonne in range(len(refs_ihm[0])) : refs_ihm[ligne][colonne].bind("<Button-1>", evt_clic_case) w_start_ihm.bind("<Button-1>", evt_demarrage) # E - Activation de la surveillance sur l'application graphique ihm.mainloop()

2 - Démineur

En cours de rédaction

3 - Pixel Art

En cours de rédaction

4 - Memory

Prévu

5 - Labyrinthe

Prévu. Basé sur l'activité précédente avec les dragons et l'aventurier.

Si vous voulez plus d'informations, vous pouvez faire des recherches sur le Web.

Vous trouverez également quelques fiches sur ce site, comme celle-ci par exemple.

FICHE Tkinter

Activité publiée le 19 07 2020
Dernière modification : 19 07 2020
Auteur : ows. h.